github如何使用fork和PR进行协作——你为啥直接commit到我的master分支啊
github如何使用fork和PR进行协作——🐧🐧你为啥直接commit到我的master分支啊
前言
🐧你为啥直接commit到我的master分支啊?!😨GitHub 上不是这样!😡你应该先 fork 我的仓库,然后从 develop 分支 checkout 一个新的 feature 分支,比如叫 feature/confession。☝️然后你把你的心意写成代码,并为它写好单元测试和集成测试,确保代码覆盖率达到95%以上。😮接着你要跑一下 Linter,通过所有的代码风格检查。然后你再 commit,commit message 要遵循 Conventional Commits 规范。之后你把这个分支 push 到你自己的远程仓库,然后给我提一个 Pull Request。😤在 PR 描述里,你要详细说明你的功能改动和实现思路,并且 @ 我和至少两个其他的评审。我们会 review 你的代码,可能会留下一些评论,你需要解决所有的 thread。🧐等 CI/CD 流水线全部通过,并且拿到至少两个 LGTM 之后,我才会考虑把你的分支 squash and merge 到 develop 里,等待下一个版本发布。☺️你怎么直接上来就想 force push 到 main?!😡GitHub 上根本不是这样!我拒绝合并!😡
在使用github进行多人协作时,一般会存在两种情况。
- 一是本身被选为了仓库的协作者,这种情况下可以直接对于本仓库创建分支进行协作。
- 二是没有被选为协作者,也是本文讨论的情况,这种时候便要采用提交PR的方式请求仓库人员将我们的修改进行合并。
这里我以一考试资料分享的仓库为例,演示如何通过提交PR向仓库提交新的考试资料。因此在本示例中,提交的是普通的PDF文件及图片,而不是代码文件,但工作流程是差不多的,可供新手作为参考。
注意!我的浏览器由于安装了相关插件,因此github上显示为中文,因此本文中部分标题、按钮等名字会替换为中文显示,请读者进行辨别。
fork目标仓库
首先我们进入github并进入目标仓库的页面。点击右上方的复刻按钮,即fork按钮

成功后会在我们的个人仓库中创建一个目标仓库的fork仓库。

现在fork后的仓库已属于我们,而左上角可明显看到“复刻自...仓库”
clone目标仓库到本地
由于页面操作在实际工作流中有诸多不便,因此我们在添加或修改仓库中文件代码时,一般需要提前将仓库clone到本地。而这一系列步骤就是我们熟悉的git clone了。

在本地选择一个目录,输入对应的git clone "fork仓库的URL"
注意!这里clone的仓库是我们fork后的仓库,而不是原来的仓库!由URL可以看出仓库的所有者已经是我(C-KyS),而不是原仓库的所有者。
现在clone成功后便可在本地查看该仓库的所有文件:


配置本地仓库相关信息
将仓库clone到本地后,我们还需要对该本地仓库进行相关的初始配置,以便于后续获取仓库的更新等。
关联原始仓库为 Upstream (上游)
使用命令关联原始仓库为上游
git remote add upstream 目标仓库URL 
关联原始仓库后,我们便可以更为方便地随时获取原始仓库的更新情况。
举个例子,我们 Fork 并在本地克隆了仓库,但在我们修改代码的这段时间,原始仓库的其他贡献者提交了新的试卷并被维护者合并了,那我们本地的文件版本就比原始仓库旧了。如果没有 upstream 这个连接,我们将很难获取到原始仓库的最新变化;而有了 upstream,我们可以轻松地执行相关命令,让本地仓库保持最新。
如以下命令
# 从原始仓库(upstream)获取最新数据git fetch upstream # 将原始仓库 main 分支的最新内容合并到你本地的 main 分支git checkout main git merge upstream/main 执行相关命令后,便可获取原始仓库的最新文件更新。
git fetch vs. git pull 的区别
这时候一些新手朋友或接触过git工具的朋友可能就会觉得,该步骤相关命令的作用和平时使用的git pull挺像的,都是拉取仓库的最新状况,这两者有什么区别呢?
首先git pull命令实际上是两个命令的结合:git fetch + git merge 或 git rebase,也就是包含两个主要动作下载+合并。而合并便有可能产生冲突,即如果原始仓库的更新和本地的修改在同一个文件或同一行,Git 会自动触发合并(Merge)或冲突(Conflict)。
而git fetch则只是单纯的下载,因此它只会将原始仓库的最新数据下载到本地 Git 仓库中,但不会自动修改你当前工作目录中的任何文件。
我们平时使用的单纯的git pull默认形式其实为git pull origin main,也就是将我们自己的仓库的仓库拉取到main分支合并。
确保主分支为最新
一般来说,在工作流中克隆到本地后的main都是最新的,但为确保严谨,还是需要对主分支进行更新
git checkout main # 将分支切换到主分支git pull upstream main # 拉取原仓库的main分支,合并到我们本地fork仓库的main分支 
创建新分支
按协作规范,我们一般不会直接在main分支上对项目进行修改,而是使用命令新建一个自己的分支。
git checkout -b your-contribution-name # checkout -b 可创建新分支并直接切换至该新创建的分支git branch # 该命令用于查看当前的分支情况
我这边创建的新分支名为ckys-add,绿色字体和左边的星号代表目前我正处于ckys-add分支
正式添加/修改文件并push
现在我们已成功配置了仓库的信息并创建了一个新分支,因此算是做完了所有的准备工作。接下来便是正式对仓库的文件进行修改。
添加/修改文件
在该步骤中你可以将自己的代码添加进仓库,或是修改项目中的代码,进行任何你想要的增删查改。
在本示例中,我只是简单地将一些新的文件添加到了该仓库中。
我这边将图中的相关文件添加进了相关目录
add/commit
对项目的修改进行完毕后便是我们最熟悉的add+commit+push三板斧了。这里稍微值得注意的是, 在标准的多人协作中,commit的信息一般需要遵守相应的格式,如conventional commit规范。对于conventional commit规范我在这里并不详细说明,读者可自行在访问官网Coventional Commit,或是社区搜索各个大佬分享的博客。(或者可以后期我再写一篇,但怕是要拖了doge)

