Как «git show» зафиксировать слияние с комбинированным выводом diff, даже если каждый измененный файл согласуется с одним из родителей?

186

После «простого» слияния (без конфликтов) git showобычно отображается только

commit 0e1329e551a5700614a2a34d8101e92fd9f2cad6 (HEAD, master)
Merge: fc17405 ee2de56
Author: Tilman Vogel <email@email>
Date:   Tue Feb 22 00:27:17 2011 +0100

Merge branch 'testing' into master

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

Есть ли способ заставить git по-прежнему показывать все различия в комбинированном режиме сравнения?

Выполнение git show -mпокажет различия (используя попарные различия между новой и всеми родительскими версиями соответственно), но я бы предпочел, чтобы различия были отмечены +/- в соответствующих столбцах, как в комбинированном режиме.

Тильман Фогель
источник
1
@ Тильман Vogel: пожалуйста обзор принят ответ - похоже , есть лучшие ответы
Джаян
1
@Jayan Хотя другие ответы более популярны, поскольку содержат полезные подсказки, на самом деле они не приближаются к моей проблеме, поскольку выполняют только двусторонние сравнения. Я искал трехсторонний дифференциал.
Тилман Фогель

Ответы:

-3

Нет, это невозможно сделать git show. Но иногда это было бы неплохо, и, вероятно, это было бы относительно легко реализовать в исходном коде git (в конце концов, вы просто должны сказать ему, чтобы он не обрезал то, что он считает посторонним выводом), так что патч для этого вероятно, будут приняты сопровождающими git.

Будьте осторожны с тем, чего вы хотите; объединение ветви с однострочным изменением, которое было разветвлено три месяца назад, все равно будет иметь огромное отличие от основной линии, и поэтому такое полное изменение будет почти бесполезным. Вот почему Git не показывает это.

apenwarr
источник
12
Пожалуйста, не говорите «нет способа сделать это», так как ясно, что это возможно - смотрите другие ответы. Это очень вводит в заблуждение, чтобы сказать.
кгадек
1
git show HEAD ^ ... HEAD; # за решение @ hesham_EE.
Майкл Диммитт
git show HEAD ~ 1 ... HEAD ~ 0 - только для имени; # лучший синтаксис. Для итерации pr.
Майкл Диммитт
256

Посмотрите на сообщение о коммите:

commit 0e1329e551a5700614a2a34d8101e92fd9f2cad6 (HEAD, master)
Merge: fc17405 ee2de56
Author: Tilman Vogel <email@email>
Date:   Tue Feb 22 00:27:17 2011 +0100

Merge branch 'testing' into master

обратите внимание на строку:

Merge: fc17405 ee2de56

возьмите эти два идентификатора коммитов и измените их. так что для получения различий, которые вы хотите, вы должны сделать:

git diff ee2de56..fc17405

показать только имена измененных файлов:

git diff --name-only ee2de56..fc17405

и чтобы извлечь их, вы можете добавить это к вашему gitconfig:

exportfiles = !sh -c 'git diff $0 --name-only | "while read files; do mkdir -p \"$1/$(dirname $files)\"; cp -vf $files $1/$(dirname $files); done"'

затем используйте его, выполнив:

git exportfiles ee2de56..fc17405 /c/temp/myproject
rip747
источник
Спасибо за предложение, но я думаю, что оно не решает мою проблему. Из-за ограниченной разметки и форматирования комментариев я добавил свой комментарий к вашему ответу. Простите за это! Должен быть рецензирован, пока не виден.
Тилман Фогель
6
Кажется, мое редактирование было отклонено. В итоге: ваш diff не показывает, какие дополнения приходят из какой ветки. И вы не можете различить, были ли изменения добавлены во второй или удалены в первой ветви.
Тилман Фогель
45
Лучшее решение git diff fc17405...ee2de56- это покажет все изменения на ee2de56, которые достижимы от коммитов на fc17405, что, я считаю, то, что вы хотите. Обратите внимание на 3 точки вместо двух.
Крис Наттикомб
1
@ KrisNuttycombe 3 точки и порядок. И ваш комментарий - это то, что я искал, и я думаю, что это больше похоже на то, что хотел ОП.
Изката
@KrisNuttycombe С этим как-то не работает git log, который по-прежнему показывает все коммиты, как ..вариант. ..и ...сделать то же самое для log, но потому что diffони разные !? Как получить список коммитов, которые были объединены в эту ветку?
Руди
77

Лучшее решение (упомянутое @KrisNuttycombe):

git diff fc17405...ee2de56

для коммита слияния:

commit 0e1329e551a5700614a2a34d8101e92fd9f2cad6 (HEAD, master)
Merge: fc17405 ee2de56
Author: Tilman Vogel <email@email>
Date:   Tue Feb 22 00:27:17 2011 +0100

показать все изменения ee2de56, которые достижимы с коммитов fc17405. Обратите внимание на порядок принятия хэшей - он такой же, как показано в информации о слиянии:Merge: fc17405 ee2de56

Также обратите внимание на 3 точки ...вместо двух !

Для получения списка измененных файлов вы можете использовать:

git diff fc17405...ee2de56 --name-only
CodeManX
источник
Это именно то, что я был после +1.
geedoubleya
Это фактически показывает результат конфликта слияния, тогда как другой ответ - нет.
Под
12

