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 это то, что устанавливает базу слияния, и nextvs-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 код.

Другие вопросы по тегам