Git冲突的解决方法

说明:前段时间有点忙,没有继续写一些工作中积累总结的东西,最近时间相对比较充裕了,继续分享点东西;前面的篇章已经说过,Git是我们公司的代码管理工具,我以前没用过,在学习使用过程中碰到最多也就是冲突的解决,所以这里就分享一些网上各位前辈总结的,以及我又添加的一些知识点,适合新手学习

冲突整理

  • 冲突原因:一个人用git 写代码,而且只有一个本地分支的情况下是不会又冲突的.冲突可以说是两个分支的冲突.具体是两个已经提交的分支的相同文件相同位置的的不同操作进行了合并.

要想不产生冲突的习惯是:修改文件之前先git pull,获取远程最新的代码,同步完了之后再对代码进行修改;亦或者事先和同时操作代码的同事沟通,这样可以大概率的避免冲突的产生。

  • 注意:git pull 如果报这个异常:
fatal: refusing to merge unrelated histories 

加如下这句解决:

git pull origin master --allow-unrelated-histories

在真实的Git运行环境中,往往涉及多个用户对版本仓库的协作,而每个用户都有一个完整的Git版本仓库副本,所以在把各自的操作结果推送到远程仓库的时候出现冲突的可能性就非常高。
在Git中解决冲突的一个优雅方式是:首先通过命令git fetch获取远程仓库最新的修改,然后执行命令git merge将本地的操作结果(实际上就是一个commit)与远程仓库的修改(远程仓库最新的commit)进行合并,如果在合并的过程没有发生冲突,那么Git会生成一个新的commit,并自动提交。但是,合并并非总是成功的,因为合并的不同提交可能是同时修改了同一个文件相同区域的内容,这样就会导致冲突。冲突发生后合并操作会终止,在本地解决冲突后,除非放弃此次合并,需要更新暂存区,再提交,最终完成合并过程。
合并示意图
git fetch和git merge操作可以使用一个命令git pull独立完成
下面的简图描绘了git pull操作的过程。
在初始状态,本地仓库和远端仓库可能是这样的:
这里写图片描述
从远端仓库执行git fetch命令后:
这里写图片描述
执行git merge操作后是这样的:
这里写图片描述
最后推送到远程仓库是这样的:
这里写图片描述

模拟冲突操作
为了模拟多用户操作一个共享仓库并产生冲突的情况,需要有一个共享仓库,为了简便,可以直接在本地使用git init命令初始化一个共享仓库。
首先执行如果命令初始化一个共享仓库:
git init --bare /home/rhwayfun/java/notes/repos/share.git
• 1
这样就在响应目录下生成了一个裸仓库(没有工作区的仓库称为裸仓库)。然后在目录/home/rhwayfun/java/notes/to下面创建两个文件夹user1和user2,模拟两个用户。并在各自的目录下克隆上面创建的share仓库,以上操作命令如下:

mkdir user1
cd /home/rhwayfun/java/notes/to/user1
git clone file:///home/rhwayfun/java/notes/repos/share.git project
cd ..
mkdir user2
cd user2/
git clone file:///home/rhwayfun/java/notes/repos/share.git project

以上命令执行完毕后就分别在user1和user2两个用户目录下有了最新的远端仓库。
在user1目录执行如下操作:

cd user1/project
git config user.name user1
git config user.email user1@163.com
mkdir team
echo "I'm user1." > team/user1.txt
git add user1.txt
git commit -m "create team/user1.txt"
git push

在user2目录执行如下操作:

cd user2/project
git config user.name user2
git config user.email user2@163.com
mkdir team
echo "I'm user2." > team/user2.txt
git add user2.txt
git commit -m "create team/user2.txt"
git push

在user2执行git push操作的时候出现了异常信息:
To file:///home/rhwayfun/java/notes/repos2/share.git
! [rejected] master -> master (fetch first)
可知,user2的push操作被拒绝,而被拒绝的原因在于本地的版本库不是最新的,需要首先获取最新的远程库的提交才能继续后面的执行。因为如果没有基于最新的版本库仓库操作可以降低冲突发生的可能性。在更新本地仓库之前,可以先分析一下,user1在team目录增加了user1.txt,而user2在team目录增加了user2.txt,所以从逻辑上两者的操作是没有冲突的。再根据对合并的说明,user2执行git pull应该会自动合并。
执行git pull命令后,继续执行如下的命令,查看提交日志:

git log --oneline --decorate --graph --all
• 1
日志如下:
* 0432ca1 (HEAD -> master) Merge branch ‘master’ of file:///home/rhwayfun/java/notes/repos2/share 
|\ 
| * 5f642a9 (origin/master) create team/user2.txt 
* 14cc834 create team/user1.txt
* 

可以看到user1和user2的提交合并到一个新的提交0432ca1。所以与之前的分析是吻合的。
但是,可以发现origin/master(这是远端仓库的引用)的提交滞后与user2的提交,因此只需要执行git push就可以将user2的提交更新到共享仓库。
执行后日志输出如下:

* 0432ca1 (HEAD -> master, origin/master) Merge branch ‘master’ of file:///home/rhwayfun/java/notes/repos2/share 
|\ 
| * 5f642a9 create team/user2.txt 
* 14cc834 create team/user1.txt

由于user2又进行了一次更新,所以需要切换到user1目录执行如下操作:
cd user1/project
//获取最新的提交

git pull

冲突解决

现在user1和user2的本地仓库都是最新的了,为了制造冲突,可以在user1目录执行如下操作:

cd user1/project
touch README.txt
echo "Hello, user1." > README.txt
git add README.txt
git commit -m "create README.txt"
git push

