Использует ли git revert трехстороннее слияние?

Когда я запускаю git revert, может случиться конфликт. Полагается ли git на трехстороннее слияние, как это показано в вопросе слияние внутренних компонентов (см. .таблицу ниже) также для revert?

введите здесь описание изображения

Что такое база слияния для возврата? В Что представляют собой три файла в трехстороннем слиянии для интерактивного ребазинга с использованием git и meld? это вполне понятно, но сложно представить это для реверта.

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

(Если я хочу вернуть C в конце.)


person white_gecko    schedule 10.05.2016    source источник


Ответы (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 — это то, что нужно ввести. Для вишневого выбора родительский коммит (возможно, выбранный через -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.

person torek    schedule 11.05.2016
comment
Спасибо, торек. Я был бы признателен, если бы вы также рассмотрели stackoverflow.com/questions/54335571/ - person Tim; 24.01.2019