git合并分支一看就懂简书,git 合并其他分支到当前分支
在Git中,我们可以为调试、发布、维护和其他不同的任务创建不同的分支,而不会互相干扰。让我们创建一个测试仓库,看看Git分支操作的幕后场景:
像往常一样,我们创建一个“readme.txt”文件并将其提交给仓库:
让我们来看看工作树的当前状态:
如果你注意的话,你可以看到“# On branch master”这一行,这意味着我们现在正在处理master branch。当我们建立一个新的本地仓库时,默认情况下它通常在主分支上。让我们看看Git是如何存储分支的:
文件”。git/HEAD”保存了我们当前工作的分支的信息。
在Git中,分支的命名信息保存在目录中。git/refs/heads ":
我们可以看到目录中有一个名为“master”的文件。让我们来看看内容:
你可以看到这是一个“SHA1散列字符串值”,也就是一个对象名。让我们看看这是什么样的物体:
是的,这是一个承诺。“主”文件包含由主提交的最新“对象名称”。根据这个“对象名”,我们可以找到对应的树对象(tree)和二进制对象(blob)。简而言之,我可以根据“名称”索引找到这个分支中的所有对象。
当一个朋友在自己的机器上执行我们文章中的例子时,会发现“cat refs/heads/master”命令的执行结果和文章中的不一样。在本文中,这个提交的名称是:“12 c 875 f 17 C2 e 8 c 37d 31 b 40fb 328138 a 9027 f 337”。前面我说过Git根据对象的内容生成“SHA1散列字符串值”作为名称。只要内容相同,那么对应的名称一定是相同的。为什么不一样?Git确实根据内容生成名称,相同的名称(SHA1散列字符串值)肯定会有相同的内容。但是commit对象和其他对象有点不一样,里面会多一个时间戳,所以不同时间生成的commit对象即使内容完全相同,名字也不会一样。
以下命令用于查看主分支的最新提交:
“1300697913 0800”这是时间戳。
现在看看这个分支中包含的数据(blob)。
查看当前的readme.txt
好的,首先是在高手分支里玩,然后我们想创建自己的测试分支来玩。git branch命令可以创建一个新的分支,或者查看当前仓库中现有的分支。让我们首先创建一个名为“测试”的分支:
让我们看看当前项目仓库中有多少个分支:
现在我们检查工作目录的“测试”分支:
现在,让我们看看我们在哪个分支上:
好了,我们现在在“test”分支中,所以让我们修改“readme.txt”文件并提交给本地仓库分支:
当查看当前版本中包含的blob时:
现在让我们像以前一样看看Git是如何存储“测试”分支的。首先,让我们看看文件”。git/HEAD”指向新的分支:
没错,”。git/HEAD”确实指向。让我们来看看”的内容。git/refs/heads "目录:
我们可以看到,目录中还有一个名为“test”的附加文件。让我们来看看内容:
检查测试分支的最新提交(测试):
查看此分支中包含的数据(blob ):
检查当前“readme.txt”文件的内容:
让我们回到主分支:
如果我们想要看到主分支和测试分支之间的区别,我们可以使用git diff命令来查看它们之间的区别:
可以看到,与测试分支相比,少了一行:“-In test branch”。
如果执行git diff命令后认为测试分支(test)的修改是正确的,可以在可以合并的时候用git merge命令将其合并到主分支(master)中:
“更新b765df9.7f3c997”意味着“b765df9”和“7f3c997”两个提交之间的内容正在被更新;“b765df9”代表主机,“7f3c997”代表测试。
这里的“快进”可以理解为没有冲突的顺利合并。“readme.txt 1”表示该文件中有一行被修改,“1files changed,1insertions(),0deletions (-)”表示本次合并中只修改了一个文件,插入了一行新数据,删除了0行。
现在我们来看看合并后的“readme.txt”的内容:
内容没有问题。它是“主”分支和“测试”分支合并的结果。如果用“git status”来看,当前工作目录的状态也是干净的。
好了,现在测试分支已经完成了任务。如果它没有值,可以用“git branch -d”命令删除这个分支:
如果你要删除的分支还没有合并到其他分支中,就不能用“git branch -d”删除,需要用“git branch -D”强制删除。
如何处理冲突?
前面说了一些分支的事情,我简单合并了一个分支。但是平时多人协作的过程中几乎不会发生冲突。下面的例子是为了分析冲突的原因和背后的故事:
像往常一样,为实验构建一个空的Git仓库:
在主分支中创建一个“readme.txt”文件,提交到本地仓库的主分支(master):
当查看当前版本中包含的blob时:
文件“readme.txt”虽然提交的比较早,但还是会暂时存放在临时存储区,直到下次“git add”的时候被冲走:
然后创建一个测试分支,并切换到测试分支来工作:
重写测试分支中“readme.txt”的内容,提交到本地仓库:
现在看看当前分支中“readme.txt”的“SHA1散列字符串值”。真的很不一样:
集结地的情况有所不同:
现在,让我们切换到主分支(master),在“readme.txt”上做一些修改,然后提交到本地仓库:
现在看看当前分支中“readme.txt”的“SHA1散列字符串值”:
临时区域的内容也发生了变化:
主分支(master)和测试分支(test)中的内容分别发生了变化(多样化)。我们现在使用“git merge”命令来合并这两个分支,看看:
合并命令的执行结果不是“快进”,而是“冲突”。是的,两个分支的内容是不同的,所以它们不能自动合并。
让我们先来看看工作目录的状态:
现在Git提示目前有一个文件“readme.txt”因为“都修改了”而没有合并。
再次查看临时存储区的内容:
看看里面每个blob对象的内容:
我们不难发现,“aac629”是当前主分支的内容,“034a81”是测试分支的内容,“4b5fa6”是它们共同的父代的内容。因为合并的过程中出现了错误,Git把他们三个放在了临时存储区。
现在让我们来看看工作目录中“readme.txt”文件的内容:
这里的“头”是当前版本中的内容;“======”下,上方“测试”表示测试分支中相应的冲突内容。我们在修复冲突时要做的,一般是去掉“头”,“=====”和“测试”,然后把代码改成我们想要的样子。
假设我们使用编辑器将“readme.txt”更改为以下内容:
但是修改后的“readme.txt”用“git add”添加到临时存储区,最后用“git commit”提交到本地仓库。这个冲突解决了:
这里看起来怪异的是Git是如何解决冲突的:如何使用“git add”添加到临时存储区。“git add”不是用于非暂存的文件吗?它如何再次解决冲突?不过我觉得仔细看了上一篇文章就不难理解了,因为Git是一个“快照”存储系统,所有新增的内容都是直接存储的,而不是和老版本对比,存储新旧版本的差异。
在Git中,两个版本之间的相同文件被合并。如果两个版本的内容相同,则不会进行处理。如果两个版本的内容不同,但可以合并,将生成一个新的blob对象。但是,当两个版本的内容不同时,在合并过程中会发生冲突。冲突解决后,我们需要将文件“git add”到临时存储区,然后“git commit”到本地仓库,这将像以前一样生成一个新的blob对象。
假设我们对合并的结果不满意,我们可以用下面的命令撤销之前的合并:
从git reset(2)命令的输出结果可以看出,主分支已经恢复到合并前的状态。
让我们使用以下命令来查看“readme.txt”文件,以确认该文件是否已被改回:
因为Git采用了“求SHA1哈希串的值”和“快照”的方法,所以在Git中创建分支的开销很小,速度很快;也正因为如此,其处理合并冲突的方法不同。
这里我想起了“C语言是汇编(计算机硬件)的马甲”这句话。其实Git也是底层文件系统的马甲,只不过它有版本控制功能,效率更高。Git中的一些命令可能不太好理解(比如git add解决合并冲突),但是对于系统层来说,它是最高效的,就像C语言中数组下标从0开始一样。