2016-12-19 7 views
2

У меня несколько раз натолкнулась на следующую ситуацию: на основе A я нажимаю фиксацию B. Кто-то другой тянет фиксацию B, но по какой-то причине он не возвращает буфер своего редактора и, таким образом, продолжает редактирование A. В конце концов, он нажимает фиксацию C, которая возвращает изменения B и вводит некоторые новые. Таким образом, эффект моего фиксации B теряется. Часто я заметил проблему только случайно (и тогда я мог бы легко повторно ввести B путем набора вишни). Однако я беспокоюсь, что иногда я вообще этого не замечал. Есть ли простой способ обнаружить (потенциал) такой ситуации? (Я доволен получением некоторых ложных срабатываний.) Как-то нужно определить, содержится ли инверсия B в некотором другом фиксации.Как обнаружить потенциально злую git-фиксацию (содержащую инверсию какой-либо другой фиксации)?

Я создал тестовый репозиторий, который показывает такое обязательство: https://github.com/tillmo/test

Этот вопрос связан, но отличается от How do you detect an evil merge in git?. Обратите внимание на то, что зло совершает слияние, а здесь нет.

+0

Похоже, что существует ошибка, связанная с тем, как настроены редакторы вашей команды. Я никогда не сталкивался с этой проблемой. – Kenyon

+0

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

+0

