Git 解决冲突

冲突场景

多人修改同一文件不同位置

小王和小李同时克隆了远程仓库的项目,并对其中的hello.txt文件进行了修改。

git clone https://github.com/*****/gitunion.git
hello的文件如下:
01 ------- 北京
02 ------- 上海
03 ------- 广州
04 ------- 深圳

小王对文件的修改:将01北京改为南京

小李对文件的修改:将04深圳改为杭州

此时两人提交了文件:

git push origin master

文件成功提交。同时因为两人都在同一分支开发,所以git会对他们的修改进行自动merge。

此时merge后的文件

01 ------- 南京
02 ------- 上海
03 ------- 广州
04 ------- 杭州

发现文件同时包含了两个人的最新修改。同时我们注意到整个提交的过程中并没有发生冲突,这是因为两人修改的不是同一行,所以Git能把两个最新的修改merge到一个文件中。

多人修改同一文件同一位置

此时小李把02改成了武汉,同时把04改成了成都。

小王把02改成了苏州

此时两人同时提交了文件

可以看到此时产生了冲突,导致git合并分支失败。

此时我们使用查看git管理状态:

git status

可以看到有未提交的文件。我们打开该文件查看:

<<<HEAD下表示的是小王的提交,由于小王已经将修改提交到远程仓库,所以远程仓库HEAD 指针指向小王的修改。===是分割符分隔符以下代表的是小李的提交>>>后的哈希值是小李提交的键值,该值指向小李的提交。此处由于两次提交都修改了内容的同一行,所以产生了冲突。但是我们注意到,04已经被替换成了成都

接下来我们解决冲突,再次提交,就可以合并了

  • git产生冲突后,冲突的内容需要合并,此时内容仅在工作区,未在暂存区​。需要使用add 命令。

  • git未冲突的内容​会被注册到暂存区,以便纳入下一次提交​。

避免冲突的发生

  1. 及时拉取最新代码:经常更新本地代码库,可以减少与其他开发者代码的差异,减少冲突的发生。

  2. 小步提交:频繁提交代码,可以减小每次合并的代码量,降低冲突的概率。

  3. 使用分支管理:合理使用Git分支管理,避免不同功能在同一分支上同时修改。

常用命令

git status  查看当前状态
git log  查看提交日志
git merge dev  合并dev分支至当前分支
git add .      添加当前目录全部文件至暂存区
git commit -m '测试'     提交,提交信息为测试
git push origin master  推送至远端分支(master为需要推送分支,按实际需要选择)
git pull origin master  合并远端分支至本地 (git pull 等于 git fetch + git merge)
git pull --rebase origin master rebase方式合并远端分支至本地
git branch 查看当前分支
git branch dev 创建dev分支  (dev可选)
git branch -d dev 删除dev分支
git branch -r 查看远程分支
git branch -a 查看所有分支 (包括远程分支)
git checkout master 切换至master分支
git checkout -b dev 创建dev分支并切换至dev分支
git checkout -b dev origin/dev 创建远程分支到本地
git restore file 丢弃工作区修改(file为具体文件名称)
git restore * 丢弃所有工作区修改
git restore --staged file  回退暂存区文件 不会更改文件内容
git rebase --continue   rebase后继续操作
git rebase --abort 退出rebase 操作

merge 和 rebase 区别

Merge是将一个分支的历史记录合并到另一个分支中,而rebase则是将一个分支的提交应用到另一个分支上

当你开始在一个专有的分支开发新的功能时,另一位团队成员更新了main分支的内容。这将会造成一个分叉的提交历史

使用merge

git checkout feature
git merge main

或者用下面这样的单行命令

git merge feature main

这会在feature分支中创建一个合并提交,这次提交会连结两个分支的提交历史,在分支图示结构中看起来像下面这样:

它没有破坏性。现存的分支历史不会发生什么改变

另一方面来说,这也意味着每当feature分支需要应用上游分支的更改时,都会在提交历史上增加一个无关的提交历史。如果main分支的更新非常活跃,这种操作也会对功能分支的提交历史产生相当程度的污染

使用rebase

为了替代merge操作,也可以把feature分支的提交历史rebase到main分支的提交历史顶端

git checkout feature
git rebase main

这些操作会把feature分支的起始历史放到main分支的最后一次提交之上,也达成了使用main分支中新代码的目的。但是,相对于merge操作中新建一个合并提交,rebase操作会通过为原始分支的每次提交创建全新的提交,从而重写原始分支的提交历史。

最大好处在于你可以让项目提交历史变得非常干净整洁
却需要付出两种代价:安全性和可追溯性。如果不能遵循rebase的黄金法则,重写项目提交历史会为协作工作流程带来潜在的灾难性后果。再次,rebase操作丢失了合并提交能够提供的上下文信息——所以你就无法知道功能分支是什么时候应用了上游分支的变更

可交互式rebase

可交互式rebase让你在把变更提交给其他分支之前有机会对提交记录进行修改。这甚至比自动rebase操作更强大,毕竟它提供了对于分支提交历史的完全掌控力。通常来说这一操作的使用场景在于合并功能分支到main分支之前,对于功能分支杂乱的提交记录进行整理。

进行可交互式rebase操作,需要向git rebase命令传递i选项参数

git checkout feature
git rebase -i main

执行以上命令会打开一个文本编辑器,其中内容为分支中需要移动的所有提交列表

pick 33d5b7a Message for commit #1
pick 9480b3d Message for commit #2
pick 5c67e61 Message for commit #3

上面这样的列表正表示了分支被rebase之后其历史的长相。通过修改pick命令或者对提交历史进行重新排序,你可以让最终的提交历史变成任何你希望的样子。比如说,如果第二次提交修复了第一次提交的什么BUG,你可以使用fixup命令替代pick来把两次提交压缩在一起。

pick 33d5b7a Message for commit #1
fixup 9480b3d Message for commit #2
pick 5c67e61 Message for commit #3

rebase操作黄金法则

关于git rebase的黄金法则就是永远不要在公共分支上使用它。

  1. 在公共分支上的提交应该是稳定的:公共分支(如主分支)应该是稳定的,包含经过测试的代码。我们应该避免在公共分支上进行直接提交,以免破坏稳定性。

  2. 使用Git Rebase来更新公共分支:当我们需要将本地的提交推送到公共分支时,我们应该使用Git Rebase来合并代码。这可以确保我们的提交历史整洁,不会影响团队成员的工作。

  3. 避免直接修改公共分支上的提交:如果我们需要修改公共分支上的提交记录,我们应该使用Git Rebase来执行修改,而不是直接修改提交。这可以确保修改的变化在整个分支上正确应用。

示例

假设我们有两个开发人员:Amy和Bob。他们在一个功能分支上各自提交了一些代码,并且主分支上也有一些新的提交。

  1. 首先,Amy执行了rebase操作将主分支上的提交合并到自己的分支上。这可以确保她的提交历史包含了最新的变化。

  2. 接下来,Amy将自己的分支推送到远程仓库,并创建了一个合并请求

  3. Bob在进行代码审查后,将Amy的代码合并到主分支上。由于Bob遵循了“黄金法则”,他使用rebase而不是merge来合并代码,保持了提交历史的整洁和一致性。


Git 解决冲突
http://localhost:8090//archives/git-jie-jue-chong-tu
作者
文希希
发布于
2024年12月08日
许可协议