如何在 Github 上进行协作

内容纲要

查看【Git】专题可浏览更多内容

如果我们直接对一个第三方的 Github 项目进行推送将会看到这样的提示:

ERROR: Permission to github/repo.git denied to Example.
致命错误:无法读取远程仓库。

请确认您有正确的访问权限并且仓库存在。

解决这个权限问题的办法有两种:

作为 Collaborator

如果这个 Github 项目实际上是团队或公司的一个项目,那么可以让项目的所有人邀请你,给予你权限。

在项目的「Settings」的「Access」下的「Collaborators」中,可以通过「Add People」添加 Github 用户:
如何在 Github 上进行协作

在添加后拥有了这个仓库的权限,就可以正常推送了。

除了这个方法还有一种常见的场景是,你遇到了一个开源在 Github 上的项目,但它有点小问题而你恰好知道解决办法,那么除了提 Issue 也可以自己改进好然后申请提交给项目主,这就是第二种方法

使用 Fork 及 Pull Request

Fork

首先,我们先进行 Fork

如何在 Github 上进行协作

点击要参与贡献的项目右上角的「Fork」,然后可选修改 Fork 到你 Github 帐户上的仓库名

所谓「Fork」仓库类似于复制仓库,用于更改项目而不影响原始仓库。 之后可以通过拉取请求从原始仓库提取更新,或者提交更改到原始仓库。

如何在 Github 上进行协作

注意左上角,可以看到现在这个项目来源于哪个帐户下的什么仓库

然后就可以根据你的方式选择 HTTPS 或 SSH 将仓库克隆到本地计算机上,如果你没有做过这方面的验证可以查看 使用 SSH 或 Token 向 GitHub 进行身份验证 一文

创建特性/开发分支

在克隆自己帐户上 Fork 而来的远程仓库到本地后,第一步应该是创建一个特性分支用于改动,而不是直接在主分支 (mastermain) 上改动

# 创建并切换到名为 feature 的分支
git switch -c feature

然后就可以做改动并推送 feature:

git add .
git commit -m '改动标题' -m '改动内容描述'

# 推送 feature 分支
git push -u origin feature

到这里,你的 Github 帐户的仓库就有了 feature 分支

原仓库有了更新

在我们进行本地修改的时候,很可能原仓库有了别的更新,这时候要如何同步原仓库的改动?

你可以选择 Github 页面上的「Sync fork」功能点点鼠标:

如何在 Github 上进行协作

之后你要从 feature 分支切换回主分支,然后 git pull origin master 拉取下来

或者通过命令行实现:

首先我们要在本地计算机的仓库上添加原仓库的远程信息:

# 添加原仓库的远程信息,将原仓库命名为 upstream
git remote add upstream https://github.com/github/repo.git
# 查看下远程仓库信息
git remote -v
origin  https://github.com/Nobody/repo.git (fetch)
origin  https://github.com/Nobody/repo.git (push)
upstream    https://github.com/github/repo.git (fetch)
upstream    https://github.com/github/repo.git (push)

origin 表示我们 Github 帐户上 Fork 而来的仓库,upstream 表示所 Fork 的原仓库

接着获取原仓库数据:

git fetch upstream

然后要合并原仓库的更新到本地主分支上了,当前是不是还在feature 分支上开发呢?

# 切换到主分支
git switch master

并不是所有的项目的主分支都叫 master,因为「政治正确」现在许多新项目改叫 main 了,根据你的实际情况来吧

然后将改动合并到本地当前分支:

git merge upstream/master

同样的,这里如果原项目中的主分支为 main 就要修改为 upstream/main

现在你本地仓库的 master 分支已经和原仓库的更新同步了,但你 Github 上 Fork 而来的仓库还没有,所以如果有必要就进行推送 master

git push origin master

推送特性/开发分支

同步了原仓库的改动后,现在回到 feature 分支,假设现在改动也改动好了可以推送了,那么:

# 回到 feature 分支
git switch feature

# 先把原仓库同步到本地 master 分支的最新修改放进来,再放上自己的修改
git rebase master
# 使用以上命令后可以使用 git log 看看历史记录的变化

# 然后推送 feature 到 github
git push -f origin feature

