Как сравнить наборы изменений в Git?

Git позволяет очень легко сравнивать различия между коммитами, используя, например, команды git diff и difftool. Также в TortoiseGit вы просто выбираете две фиксации, чтобы сравнить их.

Но есть ли способ сравнить наборы изменений? Другими словами: увидеть различия между различиями одного набора коммитов и различиями другого набора коммитов.

Это было бы очень удобно для сравнения (наборов) коммитов, которые были отобраны или были перебазированы.


person Paul Pladijs    schedule 17.02.2011    source источник
comment
Это немного язвительно, но один из ответов — постараться никогда не делать этого. Если у вас есть два похожих, но не идентичных набора изменений, мы надеемся, что они должны начинаться с разумного общего предка, поэтому вы можете просто различать их. И если вы выбираете вишню/перебазируете, надеюсь, вы фактически не будете изменять набор изменений в процессе, так что нечего сравнивать; в противном случае, если вы позже измените трансплантированную версию, вы сможете просто отличить исходную трансплантированную версию от новой.   -  person Cascabel    schedule 18.02.2011
comment
Это действительно язвительно. Мне не нужно делать это часто. Однако ветки часто перебазируются (интерактивные + неинтерактивные). Итак, как интегратор очень-очень небольшой команды, я хотел бы знать, содержат ли перебазированные ветки тот же набор изменений, или посмотреть, что изменилось в наборе изменений.   -  person Paul Pladijs    schedule 18.02.2011
comment
Другая вещь, конечно, заключается в том, что если вы ищете ответ «да» или «нет», вы можете просто сгенерировать комбинированный набор различий двух наборов изменений и сравнить их. Может быть достаточно хорошо.   -  person Cascabel    schedule 18.02.2011
comment
Я только что нашел stackoverflow.com/questions/2069177/diffing-diffs-with -diff, которые ведут к другим способам сделать что-то близкое к тому, что вы хотите.   -  person MatrixFrog    schedule 09.04.2011


Ответы (5)


Возможно, diff <(git show rev1) <(git show rev2) сделает то, что вы хотите?

person Jeff Bradberry    schedule 18.02.2011
comment
Это очень удобно для сравнения наборов изменений двух отдельных коммитов, но не для их набора. Приведенный выше код работает в Linux, но не в git bash или msysgit. Однако я мог бы написать скрипт для сравнения двух наборов изменений в графическом интерфейсе difftool. - person Paul Pladijs; 18.02.2011
comment
Возможность делать такие вещи — вот почему мне нравится cygwin git, а не msysgit. - person MatrixFrog; 09.04.2011

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

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

[other history]   [ "changeset 1" ]
o - o - o - o - o ( - o - o - o - o)
 \
  (o - o - o - o - o)
  [ "changeset 2" ]

Так что же означает сравнение этих двух? Возможно, в вашем случае различия в другой истории полностью отличаются от различий двух наборов изменений, но в целом содержимое набора изменений 1 может зависеть от этой другой истории! Это означает, что у git нет хорошего общего способа выполнить подобную операцию; чтобы сделать это правильно, он должен был бы, по сути, сказать: «Какая разница между двумя конечными фиксациями, если бы я перебазировался?» Другими словами, я считаю, что единственным разумным определением различия между наборами изменений является различие между результирующими конечными фиксациями, если они перебазируются, чтобы иметь общего предка. И, конечно же, если это то, что вы хотите, то вам придется выполнить операцию в рабочем дереве - нет другого способа возиться с подобными диффами. Очевидно, что нужно сделать перебазирование и сравнить новые конечные точки (ветки):

[other history]   [ "changeset 1" ]
o - o - o - o - o ( - o - o - o - o)
                 \
                  (o - o - o - o - o)
                  [ "changeset 2'" ]

Однако перебазирование не всегда самое веселое, и я могу придумать один небольшой способ обойти это. Результирующее рабочее дерево перебазирования, при условии, что вы разрешаете конфликты надлежащим образом, должно быть таким же, как и в результате слияния:

[other history]   [ "changeset 1" ]
o - o - o - o - o ( - o - o - o - o)
 \               \
  \               ------
   \                    \
   (o - o - o - o - o) - X
    [ "changeset 2" ]

Таким образом, вы можете выполнить это временное слияние и сравнить полученный коммит с конечным коммитом другого набора изменений. Это будет намного быстрее, чем делать rebase. (В любом случае вы, конечно, будете использовать одноразовую ветку, а не настоящую для набора изменений 2.)

person Cascabel    schedule 18.02.2011
comment
Последняя схема очень хорошая идея. Пока нет конфликтов для разрешения - person Paul Pladijs; 18.02.2011
comment
Вторая диаграмма для моей команды была бы похожей на выполнение той же работы, что и один из других разработчиков. - person Paul Pladijs; 18.02.2011
comment
@Paul: Часть идеи здесь заключается в том, что если есть конфликты, которые необходимо разрешить, они по своей сути являются частью построения различия между двумя наборами изменений. Возможно, если вы думаете об этом так: вам нужна разница между двумя конечными фиксациями, при этом все различия, возникающие в результате другой истории, удалены. Отделение этих различий от различий набора изменений 1 эквивалентно разрешению конфликтов. - person Cascabel; 18.02.2011

Вот что помогло мне сравнить два набора изменений:

git diff [base_sha_a]..[final_sha_a] > ./a.diff
git diff [base_sha_b]..[final_sha_b] > ./b.diff
diff ./a.diff ./b.diff

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

person Andrew Childs    schedule 17.12.2016

Расширение ответа jeff-bradberry:

Чтобы сравнить наборы изменений, внесенные двумя отдельными коммитами:

diff <(git show -U0 <sha-A>) <(git show -U0 <sha-B>)

Чтобы сравнить наборы изменений, внесенные двумя последовательностями коммитов:

diff <(git show -U0 <sha-A>...<sha-B>) <(git show -U0 <sha-C>...<sha-D>)

Примечание. -U0 нужно избегать сравнения «контекстных» строк (то есть строк, которые изменились после ваших правок, но не непосредственно ими).

person marcotama    schedule 27.05.2020

git diff end_rev_1...end_rev_2

Взято с: http://www.kernel.org/pub/software/scm/git/docs/gitrevisions.html

Подобное обозначение r1...r2 называется симметричной разностью r1 и r2 и определяется как r1 r2 --not $(git merge-base --all r1 r2). Это набор коммитов, которые доступны либо из одного из r1, либо из r2, но не из обоих.

И из справки git diff:

git diff [--options] <commit>...<commit> [--] [<path>...]
   This form is to view the changes on the branch containing and up to the second <commit>, starting at a
   common ancestor of both <commit>. "git diff A...B" is equivalent to "git diff $(git-merge-base A B) B".
   You can omit any one of <commit>, which has the same effect as using HEAD instead.

Это работает для вас?

person ctcherry    schedule 17.02.2011
comment
Я не думаю, что это то, чего хочет ОП. Посмотрите, чему он эквивалентен — на самом деле он не имеет ничего общего с изменениями в A; он просто использует его как способ найти начальную точку для diff. - person Cascabel; 18.02.2011
comment
Это действительно не то, что мне нужно. Это отвечает на вопрос, как сравнить различия в содержимом проекта между двумя фиксациями (или ревизиями). Я хотел бы знать, как один (или несколько) коммитов меняет содержимое (=changeset) и сравнить его с набором изменений одного (или нескольких) других коммитов. - person Paul Pladijs; 18.02.2011