背景
如果在GitHub上看到了一个有趣的项目,想要参与开发,我们一般需要遵照一定的流程。这里记录一下一般的项目合作开发流程。
当然这里的流程不仅适用于GitHub,也适用于其他的代码托管平台,如GitLab等。
前置条件
- 已经安装了Git
- 已经注册了GitHub账号
Git设置
-
设置用户名和邮箱
设置用户名和邮箱有两种模式。
-
如果你只用一个GitHub账号,可以设置全局用户名和邮箱。
1 2git config --global user.name "Your Name" git config --global user.email "Your Email" -
如果你有多个GitHub账号,可以给每个Git仓库分别设置用户名和邮箱。
1 2 3cd /path/to/your/repo git config user.name "Your Name" git config user.email "Your Email"
-
-
登录凭证管理
在上一步设置好用户名和邮箱后,在克隆仓库以及每次
git push时,都需要输入GitHub的用户名和密码,这样很麻烦。可以使用凭证管理器来保存用户名和密码。-
Windows
如果你安装的Git版本号高于
2.29,那么Git中已经集成了对GitHub OAuth的支持。当你第一次通过HTTPS方式克隆一个GitHub私有仓库时,Git会提示你使用浏览器登录GitHub,并授权Git访问你的GitHub账号。之后,Git会自动保存你的GitHub凭证,不需要再次输入用户名和密码。 -
macOS
-
方法一(旧方法):
你需要安装
Git Credential Manager。可以在终端中运行以下命令:1brew install --cask git-credential-manager安装完成后,当你第一次通过HTTPS方式克隆一个GitHub私有仓库时,Git会提示你使用浏览器登录GitHub,并授权Git访问你的GitHub账号。之后,Git会自动保存你的GitHub凭证,不需要再次输入用户名和密码。
Git Credential Manager支持各种Git托管平台,包括GitHub、GitLab、Bitbucket等的账号都可以使用这个工具进行凭证管理。
-
方法二(推荐方法):
对于GitHub账号,可以使用GitHub CLI工具进行凭证管理。可以在终端中运行以下命令安装GitHub CLI工具:
1brew install gh安装完成后,运行以下命令登录GitHub账号:
1gh auth login按照提示选择通过浏览器登录GitHub账号。登录成功后,GitHub CLI工具会自动配置Git的凭证管理,不需要再次输入用户名和密码。
-
-
Linux
Linux系统和macOS类似,可以选用Git Credential Manager或者GitHub CLI工具进行凭证管理。使用你所用的Linux发行版的包管理器安装即可。
-
GitHub合作开发流程
GitHub网页上的操作 —— Fork
-
打开你想要参与开发的项目的GitHub页面,点击右上角的
Fork按钮,将项目fork到自己的GitHub账号下。 我们把原项目称为原始仓库,把自己fork过来的项目称为Fork仓库。 -
在自己的GitHub账号下,找到fork过来的项目(即
Fork仓库),点击Clone or download按钮,复制项目的URL。
本地操作 —— Clone
-
在本地的终端中,切换到你想要存放项目的目录,运行以下命令,将项目克隆到本地。
1git clone https://github.com/your-username/project-name.git这里的
your-username是你的GitHub用户名,project-name是项目的名字。 -
进入项目目录,运行以下命令,将
原始仓库添加为远程仓库。1git remote add upstream https://github.com/authors-usename/project-name.git这里的
authors-username是原始仓库的作者的GitHub用户名,project-name是项目的名字。然后运行以下命令,查看远程仓库的情况。
1git remote -v如果一切正常,你会看到类似以下的输出:
1 2 3 4origin https://github.com/your-username/project-name.git (fetch) origin https://github.com/your-username/project-name.git (push) upstream https://github.com/authors-username/project-name.git (fetch) upstream https://github.com/authors-username/project-name.git (push)这里的
origin是你的Fork仓库,upstream是原始仓库。
本地开发
-
在本地的终端中,切换到项目目录,运行以下命令,创建一个新的分支。
1git checkout -b new-branch-name这里的
new-branch-name是你的新分支的名字,它可以是你要添加的新功能的名字,也可以是你要修复的bug的名字。 -
在本地的终端中,进行开发,修改代码/添加新功能/修复bug。然后运行以下命令,将修改的文件添加到暂存区以及提交到本地仓库。
1 2git add . git commit -m "Your commit message"也可以把本地仓库的修改推送到
Fork仓库。1git push origin new-branch-name -
重复第2步的操作,直到你的新功能/bug修复完成。
-
现在我们已经可以创建Pull Request了,但在创建Pull Request之前,为了确保我们的新代码在合并进
原始仓库时不产生冲突,我们最好拉取原始仓库的main分支的最新代码,然后可以在本地合并main分支的最新代码到自己的new-branch-name分支。1 2 3 4git checkout main git pull upstream main git checkout new-branch-name git merge main在做这一步时,如果从你开始开发新功能到现在,
原始仓库的main分支有新的提交,那么你的new-branch-name分支可能会产生冲突。你需要解决这些冲突。 解决冲突后,运行以下命令,将修改的文件添加到暂存区以及提交到本地仓库。1 2git add . git commit -m "Your commit message"然后再次运行以下命令,将修改的文件推送到
Fork仓库。1git push origin new-branch-name这样,你的
new-branch-name分支向原始仓库的main分支合并时就不会产生冲突了。
GitHub网页上的操作 —— Pull Request
-
打开你的
Fork仓库的GitHub页面,点击New pull request按钮,创建一个新的Pull Request。注意如果原始仓库提供了Pull Request模板,你需要按照原始仓库的Pull Request模板填写Pull Request的标题和内容。 -
等待
原始仓库的作者审核你的Pull Request,如果有需要,你需要根据原始仓库的作者的反馈进行修改。 -
如果
原始仓库的作者接受了你的Pull Request,恭喜你,你的代码将会被合并到原始仓库中。
本地操作 —— 更新本地仓库
-
在本地的终端中,切换到
main分支,运行以下命令,将原始仓库的main分支的最新代码拉取到本地。1 2git checkout main git pull upstream main你也可以先使用
git fetch upstream main命令,查看原始仓库的main分支的最新代码,然后再使用git merge upstream/main命令,将原始仓库的main分支的最新代码合并到本地的main分支。1 2 3git fetch upstream main git checkout main git merge upstream/main这样,你本地的
main分支就和原始仓库的main分支保持了同步。 -
然后你可以把本地的
main分支推送到Fork仓库。1git push origin main -
(可选)如果你的
new-branch-name分支已经被合并到原始仓库的main分支,你可以删除new-branch-name分支。1git branch -d new-branch-name你也可以删除
new-branch-name分支的远程分支。1git push origin --delete new-branch-name
这样,你就完成了在Github上和别人合作添加一个新功能/修复一个bug的工作。
继续开发新功能/修复新bug
如果需要继续添加新功能/修复新bug,可以先将自己Fork仓库的main分支与原始仓库的main分支同步,确保你从项目最新的版本开始工作:
```bash
git checkout main
git pull upstream main
git push origin main
```
然后,你可以在main分支上创建一个新的分支,继续开发新功能/修复新bug。
```bash
git checkout -b another-new-branch-name
```
后面的操作就和本地开发之后的一样了。