切换到user2目录,然后执行如下操作:

cd user2/project
touch README.txt
echo "Hello, user2." > README.txt
git add README.txt
git commit -m "create README.txt"
git push

• 发现在执行git push的时候失败,于是执行git pull获取最新的提交,但是好像仍然失败了,日志如下:

U README.txt 
Pull is not possible because you have unmerged files. 
Please, fix them up in the work tree, and then use ‘git add/rm ’ 
as appropriate to mark resolution and make a commit.

git 提示我们README.txt在拉取最新的提交的时候发生了冲突,需要在工作区先解决冲突,然后重新将冲突文件添加到暂存区,再执行提交。
为了查看发生冲突的文件,可以执行如下名命令:
// 查看暂存区中记录的冲突文件

• 1 git ls-files -s

• 2 日志如下:

100644 ea9df2ef42c073de18bde4ebdf50e0ac6b1cdd2d 2 README.txt 
100644 633d2ed9d0ae01d0d07136c5b5bd857e4d945c14 3 README.txt 
100644 17874eaa4a398cc94ed294c93fdbf50f7f843d88 0 team/user1.txt 
100644 2dcb7b6ac06d93ea8e6af21ded690f5e171a407c 0 team/user2.txt

编号为2表示暂存区用于保存冲突文件在当前分支中修改的副本,查看该文件的内容执行如下命令:

git show :2:README.txt

• 1
输出结果为

Hello, user2.

编号为3的为暂存区用于保存当前冲突文件在合并版本中修改的副本

git show :3:README.txt

• 1
输出结果为:

Hello, user1.

最后看看工作区的README.txt文件的内容:

cat README.txt

• 1
输出结果:

"<<<<<<< HEAD"
Hello, user2.
"======="
"Hello, user1."
“>>>>>>> 04eed972e27e23a9874f984f08d6567e565d3436”

其中特殊标识<<<<<<<和=之间的内容是当前分支所更新的内容,特殊标识=和>>>>>>>之间的内容是所合并的版本更改的内容。所以只需要手动解决这个冲突就可以,将README.txt文件修改如下:
Hello, user2 and user1.

在user2目录下执行如下操作就可以解决冲突了。
//加上-u参数表示把工作区被跟踪的文件添加到暂存区

git add -u
git commit -m "Merge README.txt: Hello, user2 and user1."
git push

重新运行命令:

git ls-files -s

输出:

100644 2ba0d56dda48b03ef57e5fbcd793f7de1103aa0e 0 README.txt 
100644 17874eaa4a398cc94ed294c93fdbf50f7f843d88 0 team/user1.txt 
100644 2dcb7b6ac06d93ea8e6af21ded690f5e171a407c 0 team/user2.txt

可以看到所有的编号都变成了0,这样就说明已经成功解决了冲突。
小结
通过以上实际操作认识了冲产生了原因和具体解决冲突的方法,以及在解决冲突过程中使用到一些有用的命令。需要提的一点是,在工作区修改冲突文件时可以使用图形工作完成,不过楼主觉得Linux下的vim编辑器就挺好用的,所有没有介绍使用图形工作修改冲突文件的内容,但本质都是对冲突文件进行编译从而解决冲突的过程。

### 如何解决 Git 冲突的最佳实践 在团队协作开发过程中,Git 冲突是一个常见的现象。当多个开发者在同一文件的不同分支上修改同一部分代码并尝试将其合并到同一个分支时,可能会发生冲突。以下是详细的解决方案: #### 打开冲突文件 当执行 `git merge` 或 `git rebase` 命令时,如果存在冲突Git 将暂停操作并将冲突标记插入受影响的文件中。此时可以使用任意文本编辑器打开这些文件,查看具体的冲突区域。 #### 识别 Git冲突标记 Git 使用特定的标记来表示冲突的部分: - `<<<<<<< HEAD`: 表示当前分支上的代码。 - `=======`: 分隔符,用于区分两个分支的内容。 - `>>>>>>> branch-name`: 表示即将被合并的分支上的代码[^1]。 例如,在一个冲突文件中可能看到如下内容: ```text <<<<<<< HEAD 这是当前分支的代码。 ======= 这是另一个分支的代码。 >>>>>>> ``` #### 解决冲突的方式 可以通过以下几种方法之一来解决冲突: 1. **保留当前分支的更改**:删除其他分支的代码及其对应的冲突标记,仅保留当前分支的代码。 2. **采用另一分支的更改**:删除当前分支的代码及其冲突标记,仅保留另一分支的代码。 3. **手动合并代码**:根据需求将两者的改动结合起来,并移除所有的冲突标记。 完成上述任一操作后,保存文件。 #### 完成冲突解决后的后续步骤 一旦解决了所有冲突,需要通知 Git 文件已修复。这通过运行以下命令实现: ```bash git add <file-with-conflict> ``` 接着继续完成合并或变基过程: - 对于合并操作,运行 `git commit` 来提交合并结果。 - 对于变基操作,则运行 `git rebase --continue` 继续应用剩余补丁。 #### 使用图形化工具辅助解决冲突 除了手动编辑外,还可以利用专门设计的合并工具(如 VS Code、Sourcetree、Meld 等)帮助可视化地比较差异并快速选择合适的变更项。 #### 避免常见误区 值得注意的是,尽管 Git 提供了极大的灵活性,但如果沿用传统的版本控制系统思维模式(比如 SVN 或 Perforce),则可能导致不必要的复杂性和低效的操作流程。因此建议遵循针对 Git 特性的最佳实践指导原则,从而简化日常任务并提高工作效率[^2]。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值