场景:模拟两个人维护同一个 Git 分支。
先在Github 仓库里基于 master
创建一个新的分支 feature/add_git_cmds
,点击 Create branch 即可:
创建成功后,回到本地,在本地拉取两个库,模拟两个人开发。
别忘了给两个人设置不同的 user~
我们先看一下 Git 仓库的全局配置( --global
):
我们让 git_learning_A 使用默认的全局用户配置,给 git_learning_B 设置局部用户配置( --local
,优先级高于全局配置):
(配置可参考1 Git 基础 --03 | 使用 git 之前需要做的最小配置)
最后在两个本地仓库里,都基于远端feature/add_git_cmds
分支创建相关联的本地分支。
命令: git checkout -b feature/add_git_cmds origin/feature/add_git_cmds
,该命令会基于后面的远端分支创建名为前者的本地分支,跟踪远端分支,并切换到新建的分支上来。
在两个本地仓库上都进行同样的操作。
至此,模拟了两个人在同一仓库的同一分支上开发的场景,接下来针对 5 种情况一一进行试验🧪吧!
34 | 不同人修改了不同文件如何处理?#
结论先行:直接 merge 即可。
git_learning_A:修改 readme.md 文件,并推送到远端。
git push
很顺利。
查看远端仓库:
查看提交记录的作者,对应 git_learning_A 使用的全局用户配置:
git_learning_B:修改另一个文件 xxx/css.x,推送之前需要先拉取,再尝试推送。
先修改文件,假设直接推送,看看会发生什么?
前面的步骤和 git_learning_A 的类似,但是在 git push
时发生了意外,是不是似曾相识?报错和上一章中提到的一模一样:3 Git 与 GitHub 的简单同步 --33 | 把本地仓库同步到 GitHub。
❌: git push -f
强行推送。
✅:先拉取,再合并,再推送。
git fetch
:
可以看到最新 commit 的 hash 值从 d7d648a 更新到了 192a3b3。
在分支说明上发现当前分支和远端分支的状态为:ahead 1(本地有更新我没有推送到远端), behind 1(远端有更新我没有合入到本地),那么先进行合入。
git merge origin/feature/add_git_cmds
:
执行后会弹出 commit 信息的编辑,默认即可,或适当添加说明。
:wq
保存退出,可以看到 merge 成功以及修改的记录。
蓝线可以看到目前 ahead 2,也就本地多了两个 commit,还没有推送到远端;
红框即 ahead 的 2 条 commit 记录。
这时候查看本地的 readme.md 和 xxx/css.x 文件,都是修改后的样子,接下来直接 push 即可。
git push
:
推送成功!不同人在不同文件上进行协同办公还是很方便的,所以协同办公时以这种方式进行是不是很高效呢?再看看其他情况吧~
35 | 不同人修改了同文件的不同区域如何处理?#
结论先行:直接 merge 即可。
⚠️:先创造有不同区域的环境,在任一仓库的 readme.md 文件中添加多行,再推送,两个仓库保持同步。readme.md 文件修改如下:
因为上一节中的文件都是 1 行,无法做到修改不同区域。
git_learning_A:修改 readme.md 的第 4 行,直接推送。
git_learning_B:修改 readme.md 的第 7 行,先 pull,再推送。
git pull
过程中,弹出 commit 信息的编辑后, :wq
保存退出,即合并成功。
⚠️:这里直接 pull 会提示,没有明确的 pull 策略是不推荐的。
1)可以手动配置 pull 的默认策略
2)或者在 git pull
命令后加入选项,如 --rebase
、 --no-rebase
、 --ff-only
3)或者使用 git fetch
后,再选择合并策略
这时候查看本地的 readme.md 文件,符合预期,接下来直接 push 即可:
这种方式下的协同办公也是比较顺利的,Git 有能力自动进行合并~
36 | 不同人修改了同文件的同一区域如何处理?#
结论先行:在 merge 时会出现冲突,需要自行解决。
git_learning_A:修改 readme.md 的第 1 行,直接推送。
⚠️:别忘了先进行 git pull
,因为刚才 git_learning_B 做的更新还没有同步。
git_learning_B:同样修改 readme.md 的第 1 行,先 pull,手动解决冲突,再推送。
这次我们 git pull
带了选项 --no-rebase
,表示通过 merge 的方式进行拉取。
紧接着, 产生冲突了,需要我们自己解决冲突,再进行提交。
vim readme.md
,打开产生冲突的文件 :
产生冲突的位置有明显的标记,HEAD 与 === 之间代表本地的代码,hash 值与 === 之间代表合入的代码。
我们需要修改这部分代码,并删去这些特殊标记,可以这样修改:(实际开发中,记得和相关人员交流后再进行修改❗️)
:wq
保存退出后,通过 git status
查看仓库状态:
红框中,上者表示进行合并;下者则表示取消合并,回到合并前的状态。
这里我们实践一下上者。⚠️:此时修改还在工作区,我们需要先添加到暂存区,再提交。
先进行添加和提交,再进行推送:
PS: -am
包含了添加和提交两个操作。
这次我们发现 Git 没有那么智能,也不需要那么智能,因为它肯定不知道谁的代码应该被保留。
37 | 同时变更了文件名和文件内容如何处理?#
结论先行:直接 merge 即可。
git_learning_A:修改 xxx/css.x 的文件名为 xxx/css2.x。
还记得 git mv
命令吗?可跳转1 Git 基础 --06 | 给文件重命名的简便方法回顾。
git_learning_B:修改 xxx/css.x 中的内容(并不知道文件名已经修改)。
Cool~Git 可以自动解决这样的问题。查看合并情况:
可以看到不仅文件名修改过来了,文件里的修改也被保留了。
本质上,这里修改的是同文件的不同区域~
38 | 把同一文件改成了不同的文件名如何处理?#
结论先行:在 merge 时会出现冲突,需要自行解决。
git_learning_A:修改 xxx/css2.x 的文件名为 xxx/cssA.x。
git_learning_B:修改 xxx/css2.x 的文件名为 xxx/cssB.x。(并不知道文件名已经修改)。
发生冲突了~
查看文件情况:
可以看到 Git 的做法是同时保留了两个修改了文件名的文件,并且两个文件的内容没有区别。
通过 git status
也很清晰的告诉了我们文件名变更的情况,以及可以怎么做。
git rm
不需要的文件, git add
最后决定要的文件,提交,推送,即可!
看了这几种场景下的 Git 协同办公,是不是对解决冲突不再恐惧了呢?