git: загадочно появился удаленный код - PullRequest
3 голосов
/ 07 апреля 2011

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

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

  1. git blame: как ни странно, мне показали тег commit и сообщение оригинального коммита, в котором был добавлен код, как будто возврата не произошло.
  2. git log - filename: показывал все коммиты, которые я ожидал там, включая возврат, но ничего после того, что предполагало, что он должен появиться снова.
  3. Ручная проверка исправлений (bisect): код снова появился в коммите сразу после возврата, но когда я извлек это исправление, его журнал был совершенно другим и не имел возврата.

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

Так это похоже на случай? Был ли код повторно введен путем неправильного выбора во время разрешения конфликта? Если так, есть ли более быстрый способ найти такого рода вещи? Например, Git Blame сказал, что код пришел из моего оригинального патча. Но есть ли способ заставить его прямо сказать мне, что он был повторно введен в патч X после восстановления? Как git отслеживает, откуда появился каждый фрагмент кода, если он не знает, что на него повлияли во время слияния? Может ли он сказать мне, что кто-то испортил этот кусок кода во время конфликта слияния? Я полагал, что само слияние должно было появиться во вине.

1 Ответ

4 голосов
/ 07 апреля 2011

Это выглядит как окончательный случай

Git слияния, затем возврат, а затем отменить возврат

Значение: вы не должны действительно отменить коммит слияния, как когда-либо .Вместо этого «сбросить --hard» до точки, предшествующей этому.Применяются и другие низкоуровневые методы, но я рекомендую даже смотреть на них, если вы абсолютно не можете позволить толчок без ускоренной перемотки (сброс git на более ранний коммит приведет к «принудительным» толчкам при продвижении более поздней новой работы).Что делает возврат, так это возвращает содержимое .Тем не менее, исходный коммит слияния будет по-прежнему показывать источник слияния как родительский коммит.Это дурак думает, что удаленная ветвь была полностью объединена, даже если содержимое было отменено (!).Со всеми возможными неприятными последствиями.

git show-branch mybranch previouslymergedbranch`

git log --no-walk $(git merge-base -a mybranch previouslymergedbranch)

должно показывать вам связь (отношения)


@ Tesserex Хорошо ..., я сказал"выглядит как" :)

Все же есть вероятность, что вы были укушены изумительным, но обязательно несовершенным отслеживанием слияний (базовым обнаружением) git [1].Возможно, вы можете просмотреть выходные данные show-branch и merge-base в во время слияния.Если это было последнее слияние, вы можете

git rev-list --merges --parents -1 mybranch

Это должно вернуть три ша1: <mergecommit> <mergetarget> <mergesource>.Здесь mergecommit - это просто, когда произошло слияние, mergetarget - это «mybranch», а mergesource - «ранее объединенная ветвь», так что вы можете запустить вышеуказанные команды.

Возможно, что упругий коммит (который вы отменили) все еще находился в ожидании слияния (в соответствии с git) и, как таковой, был объединен повсеместно, отменяя вашу отмену 'revert'... Это может происходить по разным причинам (например, исходный коммит был перенесен вручную или конфликтует выбор вишни, что делает невозможным для git обнаружить, что коммит уже был применен к цели слияния)

Я даже не уверен, будет ли git активно обнаруживать несогласованную («чистую») вишенку в середине слияния (последовательность коммитов);Хотя это, безусловно, может:

git log --left-right --oneline --cherry-pick --graph --boundary mergetarget...mergesource

Это покажет вам то, что git видит как дельту в 'commits' между двумя ссылками во время слияния.Страница man для git-log объясняет, что --cherry-pick указывает git исключать коммиты из выходных данных, даже если они имеют другой идентификатор фиксации (хэш) , но различия идентичны для всех намерений и целей.


[1] OT: это загадка: мы можем сделать программное обеспечение умнее, но пока есть утечки абстракций, будут проблемы:

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

...