Git revert также использует 3-way-merge?
Когда я бегу git revert
Может случиться, что возник конфликт. Git полагается на 3-way-merge, как это изображено в внутреннем вопросе merge (см. Таблицу ниже) также для revert
?
Что такое база слияния для возврата? В Что входят три файла в трехстороннем слиянии для интерактивного перебазирования с использованием git и meld? это довольно ясно, но трудно представить это для обратного.
A - B - C - D - C^-1
(Если я хочу вернуться C
в конце.)
1 ответ
Да, база есть. (Примечание: этот код сильно изменился с тех пор, как я смотрел на него много лет назад. Я взял некоторые из них для своего недавнего ответа на вопрос, который вы связали здесь.)
И то и другое 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, родитель коммитов (возможно, выбран через -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
линии, поставив A
а также B
разделяется на старые и новые префиксные поля. Затем после reverse_patches
), при фактическом применении каждого патча, git использует сохраненные старые и новые значения sha1 для фальсификации трехстороннего слияния (если git am
дано --3way
). Таким образом, применив текстовое исправление в обратном порядке, мы получим новый файл в качестве основы и оригинал в качестве цели, как sequencer.c
код.