发布网友 发布时间:2022-05-07 20:12
共3个回答
热心网友 时间:2022-04-18 18:29
在解决gitmerge的冲突时,有时我总忍不住吐槽git实在太不智能了,明明仅仅是往代码里面插入几行,没想到合并就失败了,只能手工去一个个确认。真不知道git的合并冲突是怎么判定的。在一次解决了涉及几十个文件的合并冲突后(整整花了我一个晚上和一个早上的时间!),我终于下定决心,去看一下gitmerge代码里面冲突判定的具体实现。正所谓冤有头债有主,至少下次遇到同样的问题时就可以知道自己栽在谁的手里了。于是就有了这样一篇文章,讲讲gitmerge内部的冲突判定机制。recursivethree-waymerge和ancestorgit的源码先用merge作关键字搜索,看看涉及的相关代码。找了一段时间,找到了gitmerge的时候,比较待合并文件的函数入口:ll_merge。另外还有一份文档,它也指出ll_merge正是合并实现的入口。从函数签名可以看到,mmfile_t应该就代表了待合并的文件。有趣的是,这里待合并的文件并不是两份,而是三份。intll_merge(mmbuffer_t*result_buf,constchar*path,mmfile_t*ancestor,constchar*ancestor_label,mmfile_t*ours,constchar*our_label,mmfile_t*theirs,constchar*their_label,conststructll_merge_options*opts)看过githelpmerge的读者应该知道,ours表示当前分支,theirs表示待合并分支。看得出来,这个函数就是把某个文件在不同分支上的版本合并在一起。那么ancestor又是位于哪个分支呢?倒过来从调用方开始阅读代码,可以看出大体的流程是这样的,gitmerge会找出三个commit,然后对每个待合并的文件调用ll_merge,生成最终的合并结果。按注释的说法,ancestor是后面两个commit(ours和theirs)的公共祖先(ancestor)。另外前面提到的文档也说明,git合并的时候使用的是recursivethree-waymerge。关于recursivethree-waymerge,wikipedia上有个相关的介绍#Recursive_three-way_merge)。就是在合并的时候,将ours,theirs和ancestor三个版本的文件进行比较,获取ours和ancestor的diff,以及theirs和ancestor的diff,这样做能够发现两个不同的分支到底做了哪些改动。毕竟后面git需要判定冲突的内容,如果没有原初版本的信息,只是简单地比较两个文件,是做不到的。鉴于我的目标是发掘git判定冲突的机制,所以没有去看git里面查找ancestor的实现。不过只需肉眼在图形化界面里瞅上一眼,就可以找到ancestorcommit。(比如在gitlab的network界面中,回溯两个分支的commit线,一直到岔路口)有一点需要注意的是,revert一个commit不会改变它的ancestor。所谓的revert,只是在当前commit的上面添加了新的undocommit,并没有改变“岔路口”的位置。不要想当然地认为,revert之后ancestor就变成上一个commit的ancestor了。尤其是在revertmergecommit的时候,总是容易忘掉这个事实。假如你revert了一个mergecommit,在重新merge的时候,git所参照的ancestor将不是merge之前的ancestor,而是revert之后的ancestor。于是就掉到坑里去了。建议所有读者都看一下git官方对于revertmergecommit潜在后果的说法:mit的公共祖先,比较同一个文件分别在ours和theirs下对于公共祖先的差异,然后合并这两组差异。如果双方同时修改了一处地方且修改内容不同,就判定为合并冲突,依次输出双方修改的内容。热心网友 时间:2022-04-18 19:47
版本不一致,服务器上header指针所指向的文件版本和本次提交更改有冲突。或者本次合并请求与服务器上文件有冲突,需要手动更改。热心网友 时间:2022-04-18 21:22
譬如 remote 有 commit 1,2,4