为什么最后一步加了 -f 选项,不是都说最好不用该选项吗?

首先这个操作只是在自己的项目上,其次如果在 git rebase 操作之前如上示例,在拉取原仓库最新修改前有过一次推送,那么当前本地 feature 和你 Github 上的 feature 是有所不同的。

你本地 feature 的历史中多了原仓库的更新,和之前推送不一样了。

创建 Pull Request

前往你的 Github 项目,点击「Pull requests」

如何在 Github 上进行协作

点击右侧的「New pull request」按钮创建一个 Pull Request

如何在 Github 上进行协作

如上图,主要是三个部分:

  1. 请求的项目为 github/repo,从我的 Github 项目 Nobody/repofeature 分支合并修改
  2. 然后是填写请求的标题及内容,为什么要做这些、大概做了什么修改进行描述一下;
  3. 在页面底部还有修改前后的修改对比部分,不过这部分不是本文重点就不截图了;

在确定后就可以点击「Create pull request」了

管理 Pull Request

现在转换身份,如果你是一个项目主,该如何处理 Pull Request 呢?

如何在 Github 上进行协作

你可以在这个界面预览修改、改动了什么文件、有哪些提交,也可以使用右侧列表的功能,比如加上标签等等

如何在 Github 上进行协作

你还可以在 Commit 中的具体一行通过点击蓝色加号按钮添加评论,例如说你认为某段代码可以进一步改进等等

如何在 Github 上进行协作

最后如果你觉得这次请求并不合理可以选择「Close pull request」,或点击绿色按钮进行 Merge

Pull Request 的几种合并有什么不同?

在 Merge 按钮的右侧有个下拉按钮,你可以看到有几种不同的合并方式,那么它们有什么不同呢?

「Create a merge commit」:

*   commit 686785618ac8795a7eaa412049e7f859869ed8f3 (HEAD -> master, origin/master, origin/HEAD)
|\  Merge: 9ef96c8 94fd1f1
| | Author: Github <[email protected]>
| |
| |     Merge pull request #1 from Nobody/repo
| |
| * commit 94fd1f1f76b3c6a0a296ea64f0983aafc141230d
| | Author: Nobody <[email protected]>
| |
| |     docs: Fix content
| |
| * commit 8f832d016c82b0b5d1f8dad27aba0b507f468052
|/  Author: Nobody <[email protected]>
|
|       docs: Fix title
|
* commit f6112e6c5721a95d204f215227c48c9f7d33dee1
| Author: Github <[email protected]>
|
|     docs: add README.md
|
* commit b36602c3bf6c3be2a989d48e35834a14757b2550
  Author: Github <[email protected]>

      Initial commit

可以看到,使用「Create a merge commit」除了贡献者自己的提交,还会多一个合并提交,即「Merge pull request #1 from Nobody/repo」

并且可以看到支线有分开在合并的记录

「Squash and merge」:

* commit b27cfa1afdafea6d740f01668d7ace5de0cb4eab (HEAD -> master, origin/master, origin/HEAD)
| Author: Nobody <[email protected]>
|
|     docs: Fix format error
|
* commit f6112e6c5721a95d204f215227c48c9f7d33dee1
| Author: Github <[email protected]>
|
|     docs: add README.md
|
* commit b36602c3bf6c3be2a989d48e35834a14757b2550
  Author: Github <[email protected]>

      Initial commit

而使用「Squash and merge」会将贡献者的提交合并成一条提交

「Rebase and merge」

* commit 94fd1f1f76b3c6a0a296ea64f0983aafc141230d (HEAD -> master, origin/master, origin/HEAD)
| Author: Nobody <[email protected]>
|
|     docs: Fix content
|
* commit 8f832d016c82b0b5d1f8dad27aba0b507f468052
| Author: Nobody <[email protected]>
|
|     docs: Fix title
|
* commit f6112e6c5721a95d204f215227c48c9f7d33dee1
| Author: Github <[email protected]>
|
|      docs: add README.md
|
* commit b36602c3bf6c3be2a989d48e35834a14757b2550
  Author: Github <[email protected]>

      Initial commit

使用「Rebase and merge」会将贡献者的提交记录直接合并入分支,而且可以看到分支是一条直线