Какие категории во вкладке Diff после слияния - PullRequest
0 голосов
/ 03 апреля 2020

Я произвел слияние ветви с другой веткой, и на вкладке Diff есть три категории, содержащие файлы:

Diff с: origin / branch @ hash1
Diff с: origin / working_branch @ hash2
Combined Diff

Какие файлы в каждой категории? Я слил origin / working_branch с origin / branch.

Это так?

Различаться с: origin / branch @ hash1 - содержит файлы, измененные в origin / working_branch
Различаться с помощью: origin / working_branch @ hash2 - содержит файлы, измененные в источнике / ветви
Combined Diff - содержит файлы, измененные в обеих ветках

1 Ответ

1 голос
/ 04 апреля 2020

Часть этого вопроса о Git Расширения , графический интерфейс пользователя. Я не использовал это и не могу ничего ответить об этом. Другая часть этого вопроса, однако, заключается в том, что означают / показывают эти различия, и это основа c командная строка Git.

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

...---F--G--H   <-- master

или:

* 9fadedd637 (master) a commit message subject
|
* 3bab5d5625 some other commit message subject
|
* 1c56d6f57a this commit does something or other
|
:

как показано, например, git log --graph (вышеприведенный вывод моделируется и не совсем то, что показывал бы --graph, но достаточно близко).

К представлению коммита, мы можем либо проверьте его, чтобы у нас были все файлы в рабочем дереве, где мы можем их видеть; или мы можем попросить Git до показать коммит, сравнив его с его родителем. Чтобы увидеть коммит H, на кончике master мы имеем Git, извлекающие G и H во временную область (в памяти) и , сравни им.

Некоторые файлы в G соответствуют своим аналогам в H. Git вообще ничего не говорит об этих файлах. Некоторые файлы не не совпадают; для них Git показывает нам рецепт - список различий - по которому мы могли бы изменить файл в G так, чтобы он совпадал с копией в H.

Коммиты слияния имеют более одного родителя. При рисовании их с новыми коммитами вправо, как я обычно делаю в StackOverflow, мы получаем что-то вроде этого:

          I--J
         /    \
...--G--H      M--N--...
         \    /
          K--L

Commit M - это слияние с родителями J и L.

Слияние похоже на любой другой коммит: оно содержит полный снимок, а не набор изменений. Но мы можем просмотреть это при изменении , сравнив снимок в M со снимком в J:

git diff <hash-of-J> <hash-of-M>

делает именно это, для instance.

Мы также можем рассматривать это как изменения, сравнивая L против M:

git diff <hash-of-L> <hash-of-M>

Любой diff покажет изменения . Изменения, которые они покажут, разные.

Так как M - это коммит слияния, то, что мы увидим, глядя на J -vs- M, это изменения, которые мы внесли из работы, выполненной вдоль строки bottom , в коммитах K и L. Если мы сравним L -vs- M, то увидим изменения, которые мы внесли из работы, проделанной вдоль строки top , в коммиты I и J. Обратите внимание, что, возможно, L - это, например, вишня I, так что работа дублируется. В этом случае объединение заняло только одну копию этих изменений, а не две копии, поэтому не будет видеть, что в или этих двух различий.

A комбинированный diff - это нечто совершенно другое. Это, на мой взгляд, попытка быть полезной, которая не так успешна, как хотелось бы. Git комбинированный дифференциал сначала запускает каждый отдельный дифференциал - в данном случае J против M и L против M, а затем выбрасывает из этот diff любой файл, который не вообще изменился в другом diff.

То есть, предположим, что в H у нас было четыре файла, каждый из которых также находится в I , J, K, L и M, и имеют место следующие свойства:

  • same.txt одинаково во всех шести коммитах.
  • top-only.txt изменяется в I и / или J, но не в K и / или L.
  • bot-only.txt изменяется в K и / или L, но не в I и / или J.
  • both.txt изменяется в J, а также в L.

Мы также будем предполагать, что M не является злым слиянием (см. Зло сливается в git? ). То есть, H -vs- M, если мы запустим этот diff, не покажет любые изменения, которые не были получены через I, J, K или L. Более того, мы предполагаем, что изменения в both.txt не перекрывались вообще, поэтому объединение объединило оба изменения: никаких конфликтов, никаких других проблем.

