GIT 合并基本原理
二路合并
二路合并就是逐行对比,如果行内容不同这报冲突。
本地提交
console.log('hello world')
其他提交
console.log('world hello')
假设这是修改了同一个文件,进行合并时,发现这一行不一致,git 没有理由去丢弃本地提交或者其他提交,只能人为处理
三路合并
三路合并就是先找一个 base,如果两个文件相对于 base 都有修改,那就会报冲突,则需要人工修改,否则,git 将相当于 base 变化来决定最终结果
// base
console.log('hello world')
// mine
console.log('hello world')
// theirs
console.log('world hello')
base: 代表 mine 和 theirs 的公共祖先 mine: 代表本地修改 theirs: 代表合并其他人修改
当前的情况表示代码其他人有修改,但是本地没有修改,则 git 会自动把结果合并为 theirs 的代码
console.log('world hello')
如果本地文件被修改,合并的分支也有修改
// base
console.log('hello world')
// mine
console.log('hello world 1111')
// theirs
console.log('world hello')
git 无法合并,需要人为进行合并
<<<<<<< Mine
console.log('hello world 1111')
=======
console.log('world hello')
>>>>>>> Theirs
简单示例
1-9 表示每个修改后的 commit 以及一个唯一的 hash 值。
2 开始分出了一个 dev 分支, 4 7 是 master 上的提交,3 5 8 是 dev 上的提交
现在要合并 7 和 8,可以把 git 提交记录看成一个有向无环图,这样就可以找到 2 为他们的 base 节点,就可以用来对比文件是否有修改
递归三路合并原理
- 0: 的位置创建了 a.js
console.log('a')
git add .
git commit -m "0"
- 1: 的位置从 master 上创建了一个新的分支 test1,并且创建了一个提交,没有修改 a.js
git checkout -b test1
# 用于创建提交
touch test1.js
git add .
git commit -m "1"
- 2: 的位置在 master 中创建了一个提交,没有修改 a.js
git checkout master
# 用于创建提交
git touch test2.js
git add .
git commit -m "2"
- 3: 的位置在 test1 中创建了一个提交,没有修改 a.js
git checkout test1
git touch test3.js
git add .
git commit -m "3"
- 4: 的位置在 master 中修改了 a.js,并且创建了一个提交
console.log('b')
git checkout master
git add .
git commit -m "4"
- 5: 的位置从 master 上创建了一个新的分支 test2,并且合并了 test1 的代码,即合并 4 和 3 的代码,从前面可知,4 修改了 a.js 的代码,test1 分支中没有修改 a.js,他们的公共祖先是 0
git checkout -b test2
git merge test1
// 0
console.log('a')
// 3
console.log('a')
// 4
console.log('b')
由此对比出,合并后的为 4 中的内容,因为 3 没有修改该文件
console.log('b')
- 6: 的位置切换到了 master 分支,并且合并了 test1 的代码,即合并 3 和 4 的代码,原理和 5 一致
git checkout master
git merge test1
- 7: 的位置切换到了 test2 分支,并且修改 a.js 的代码,创建了一个提交
console.log('c')
git checkout test2
git add .
git commit -m "7"
- 8: 的位置切换到了 master ,合并 test2 的代码,即合并6 和 7 此时,
git checkout master
git merge test2
6 和 7 有两个公共的祖先,4 和 3, 这时候会递归的去找 4 和 3 的祖先,则是 0,先合并 4 和 3,生成临时的节点,假设为 x ,根据上面的结论,x 中 a.js 为
console.log('b')
然后把 x 当作 6 和 7 的祖先,进行合并
// x
console.log('b')
// 6
console.log('b')
// 7
console.log('c')
所以合并结果为
console.log('c')