先再现一下合并会删除代码的情况:
示例如下:
1、初始化一个仓库,并新建一个master.txt文件,然后提交。
$ git init tem
Initialized empty Git repository in D:/temp/tem/.git/
$ cd tem
$ touch master.txt
$ vim master.txt
$ cat master.txt
this is master branch!
$ git commit -a -m "commit master branch"
[master (root-commit) 3e4d6ff] commit master branch
1 file changed, 1 insertion(+)
create mode 100644 master.txt
2、新建一个分支develop,创建一个文件develop.txt,并提交。
$ git checkout -b develop
Switched to a new branch 'develop'
$ touch develop.txt
$ vim develop.txt
$ cat develop.txt
this is develop branch!
$ git add .
$ git commit -a -m "commit develop branch"
[develop f439ba3] commit develop branch
1 file changed, 1 insertion(+)
create mode 100644 develop.txt
3、创建分支feature1,新建文件feature.txt,并提交。
$ git checkout -b feature1
Switched to a new branch 'feature1'
$ touch feature1.txt
$ vim feature1.txt
$ git add .
$ git commit -a -m "feature1 commite"
[feature1 98e05e7] feature1 commite
1 file changed, 1 insertion(+)
create mode 100644 feature1.txt
4、合并develop分支。
$ git checkout master
Switched to branch 'master'
$ ll
total 1
-rw-r--r-- 1 mydwh 197121 23 Jul 22 16:18 master.txt
$ git merge develop
Updating 3e4d6ff..f439ba3
Fast-forward
develop.txt | 1 +
1 file changed, 1 insertion(+)
create mode 100644 develop.txt
5、合并feature1分支
$ git merge feature1
Updating f439ba3..98e05e7
Fast-forward
feature1.txt | 1 +
1 file changed, 1 insertion(+)
create mode 100644 feature1.txt
$ ll
total 3
-rw-r--r-- 1 mydwh 197121 25 Jul 22 17:01 develop.txt
-rw-r--r-- 1 mydwh 197121 25 Jul 22 17:03 feature1.txt
-rw-r--r-- 1 mydwh 197121 23 Jul 22 16:18 master.txt
6、删除feature1.txt文件并提交。
$ rm feature1.txt
$ ll
total 2
-rw-r--r-- 1 mydwh 197121 25 Jul 22 17:01 develop.txt
-rw-r--r-- 1 mydwh 197121 23 Jul 22 16:18 master.txt
$ git commit -a -m "delete feature1.txt,commit master branch"
[master 88cd117] delete feature1.txt,commit master branch
1 file changed, 1 deletion(-)
delete mode 100644 feature1.txt
7、登出到feature1分支,并删除master.txt,develop.txt,然后提交。
$ git checkout feature1
Switched to branch 'feature1'
$ ll
total 3
-rw-r--r-- 1 mydwh 197121 25 Jul 22 17:01 develop.txt
-rw-r--r-- 1 mydwh 197121 25 Jul 22 17:08 feature1.txt
-rw-r--r-- 1 mydwh 197121 23 Jul 22 16:18 master.txt
$ rm master.txt develop.txt
$ ll
total 1
-rw-r--r-- 1 mydwh 197121 25 Jul 22 17:08 feature1.txt
$ git commit -a -m "delete master.txt ,develop.txt,commit feature1 branch"
[feature1 70b4ed7] delete master.txt ,develop.txt,commit feature1 branch
2 files changed, 2 deletions(-)
delete mode 100644 develop.txt
delete mode 100644 master.txt
8、登出master分支,合并feature1分支。
$ git checkout master
Switched to branch 'master'
$ ll
total 2
-rw-r--r-- 1 mydwh 197121 25 Jul 22 17:11 develop.txt
-rw-r--r-- 1 mydwh 197121 24 Jul 22 17:11 master.txt
$ git merge feature1
Merge made by the 'ort' strategy.
develop.txt | 1 -
master.txt | 1 -
2 files changed, 2 deletions(-)
delete mode 100644 develop.txt
delete mode 100644 master.txt
$ ll
total 0
问题:最后一次合并,发现git不但没有合并,反而将文件给删除了,why?
首先澄清一下,git的合并是数学的集合合并吗?
非也。数学中的合并是A集合有{a,b},B集合有{c},那么合并后的集合就是{a,b,c}。
而git的合并,我认为是分支开发者意愿的合并,而不是源代码文件的合并。理解这点,对git为什么在合并时会删除文件就好理解了。
在我的实验中,如果把master分支比作公司创始人,他最先创建了文件master.txt,放到公司的仓库中,自己使用。然后master想去闭关修行,就找了一个项目经理develop,他在公司原有的基础上创建了文件develop.txt,并放到公司仓库中共自己使用。一段时间后,develop也想闭关修行,就又找了一个项目经理feature1,他创建了文件feature1.txt,供自己使用。
由于master闭关,他是不知道公司仓库里有文件develop.txt和feature1.txt的。当master与develop合并时,是他们两人共同交换了对仓库中文件的使用意愿。合并的结果,那就是master感知到仓库中有develop.txt文件,自己可以使用。注意,合并并不是master复制了develop.txt文件,而是知道仓库中有一份develop.txt文件,我可以使用。
同理,当master与feature1合并时,master感知到仓库有一份文件feature1.txt文件,自己可以使用。
这就好比,公司创始人出山了,分别与两位项目经理交换了一下意见。公司创始人发现公司资产增多了。变成了三个文件。
接下来,master与feature1都对公司进行治理。master删除了文件master.txt,develop.txt。feature1删除了文件feature1.txt。
注意这儿要理解git的删除,只要你把文件提交到仓库里,那就永远在仓库里,只要你想要,总能找到。因此,对文件的删除,可以理解为分支对文件的弃用,而不是真的从仓库中删除了。
此时的局面就是,master只使用仓库中的feature1.txt文件,而弃用master.txt,develop.txt。而feature1只使用master.txt,develop.txt文件,而弃用feature1.txt文件。当master要合并feature1分支时,很多人以为是文件的合并,那么master分支中没有文件master.txt,develop.txt,那就把feature1分支中的master.txt,develop.txt合并过来,这样,master分支就有三个文件了。而实质上不是这样子的,合并实质上是master采纳feature1的意愿。因为master删除master.txt,develop.txt文件时,feature1没有表示异议,那git就认为没冲突,master的意愿就是弃用master.txt,develop.txt这两个文件,git在合并时尊重了master的意愿。又feature1对feature1.txt文件是弃用的,master没有表示异议,那git就认为没冲突,采纳了feature1的意愿,在合并时就删除了master分支中的feature1.txt文件。最后合并的结果是:综合了两个分支对文件最新的使用意愿,那就是合并后,master分支中没有文件了。
很多人在合并分支时出现git删除源代码的情况,原理就是这样的。当你理解后,就有很多办法避免出现源代码被删除的可能。