У меня нет правильного ответа (пока), но я бы сказал, что итерация по всем коммитам и вычисление пересечения их обратного diff ('commit..commit ^') с diff от его родителя ('commit^^ .. commit ^) мог найти по крайней мере большинство из этих случаев. –

ответ

0

Проще всего вы можете использовать git log -S. Скажем, вы ввели строку

FILE* = fopen(config_file, "r"); 

и кто-то еще удалил ее.

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

git log -S'fopen(config_file,' 

Первым коммят в списке является тот, который извлекал линии, второе предание тот, который его представил.

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

+0

Это слишком громоздко. Я хочу иметь возможность автоматически обнаруживать такие ситуации в существующем git-репо без необходимости заботиться о каждой отдельной строке кода. – tillmo

0

Это на самом деле несколько сложно воспроизвести. Скажем, у нас есть участники Alice (A) и Bob (B), работающие над репозиторием. В настоящее время база фиксации является X:

  master 
      ↓ 
* --- * --- X 

Теперь, как А и В, выделяющих проверили и работать на нем в том же файле. А первое, совершает и толкает изменения:

   master 
        ↓ 
* --- * --- X --- Y 

Теперь, B по-прежнему базируется на X. В настоящее время возможны две возможные ситуации:

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

    Таким образом, любое изменение изменений, внесенных с Y намеренно сделаны В.

  2. B не совершает изменения, но попытки вытащить первый (возможно потому, что B знает, что есть новые изменения на пульте дистанционного управления).Поскольку pull попытается отредактировать файл, над которым работает B (и имеет изменения), Git откажется фактически обновить рабочий каталог сообщением о том, что «локальные изменения будут перезаписаны».

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

Так что в принципе, если это произойдет, вам действительно нужно обвинить B в отмене работы A. Вне этих двух ситуаций, на самом деле нет способа найти ситуацию, о которой вы объяснили.

Единственное, о чем я могу думать, это ситуация, аналогичная (2), но где B никогда не сохранял их изменений. Поэтому, когда вызывается Y, Git имеет чистый рабочий каталог (хотя в файле есть несохраненные изменения) и корректно обновляет локальную ветвь. Затем, после этого, B может сохранить файл, приводящий к только этим изменениям, игнорируя все, что произошло в Y.

Но, это опять-таки означает, что, когда В конце концов совершают, что они включают в себя погубят изменения намеренно - или B просто не проверяет на всех каких изменений включены в коммите, который является опасным рабочим процессом для многих других причины.

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

+0

Все это правда. Однако, как я уже сказал, я все еще хочу видеть такие ситуации, а также о прошлом, когда обучение B и т. Д., Очевидно, не помогает.Кроме того, я знаю, что могут быть ситуации, когда фиксации намеренно уничтожаются. Однако, поскольку это происходит не так часто, я рад, что они были ложными срабатываниями. – tillmo

+2

Я думаю, что вы просите что-то, что нельзя сделать. Поскольку вы, по сути, будете получать уведомление каждый раз, когда что-либо было совершено. Поскольку, в любое время, когда вы меняете код, вы не работаете с кем-то, кто работает. Я не думаю, что для git есть способ разумно знать, ЧТО код важен для вас. – Kenyon

+2

Я хотел бы добавить, что B должен быть не только осведомлен о заботе о совершении совершения, но и заботиться о том, чтобы сэкономить чаще. Как вы называете 'git pull', даже не сохраняя файл раньше? –

2

В общем, это явно невозможно, но достаточно легко достать достаточно дел, чтобы сделать его стоящим. Следующее - в основном чистая теория: для Git нет ничего, чтобы сделать это.


Подумайте, как делать снимки, которые могут быть преобразованы в дельта (потому что они есть). Ваша задача, учитывая последовательность фиксаций:

...--A--B--C--D--... 

(мы несколько произвольно ограничивать это линейные Фиксации-модов к алгебре для ведения слияний очевидны, хотя и грязный) мы будем вычислять Д B, ΔC и ΔD. ΔB является просто B-A, ΔC является C-B и т. Д. Конечно, результатом «вычитания» является набор diff (или набор изменений), а не простое число. Эти дельта, однако, являются тем, что вы видите при запуске git show (или git diff). (Вы также можете избежать обнаружения переименования здесь, если попытаетесь сделать это по-настоящему и сделать его надежным.)

Далее мы хотим увидеть, включает ли ΔC "-ΔB или включает ли ΔD" "-ΔB. A нормальный git revert- отрицательная дельта, поэтому мы ищем набор изменений, который не является самовосстанавливающимся, но все же содержит a revert.

Когда мы смотрим на сырье формы git diff производства, мы находим, что для строго измененных файлов, то разница просто много шаблонных-у @@ и ломоть-контекстных линия вокруг изменения, которые выражаются исключительно как - и + строки: удалить старый, вставить новый.

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

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

Другими словами, если ΔC = -ΔB + ∂C, или ΔD = -ΔB + ∂D, то мы предположим, что одна из этих дельт была «неправильной»: она должна была быть только ∂C или просто ∂D.

Программа git patch-id может вычислять идентификатор патча для любой diff-hunk, поэтому, чтобы определить, является ли какой-то большой треугольник ΔX отрицательным от некоторого предыдущего ΔB плюс несколько меньших ∂X, вы можете просто разделить оригинал ΔB в его составные куски, отрицать каждый из них и получать его идентификатор патча. [Изменить: используйте André Sassi's suggestion - упростите это, предварительно вычислив обратный дифференциал, либо используя BB^как два входа для git diff, либо используя флаг -R, который доступен как в , так и git show.] Поместите их в основной список L Затем для любого последующего фиксации X, начиная с l = L, пройдите через компонентные куски ΔX. Вычислите идентификатор патча hunk и посмотрите, соответствует ли это следующему значению, указанному в вашем списке. Если да, отбросьте один предмет от l. Если вы опустили последний вещь от l, вы только что обнаружили, что ΔX включает -ΔB. В противном случае перейдите к следующему столбцу в ΔX. Если вы достигнете конца ΔX, не отбрасывая все значения от l, вы пришли к выводу, что ΔX не включает -ΔB.

Повторите все подозрительные коммиты, и вы увидите, сможете ли вы автоматически найти эти «случайные обратные». Обратите внимание, что преднамеренная реверсия не будет иметь ничего , но -ΔB, а также будет иметь сообщение фиксации, в котором говорится «вернуться ...».

+0

Незначительное улучшение заключалось бы в том, чтобы принять фиксацию, которая имеет большинство, но не всех, hunks в L (например, 70% или 80% из них), потому что иногда один из этих hunks, возможно, был перезаписан для некоторого нового кода - это было бы конфликт, если B (из ответа @poke) сделал правильную вещь. Как git обнаруживает, что файл был переименован, даже если произошли некоторые изменения. –

+0

@torek, Андре Сасси: Да, это то, что я имел в виду. Похоже, что пока это не реализовано ... – tillmo

 Смежные вопросы

  • Нет связанных вопросов^_^