该文章参考大佬@码农高天的视频十分钟学会正确的github工作流,和开源作者们使用同一套流程,如果有想看视频讲解的可以看看
梦开始的地方
【remote】main | 【Local】 | 【Disk】 |
---|---|---|
Init | ||
首先我们有上面的三个工作区,分别是 Remote(GitHub云端)、Local(本地git状态)、Disk(硬盘状态),最开始时只有云端有Init这个状态。
我们通过git clone
命令克隆远程仓库到本地:
1 | git clone <repo-url> |
由此我们的状态变为:
【remote】main | 【Local】main | 【Disk】main |
---|---|---|
Init | Init | Init |
三个状态是一样的,因为我们没有做出任何改动,且远程仓库也没有发生更新。
创建我们自己的一个branch
在我们需要对代码进行改动时,首先需要建立一个属于我们自己的新分支
1 | git check out -b my-feature |
这样我们有一个新的分支为 my-feature
这个分支会保存在我们的本地 git 状态中,但同时我们的Disk状态会同步更新为 my-feature ,而如果我们切换分支,Disk 的内容也会切换到对应的分支
实际上 Disk 对于源文件来自于哪个 branch 是一无所知的,他只知道源文件长啥样,当我们使用git checkout <branch>
来切换分支时,git 会把对应的源文件同步给硬盘
现在我们的状态为:
【remote】main | 【Local】main | 【Local】my-feature | 【Disk】my-feature |
---|---|---|---|
Init | Init | Init | Init |
为什么要建立我们的feature branch ?
这样可以确保我们的主分支不会被我们的代码改动搞得不能工作,同时也非常利于多人合作(相当于我们新开了一个副本进行修改,而不是直接在源代码上进行改动)
开始修改代码
查看修改状态
我们进行代码修改之后,我们得到一个新的状态叫 f-commit
但是此时我们的改动只在 Disk 上是知道的,而git对此一无所知(因为git并不是一个实时追踪更新的软件),此时我们可以通过输入
1 | git diff |
来查看我们的git状态与本地 Disk 状态差异
比如我这里修改了 makefile 文件,输入git diff
后会看到:
如果想要退出查看git diff
,输入q
即可退出。
代码修改完成
在我们把所有的文件全部修改完毕后,在我们更新 git 状态之前,还要将修改的文件保存到暂存区中,只有保存到暂存区中,我们后续的 commit 才会将暂存区中的文件状态推送给 git
1 | git add <changed_file> |
然后我们使用
1 | git commit -m <comment> |
来将我们暂存区中的文件状态推送到 Local git 中
现在我们的状态为
【remote】main | 【Local】main | 【Local】my-feature | 【Disk】my-feature |
---|---|---|---|
Init | Init | Init | Init |
f-commit | f-commit |
推送到云端分支中
然后我们使用:
1 | git push origin my-feature |
来把我们的代码改动推送到云端中,这时我们会发现 GitHub 中多出一个分支为 my-feature,这个branch中保存着我们的代码改动
【remote】main | 【remote】my-feature | 【Local】main | 【Local】my-feature | 【Disk】my-feature |
---|---|---|---|---|
Init | Init | Init | Init | Init |
f-commit | f-commit | f-commit | ||
当修改过程中,主分支有了更新
如果我们在代码修改过程中,主分支发生了更新,我们想看看我们的代码在这个新的更新下好不好使,首先我们需要把这个新更新的版本同步到我们的 main 中
我们通过 checkout
来切换分支
1 | git checkout main |
这样我们的Local git 切换到 main 分支中,同时 Disk 中也被git同步为 main 分支状态。
【remote】main | 【remote】my-feature | 【Local】main | 【Local】my-feature | 【Disk】main |
---|---|---|---|---|
Init | Init | Init | Init | Init |
f-commit | f-commit | f-commit |
然后我们通过pull
来拉取主分支中的更新
1 | git pull origin master |
这样我们就把主分支拉取到我 Local 的 main 中
【remote】main | 【remote】my-feature | 【Local】main | 【Local】my-feature | 【Disk】main |
---|---|---|---|---|
Init | Init | Init | Init | Init |
update | f-commit | update | f-commit | update |
这样我们的 Local git 和 Disk 就和远端 GitHub 是一致的了
现在我们切换回 my-feature 这个分支中
【remote】main | 【remote】my-feature | 【Local】main | 【Local】my-feature | 【Disk】my-feature |
---|---|---|---|---|
Init | Init | Init | Init | Init |
update | f-commit | update | f-commit | f-commit |
但是我们现在的 my-feature 中并没有主分支现在的新版本,仍然是旧版本
接下来我们通过rebase
来同步这个主分支改变
1 | git rebase main |
这句的意思是,先把我的所有修改扔到一边,把这个main给同步上,然后再在同步后的基础上,尝试把我的commit给弄回去
当然这个过程中可能会出现 rebase conflict ,这时就需要你手动去选择需要哪一行代码了
rebase 成功之后,我们的状态变为了:
【remote】main | 【remote】my-feature | 【Local】main | 【Local】my-feature | 【Disk】my-feature |
---|---|---|---|---|
Init | Init | Init | Init | Init |
update | f-commit | update | update | update |
f-commit | f-commit |
更新完我们的feature branch之后,就可以把当前的状态推送到远端的 my-feature 分支中了:
1 | git push -f origin my-feature |
由于我们做了 rebase,所以我们在push 时必须加上 -f 表示强制推送(force)
然后我们的状态变为:
【remote】main | 【remote】my-feature | 【Local】main | 【Local】my-feature | 【Disk】my-feature |
---|---|---|---|---|
Init | Init | Init | Init | Init |
update | update | update | update | update |
f-commit | f-commit | f-commit |
合并到主分支中
现在我们可以在GitHub中发起一个 pull request(PR)了
为什么叫 pull request
因为我们通常认为这里是由主分支的主人来拉取所需要的分支,所以我们这些contributor 需要提出拉去请求
分支被拉取合并
当我们的 PR 成功发出后,由项目负责人来进行 Squash and merge
Squash操作是什么?
Squash就是将我们的一个分支上所做的所有改动,比如说一个分支可能有很多个commit,而一般为了 commit 的简洁,会将这些改动合并为一个改动,然后再合并到主分支中,也就是我们的所有改动被命名为了一个新的改动update2,所有的改动都被正常地合并了,只是commit的结构和数量改变了而已。
【remote】main | 【remote】my-feature | 【Local】main | 【Local】my-feature | 【Disk】my-feature |
---|---|---|---|---|
Init | Init | Init | Init | Init |
update | update | update | update | update |
update2 | f-commit | f-commit | f-commit |
删除分支
在我们的分支被合并之后,在GitHub上有一个按钮叫做 delete branch 会把我们远端这个 my-feature 给删掉
【remote】main | 【Local】main | 【Local】my-feature | 【Disk】my-feature |
---|---|---|---|
Init | Init | Init | Init |
update | update | update | update |
update2 | f-commit | f-commit |
但是远端这个被删掉了,我们的 Local git 中的并没有被删掉,此时我们切换到main分支上,然后使用:
1 | git branch -D my-feature |
来删掉这个 my-feature 分支
然后再次同步远程仓库的状态
1 | git pull origin main |
此时我们的状态为:
【remote】main | 【Local】main | 【Disk】main |
---|---|---|
Init | Init | Init |
update | update | update |
update2 | update2 | update2 |
此时我们的本地的三个工作区又保持一致了,和我们最开始的状态一致。
至此我们的一整套GitHub工作流就已经完成了!^_^