push
现在我们需要推送分支到我们的GitHub 仓库 (origin),即我们fork出来的那个仓库,即执行以下命令:
git push origin ckys-add 对于该命令有两个选项:
- 关于origin: 为什么是orign而不是之前创建的upstream?
origin 和 upstream 它们被称为远程别名 (Remote Names),或简称远程 (Remotes),可简单理解为仓库的一个别名,即一个origin就映射一个你拥有的仓库,而upstream便映射的是原仓库。这下便可以理解了,我们不是原仓库的协作者,是没有原仓库的相关权限的,因此自然不可能git push upstream。 - 关于ckys-add: 这里的ckys-add是明确指定推送哪个本地分支,必须要加用于上游追踪。当然也有利用-u 选项(git push -u origin ckys-add)使得后续不用加以方便操作的选择,这里不过多赘述。
创建PR并提交
返回网页端
现在我们返回github网页,进入我们的fork仓库,可以看到这里仓库名称下方出现了比较&拉取请求按钮,说明仓库已经检测到了我们通过ckys-add分支push了新的推送,可以进行拉取请求(pull request)操作了。

确认PR目标、来源等信息
点击比较&拉取请求按钮后,我们会看到如下页面,在该页面的顶部会出现四个重要信息,这里我在图中已经框中并标号了,分别为基础仓库(base repository)、基础分支(base branch)、头部仓库(head repository)、比较分支(compare branch)。

对四个配置信息进行简单解释:
| 配置项 | 显示内容 | 解释 |
|---|---|---|
| base repository | HDU-Course/HDU-FinalExamPaper | 目标仓库,即我们的贡献最终要去的地方,也就是原始仓库。 |
| base branch | main | 目标分支: 原始仓库默认接收贡献的分支(默认通常是 main,但也可以是其他分支)。 |
| head repository | C-KyS/HDU-FinalExamPaper | 来源仓库 : 这是我们推送了修改的仓库(你的 Fork)。 |
| compare branch | ckys-add | 来源分支: 这是我们进行了修改的那个分支。 |
通过这四个信息我们可以完成最终的PR提交确认。
填写PR描述
在上张图片的中间,我们可以看到添加标题和添加描述的按钮填写框,在这里我们需要详细说明我们修改的功能改动和实现思路,同时严格的话还需要@ 项目评审,等待评审人员的review和留言。
提交PR
确认无误后,点击绿色的 创建拉取请求 (Create pull request) 按钮,提交成功。

提交结束及后续
在提交成功后,页面上方的菜单栏中有四个功能可供我们查看,分别为讨论(Conversation)、提交(Commits)、检查(Checks)、更改的文件(Files changed)。

“Conversation” (讨论) 标签页
该页面是第一个主视图,也就上图所展示的,用于沟通和状态概览。
- 评审意见和评论: 我们 @维护者(我这里@ek1ng) 的所有评论、疑问或建议都会在这里显示。
- LGTM/批准状态: 维护者点击 “Approve” 或留下 LGTM 的行为会在这里记录。
- 事件时间线: 底部的时间线记录了 PR 的创建、提交更新和最终合并/关闭等关键动作。
“Commits” (提交) 标签页

这里按时间顺序显示我们在这个分支(我这里是 ckys-add分支)上做的所有 git commit 记录。
“Checks” (检查) 标签页
这里在规范的仓库中一般会有自动化检查成果(CI/CD),所有的自动化测试、格式检查等流水线的结果会在这里显示。
- 绿色勾 ✓ \checkmark ✓ (Success): 表示自动化检查通过。
红色叉 × \times × (Failure): 表示有检查失败,需要点击 “Details” 查看日志并修复问题。
但我这里状态信息显示 workflow runs completed with no jobs (工作流运行完成,但没有作业),表明我这个特定的开源项目 (HDU-Course/HDU-FinalExamPaper) 是没有使用 GitHub Actions 或其他 CI/CD 工具来运行自动化测试或代码检查。

“Files changed” (文件更改) 标签页
该页面用于显示我们提交的文件与目标分支之间的所有差异。
评审者通常会在这里对文件的特定行进行评论(即 Thread/会话)。当我们处理完一个意见后,我们会回到 “Conversation” 标签页点击 “Resolve conversation” 关闭它。

后记
到此为止在github上创建并提交PR的简单教程便结束了,后续的就要等待评审者的回复。由于笔者所作为示例的仓库并非热门仓库(因为也是新手怕第一次给别人热门仓库搞坏了,所以挑了一个小一点 哈哈),因此后续review的教程就要等一段时间了,包括真正修改提交代码的教程。
说来好笑,笔者真正接触到git标准工作流的是一个整活类型的视频,即🐧你为啥直接commit到我的master分支啊,也就是文章开头引用的文字。但当时在看的时候也有诸多不懂的地方,也是通过本视频采取了解了整个git的标准工作流,说实话该视频的内容还真挺有用的呢。