Вы можете создать ветку с HEAD, установленным в один коммит перед слиянием Затем вы можете сделать:

git merge --squash testing

Это объединит, но не совершит. Затем:

git diff
side2k
источник
5

Похоже, здесь ответили: https://public-inbox.org/git/7vd392ezhx.fsf@alter.siamese.dyndns.org/

Таким же образом, работает

$ git diff --cc $ M $ M ^ 1 $ M ^ 2 $ (git merge-base $ M ^ 1 $ M ^ 2)

должен показывать комбинированный патч, который объясняет состояние в $ M относительно состояний, записанных в его родителях и базе слияния.

max630
источник
Знаете ли вы, если какой-либо инструмент может быть настроен для отображения такой разности в параллельной манере, возможно, в несколько столбцов (как в окне разрешения конфликтов слияния IntelliJ)? Ваш ответ именно то, что я искал
Макс
@ Макс Нет, боюсь, что нет. Поиск в Google "n-way visual diff" дает некоторые ссылки, поэтому я попробовал их.
max630
4

Я думаю, вам просто нужно git show -c $ ref. Попытка сделать это в репозитории git на a8e4a59 показывает комбинированный diff (плюс / минус символы в одном из 2 столбцов). Как упоминается в руководстве по git-show, оно в значительной степени делегирует «git diff-tree», поэтому эти параметры выглядят полезными.

patthoyts
источник
3
Нет, для «простого» слияния git show -c $refпоказывается тот же результат, который я цитировал, т.е. никаких различий. -cвыбирает комбинированный режим сравнения, очень похожий на режим по умолчанию для коммитов слияния, который равен '--cc', смотрите git help showи git help diff-tree. Оба полностью опускают файлы, которые согласуются с любой из родительских версий этого файла.
Тилман Фогель
a8e4a59действительно, я не имею в виду слияния. Этот коммит слияния действительно содержит один файл, который отличается от обеих его родительских версий. Documentation/git-fast-import.txtнекоторые вещи добавлены от одного родителя, а некоторые от другого. Это приводит к непустому выводу изgit diff-tree --cc . Однако показаны только изменения в этом «конфликтующем» случае. Все "чистые" результаты слияния, смотрите git show -m a8e4a59, вообще не отображаются.
Тилман Фогель
1
@TilmanVogel: Спасибо, что указали на то, что "неинтересные" слияния файлов не учитываются git show -c. ( man git-diff-treeговорит «Более того, в нем перечислены только файлы, которые были изменены от всех родителей». Но я, конечно, этого не заметил.)
Пол Уиттакер
3

в вашем случае вам просто нужно

git diff HEAD^ HEAD^2

или просто хеш за вас фиксируете:

git diff 0e1329e55^ 0e1329e55^2
gurugray
источник
4
Нет, это просто двухсторонняя разница между двумя родителями. То , что я просил был режим , который одновременно показывает различий между git merge-base HEAD^ HEAD^2и HEAD^и HEAD^2в том же стиле , как это делается для файлов , которые были слиты с конфликтами.
Тилман Фогель
3

Если ваш коммит слияния является коммитом 0e1329e5, как указано выше, вы можете получить diff, который содержался в этом слиянии:

git diff 0e1329e5^..0e1329e5

Надеюсь, это поможет!

hesham_EE
источник
3

Если вы сидите на коммите слияния, то это показывает различия:

git diff HEAD~1..HEAD

Если вы не в коммите слияния, просто замените HEAD коммитом слияния. Этот метод кажется самым простым и интуитивно понятным.

Брюс Доусон
источник
1
Это не «комбинированный diff» вывод. Получение различий между каждой парой родителей и HEAD здесь не проблема.
Тильман Фогель
2

Вы можете использовать команду diff-tree с флагом -c. Эта команда показывает, какие файлы были изменены в коммите слияния.

git diff-tree -c {merged_commit_sha}

Я получил описание флага -c от Git-Scm :

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

Эхсан Мирсаиди
источник
2
Похоже, хорошая статья на эту тему: haacked.com/archive/2014/02/21/reviewing-merge-commits и, возможно, это тоже: longair.net/blog/2009/04/16/git-fetch-and-merge
Девин Г Род
1

Я построил универсальный подход к выполнению различных операций над коммитами слияния.

Шаг первый : Добавьте псевдоним в git, отредактировав ~/.gitconfig:

[alias]
  range = "!. ~/.githelpers && run_on_merge_range"

Шаг второй : В ~/.githelpers, определите функцию bash:

run_on_merge_range() {
  cmd=$1; shift
  commit=$1; shift
  range=$(git show $commit | grep Merge: | awk '{print $2 "..." $3}')
  echo "git $cmd $range $@"
  if [ -z $range ]; then
    echo "No merge detected"
    exit 1
  fi
  git $cmd $range $@
}

Шаг третий : прибыль!

git range log <merge SHA> --oneline
git range diff <merge SHA> --reverse -p
git range diff <merge SHA> --name-only

Здесь, наверное, очень много возможностей для улучшения, я просто собрал все это вместе, чтобы преодолеть досадную ситуацию. Не стесняйтесь издеваться над моим синтаксисом и / или логикой bash.

Nerdmaster
источник
Обратите внимание, что вы можете захотеть изменить «...» на «..» в бите «awk», в зависимости от того, что вам нужно и какую команду вы используете: stackoverflow.com/questions/462974/…
Nerdmaster