当我运行git revert
时,可能会发生冲突。 git是否依赖于3-way-merge,因为问题merge internals(参见下表)也为revert
描述了?
还原的合并基础是什么?在What are the three files in a 3-way merge for interactive rebasing using git and meld?中,它很清楚,但很难想象这是为了还原。
A - B - C - D - C^-1
(如果我想在最后还原C
。)
答案 0 :(得分:4)
是的,有一个基地。 (旁注:自从我多年前看过这段代码以来,这段代码发生了很大的变化。我在最近的挑选答案中找到了一些,你已经在这里找到了答案。)
git cherry-pick
和git revert
都由相同的源文件(builtin/revert.c
和sequencer.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
指向C
和parent
的数据,指向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
代码一样。