git还原还使用3路合并吗?

时间:2016-05-10 23:27:44

标签: git merge revert git-revert 3-way-merge

当我运行git revert时,可能会发生冲突。 git是否依赖于3-way-merge,因为问题merge internals(参见下表)也为revert描述了?

enter image description here

还原的合并基础是什么?在What are the three files in a 3-way merge for interactive rebasing using git and meld?中,它很清楚,但很难想象这是为了还原。

A - B - C - D - C^-1

(如果我想在最后还原C。)

1 个答案:

答案 0 :(得分:4)

是的,有一个基地。 (旁注:自从我多年前看过这段代码以来,这段代码发生了很大的变化。我在最近的挑选答案中找到了一些,你已经在这里找到了答案。)

git cherry-pickgit revert都由相同的源文件(builtin/revert.csequencer.c)实现。

正如你所说,棘手的部分是决定为合并基础做什么。在您的示例中,我们正在撤消B - 到 - C差异。这是实际的源代码(在sequencer.c中),有点剥离:

if (opts->action == REPLAY_REVERT) {
        base = commit;
        base_label = msg.label;
        next = parent;
        next_label = msg.parent_label;
        strbuf_addstr(&msgbuf, "Revert \"");
        strbuf_addstr(&msgbuf, msg.subject);
        strbuf_addstr(&msgbuf, "\"\n\nThis reverts commit ");
        strbuf_addstr(&msgbuf, oid_to_hex(&commit->object.oid));

        if (commit->parents && commit->parents->next) {
                strbuf_addstr(&msgbuf, ", reversing\nchanges made to ");
                strbuf_addstr(&msgbuf, oid_to_hex(&parent->object.oid));
        }
        strbuf_addstr(&msgbuf, ".\n");
} else {

[这是樱桃挑选案例,仅为完整性而包含]

        const char *p;

        base = parent;
        base_label = msg.parent_label;
        next = commit;
        next_label = msg.label;

当我们在此处输入时,commit指向Cparent的数据,指向B的数据。变量base的赋值是设置合并的基础,而next - vs - base是要引入的内容。对于cherry-pick,提交的父级(可能通过{{选择) 1}})是合并基础。对于revert,提交本身是合并基础,父级(也可能来自-m)是引入的内容。

另一种获得相同效果的方法(这是多年前这样做的,直到最近,我认为这仍然被使用)是反向应用-m生成的提交。在这种情况下,构造的基本版本是第二个哈希值(文本差异的git format-patch部分中的B部分):

A..B

在将文本提取到一系列补丁中之后调用/* * This represents a "patch" to a file, both metainfo changes * such as creation/deletion, filemode and content changes represented * as a series of fragments. */ struct patch { [snip] char old_sha1_prefix[41]; char new_sha1_prefix[41]; static void reverse_patches(struct patch *p) { [snip] swap(p->old_sha1_prefix, p->new_sha1_prefix); 函数,即在从reverse_patches行提取哈希值的代码之后,放置index和{{ 1}}部分到旧的和新的前缀字段。然后(在A之后),当实际应用每个补丁时,git使用保存的旧的和新的sha1值伪造3向合并(如果给出B reverse_patches)。因此,通过反向应用文本补丁,我们将新文件作为基础,将原始文件作为目标,就像使用git am代码一样。