Как я могу обобщить слияние, чтобы обнаружить ошибочное «git merge -s ours»?

Несколько раз в прошлом у нас возникала проблема, когда разработчики (явно или фактически) выполняли git merge -s ours, когда они не должны были этого делать, коммиты были потеряны, и мы обнаружили это намного позже, когда очистка намного сложнее и требует больше времени. Тесты не провалились, потому что сами коммиты, которые добавили тесты, были молча отменены вместе с кодом, который они тестировали.

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

Lines              Left(2b3c4d) Right(3c4d5e)
Common with base   970          930
Unique wrt base    20            50
Unique wrt other   15            45
Unique wrt merge   15            45
Common with merge  995          985

Но в случае, когда слияние было выполнено неправильно, отменяя многие изменения, или когда было выполнено git merge -s ours, это может привести к появлению примерно такого отчета:

Lines              Left(2b3c4d) Right(3c4d5e)
Common with base   970          930
Unique wrt base    20            50
Unique wrt other   15            45
Unique wrt merge   15             0 !!
Common with merge  990          935
Warning: 100% of changes from 3c4d5e are missing from merge commit!

Если бы этот отчет запускался для каждой фиксации, мы могли бы помечать (с помощью задания jenkins) каждый раз, когда слияние было немного вонючим.

До сих пор я играл с git diff --stat, git diff --name-status и git diff --summary, но пока ни один из них не дал мне того, что я хочу.

Лучшее, что я могу сделать до сих пор, приведет к чему-то вроде следующего для обычного слияния:

              base..left   base..right  left..merge  right..merge
              f67c4..a9eb4 f67c4..5b592 a9eb4..cb209 5b592..cb209
 a    |                    1 +          1 +          
 b    |       1 +                                    1 +
 base |       1 +          1 +          1 +          1 +
changed       2            2            2            2
insertions(+) 2            2            2            2
deletions(-)  0            0            0            0

и для слияния ours:

              base..left   base..right  left..merge  right..merge
              f67c4..a9eb4 f67c4..5b592 a9eb4..95637 5b592..95637
 a    |                    1 +                       1 -
 b    |       1 +                                    1 +
 base |       1 +          1 +                       2 +-
changed       2            2            0            3
insertions(+) 2            2            0            2
deletions(-)  0            0            0            2

Обратите внимание, что я не только хочу обнаружить -s ours слияние, я также хочу поймать ситуацию, когда некоторые, но не все изменения находятся в результирующем слиянии. Это более общий случай обнаружения ошибочных слияний, чем просто проверка одной конкретной причины потерянных изменений.

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

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

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

Ближайшие существующие вопросы, которые я могу найти к этому: Обнаружение слияния, сделанного '-s ours' (но единственный ответ там не помогает) и "git merge -s ours" и как показать разницу (но есть ответов вообще нет).


person Mark Booth    schedule 20.01.2015    source источник
comment
Простой способ обнаружить -s ours слияние — запустить сравнение обоих родителей коммита слияния. Если один diff пустой, а родители различны, это верный признак того, что было выполнено -s ours (или эквивалентное). Например, вы можете перебрать $(git show --pretty=%P $commit) и предупредить if ! git diff -s --exit-code $parent..$commit.   -  person user4815162342    schedule 20.01.2015
comment
Лучший способ увидеть, что произошло при слиянии, IMO, - это повторить слияние самостоятельно, а затем сравнить результат с фактическим слиянием. Таким образом, 1_   -  person Tavian Barnes    schedule 20.01.2015
comment
Спасибо, @user4815162342, я примерно так и делаю, используя git diff --stat для base..left, base..right, left..merge и right..merge. Кроме того, я не хочу предполагать слияние -s ours между прочим, я также хочу поймать ситуацию, когда некоторые, но не все изменения находятся в результирующем слиянии. Я обновил свой вопрос, чтобы сделать оба более понятными.   -  person Mark Booth    schedule 20.01.2015
comment
Спасибо @TavianBarnes, проблема в том, что мы видим такие проблемы только в коммитах слияния с конфликтами, что означало бы каждый раз разрешать все конфликты. Думаю, я мог бы попробовать git checkout <left>; git merge -s recursive -X ours <right>; git diff <merge> и сравнить его с git checkout <right>; git merge -s recursive -X ours <left>; git diff <merge>, чтобы найти уникальное и обычное.   -  person Mark Booth    schedule 20.01.2015
comment
Даже при наличии маркеров конфликтов git diff покажет вам, как они были разрешены.   -  person Tavian Barnes    schedule 20.01.2015
comment
Вы видели этот ответ на Как обнаружить Злое слияние?   -  person Joseph K. Strauss    schedule 26.01.2015
comment
Спасибо @JosephK.Strauss, я этого раньше не видел. Приятно знать, что есть термин для того, что я пытаюсь обнаружить, даже если определение не совсем четкое.   -  person Mark Booth    schedule 27.01.2015
comment
На самом деле, я думаю, что то, что я хочу, — это эвристика зла, где 100% зла — это все изменения с одной стороны слияния отбрасываются, а 0% зла — все изменения с обеих сторон и никаких других изменений. У вас может быть даже ›100% зло, когда все изменения с одной стороны отбрасываются и нет изменений ни с одной стороны. *8')   -  person Mark Booth    schedule 27.01.2015


Ответы (1)


У меня была именно эта проблема, и в итоге я написал инструмент для обнаружения этих типов слияний. Хотя я не могу поделиться фактическим кодом (технически он принадлежит моему работодателю), алгоритм очень прост: пусть S1 будет набором всех файлов, в которых есть изменения между слиянием и вторым родителем слияния. Пусть S2 будет набором всех файлов, которые имеют изменения между слиянием и базой слияния. Вычтите S2 из S1, и у вас останется набор файлов, которые, вероятно, потеряли изменения из-за слияния.

Это не только обнаружит слияния, сделанные с помощью -s ours, но и обнаружит неудачные слияния, когда некоторые, но не все, изменения во втором родительском элементе попали в слияние.

person David Deutsch    schedule 12.06.2015