Сравнение различий во вспомогательной памяти в Git

Предположим, что я просто переустановил ветвь foo на master, с конфликтами. Я хочу убедиться, что во время разрешения конфликтов я случайно не повредил содержимое foo, внеся дополнительные изменения или потеряв изменения (отличные от того, что подходит для разрешения конфликта). Я сделал это через:

diff -u <(git diff `git merge-base master [email protected]{1}` [email protected]{1}) \
        <(git diff `git merge-base master foo    ` foo    )

(обновление: или эквивалентный синтаксис ... для git-diff, который мне только что напомнили:)

diff -u <(git diff [email protected]{1}) <(git diff master...foo) | mate

Это показывает мне все изменения, произошедшие с master..foo, рассматриваемые как патч, и именно это я хочу проверить на минимальное. Однако вызов является сложным, и вывод не совсем понятен для интерпретации.

Есть ли лучший способ выполнить эту задачу - предоставить ту же информацию, но с лучшим способом или форматом - или я должен просто взять вышеописанное и обернуть его в script?

Ответ 1

То, что мы действительно хотим показать, - это комбинированный diff конфликта, который генерируется так, как будто мы выполнили слияние, чтобы получить от (a) до (b), где (a) ранее было основано (вверх по течению) и (b ) теперь основывается на (восходящем-новом).

Мы не хотим просто прямого разграничения.

Вместо этого мы можем по существу выполнить слияние, но заставляем результирующее дерево быть $b ^ {tree}, которое мы уже знаем, является правильной "конечной" точкой того, что мы хотим.

Более или менее предположим, что мы имеем

newcommit -> the new version of the series
oldcommit -> the old version of the series
upstream -> the (new) version of the base of the series

Мы можем сгенерировать слияние через

git commit-tree newcommit^{tree} -p oldcommit -p upstream -m "message"

а затем показать результат с помощью git show ", и это приведет к созданию объединенного формата diff, который отображает все необходимые биты в качестве разрешения конфликта, который автоматически игнорирует изменения, которые фактически не являются частью разрешения конфликтов.

Это даже работает для простого изменения изменений, и вы можете сделать немного больше работы, чтобы гарантировать, что сгенерированное комманда слияния имеет точные отметки времени автора и фиксации, чтобы она соответствовала нескольким вызовам (так как мы храним свободную ссылку в базу данных объектов).

К сожалению, я не смог понять, как просто получить "git diff", чтобы различать то же самое, не создавая дерева. Я не уверен, какие аргументы нам нужно пройти, чтобы добраться до этой точки.

Ответ 2

Различия между master и rebased foo:

git diff master..foo

против.

Различия pre-rebase foo после разветвления мастера (обратите внимание на три точки):

git diff [email protected]{1}

?

Ответ 3

Так как это rebase, а не слияние, вы можете сравнить foo с самим собой, но до слияния. Если я правильно назову [email protected]{1}, вы получите родительский элемент текущей фиксации для foo, и, возможно, это не то, что вы ищете.

Я думаю, вы можете сделать что-то вроде следующего (если вы не сделали git gc):

На ветке foo после rebase:

$ git reflog

Это покажет, как движется ваш филиал HEAD. Вы должны увидеть некоторые записи, подобные этому (в зависимости от того, если вы переустановите интерактивно или нет):

64d3c9e [email protected]{15}: rebase -i (finish): returning to refs/heads/master
64d3c9e [email protected]{16}: rebase -i (fixup): Fixes external dependencies
049169e [email protected]{17}: rebase -i (fixup): updating HEAD
d4c2e69 [email protected]{18}: rebase -i (pick): Fixes external dependencies
049169e [email protected]{19}: rebase -i (fixup): Imports futures
e490bed [email protected]{20}: rebase -i (fixup): updating HEAD
...
etc
...

Посмотрите вперед к последнему фиксации foo перед слиянием. В зависимости от того, что вы сделали, это может быть сложно или нет. Вот почему я не предоставил do-it script.

Поднимите идентификатор фиксации, который имеет последнюю фиксацию для foo, перед переустановкой, а затем сравните с этим идентификатором фиксации. Скажем, что идентификатор фиксации: XXXX:

 git diff XXXX...foo

Возможно, это то, что вы хотите.

Ответ 4

git-cherry ищет коммиты на одной ветке, которые не находятся на другом. Вы использовали бы его как:

git cherry -v OLDTIP TIP UPSTREAM

то есть. найдите коммиты, которые были на OLDTIP, но не на UPSTREAM..TIP. Он рассматривает подпись патча, чтобы увидеть, включен ли патч, поэтому, если патч был добавлен, сброшен или изменен во время переустановки, он появится в списке. Вещи, которые были применены без изменений, не будут отображаться.

Аналогичный эффект может быть достигнут, возвращаясь к OLDTIP и выполняя git rebase -i TIP, поскольку для этой цели используется одна и та же логика для заполнения списка коммитов.

Ответ 5

Несколько иной подход: Git имеет хорошую поддержку для показа этого в случае слияний. то есть "что изменилось относительно родителя-1, которое не может быть объяснено родителем-2?"

Есть несколько способов, которыми вы могли бы использовать эту поддержку для своей rebase:

Вариант 1:

  • Сначала выполните сбрасывание (вместо переустановки). Затем на дисплее обычного слияния будет показано, что изменилось слияние. Проверьте, что вы хотели.

  • Вернитесь назад и переустановите, и сравните переустановленный отзыв с результатом слияния - они должны быть идентичными.

Вариант 2 (если перезагрузка проще слияния):

  • Сделайте перезагрузку.
  • Используйте трансплантат, чтобы он выглядел как слияние локально/временно.

Чтобы сделать это, создайте .git/info/grafts с одной строкой:

TIP UPSTREAM OLDTIP

Где TIP - это идентификатор фиксации вашей переустановленной ветки, а остальные - два желаемых родителя (т.е. две вещи, которые вы объединили бы, если бы вы делали слияние). Затем рассмотрите его так, как если бы это было реальное слияние.

Я не уверен в его автоматизации; Я стараюсь делать это с открытым gitk, потому что он упрощает сравнение правильных версий (с помощью контекстного меню).

Если вы действительно хотите сравнить два diff, вы можете посмотреть на interdiff (1), но я не уверен, насколько хорошо он справится с разными файлами базы.