Очевидно, что разница J против M ничего не показывает для same.txt: он не был затронут ни в одном из пяти коммитов, следующих после H.

Различение J против M не показывает top-only.txt потому что копия в M совпадает с копией в J. Изменения в этом файле произошли в I и / или J, т. Е. Сравнение H с J показывает изменения, но эти изменения в H версии top-only.txt, что приводит к версии J top-only.txt, применяются к версии H для получения версии M.

Diffing L против M не показывает bot-only.txt для той же причине. Опять же, M копия bot-only.txt соответствует копии L.

Только для both.txt есть различия между J и M и различиями L и M.

Если мы спросим Git о комбинированном diff представлении M, Git теперь будет:

  • diff J vs M: изменены два файла: top-only.txt и both.txt; и
  • diff L против M: два файла изменены: bot-only.txt и both.txt.

Таким образом, в списке есть три файла, по одному в обоих файлах. и один только в одном каждый. Комбинированный diff теперь выбрасывает файлы only-in-one-diff, оставляя только один файл both.txt.

На данный момент, у вас есть возможность двух разных видов комбинированный дифференциал:

  • git diff --cc (по умолчанию: обратите внимание на две черточки и две c с): это печатает ничто .
  • git diff -c ( обратите внимание на один da sh и один c): это показывает разницу для both.txt.

Значение --cc действительно имеет смысл. Идея в том, чтобы показать вам, где произошел конфликт слияния . Поскольку не было конфликтом слияния, он ничего не показывает. (Для случая, когда он действительно что-то показывает, см. раздел комбинированного различий в документации git diff .)

-c тоже имеет смысл, за исключением одного: он не показывает ни top-only.txt, ни bot-only.txt. Что нам действительно нужно здесь, но у Git нет, так это способ сравнить снимок результата слияния со снимком base merge . То есть мы могли бы посмотреть H против M. Нет встроенной операции для этого, несмотря на то, что я думаю, что, вероятно, должно быть.

Вывод git show -c, который запускает этот вид комбинированного diff, в тестовом репозитории, который я сделал здесь, это:

commit 54627dbf51ab9b27c8e5486e4755651688dd5d21 (HEAD -> merge)
Merge: da92a96 e77c224
[snip]
diff --combined both.txt
index 5d51eed,506867f..1f3f391
--- a/both.txt
+++ b/both.txt
@@@ -2,10 -2,10 +2,11 @@@ this fil
  will be
  modified in
  both branches.
 +here is the top-branch change

  The changes
  will be
  combined into
  one file
  in the merge result.
+ here is the bottom-branch change

Мы можем сделать это вручную. Смотрите скрипт ниже (с именем git-show-merge, чтобы я мог запустить его как git show-merge). Это в основном находит базу слияния от родителей указанного слияния (или HEAD по умолчанию), затем запускает требуемый diff.

Git также имеет опцию -m, доступную для git show и git log оба. Этот флаг эффективно «разбивает» слияние на отдельные «виртуальные коммиты». Каждый из них является коммитом с одним родителем, один из родителей которого является одним из родителей фактического слияния. В этом случае механизм внутренних различий Git хорошо справляется с дифференцированием, которое фиксируется как обычный дифференциал, чтобы показать вам, какие файлы были изменены.

В этом случае git show -m <hash-of-M> будет дифференцировать J -vs- M сначала, затем L -vs- M секунд и покажем вам оба различия.

Похоже, Git Расширения не имеют опции -m, но имеют возможность показывать либо J -vs- M diff, либо L -vs- M diff, либо - если вы выберете его - один из форматов комбинированного diff, вероятно, --cc вариант.

Обратите внимание, что git log -p по умолчанию не пытается , чтобы показать слияние. Используйте явную опцию -c или --cc, чтобы заставить git log показывать комбинированную разницу.


#! /bin/sh
USAGE="[commit]  the merge commit to show - default is HEAD"
. git-sh-setup
case $# in
0) set HEAD;;
1) ;;
*) usage;;
esac
commit=$1
hash=$(git rev-parse ${commit}^{commit}) || exit
set -- $(git rev-parse $hash^@)
[ $# -ge 2 ] || die "$commit ($hash) is not a merge"
set -- $(git merge-base --all $@)
case $# in
0) die "parents of ${commit} are unrelated";;
1) ;;
*) echo "warning: more than one merge base, diffing against $1";;
esac
git diff $1 $hash
...