Как вы получаете git bisect игнорировать объединенные ветви? - PullRequest
34 голосов
/ 12 апреля 2011

Я знаю, что git bisect поддерживает ветки по своему дизайну, поэтому, если между хорошим коммитом G и плохим коммитом B вы слились в ветке, он должен принять во внимание и эти изменения, так как ошибка может содержаться в ветке.

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

Тогда проблема заключается в том, что при разделении пополам в этом сценарии вы получаете некомпилируемые коммиты в коммитах из зависимости.

Я бы просто хотел рассматривать каждое слияние ветвей как один коммит при делении пополам.

Обходной путь, который я нашел до сих пор, заключается в создании списка допустимых коммитов G..B с помощью git log --first-parent, а затем при делении пополам git bisect skip, если текущий коммит отсутствует в этом списке , Хотя это занимает много времени (много файлов для проверки / изменения для каждого пропуска).

Таким образом, вопрос заключается в следующем: есть ли способ сделать --first-parent с помощью git bisect или предоставить список коммитов, которые, как я считаю, действительны, чтобы избежать проверки веток, которые, как я знаю, уже не компилируются? Как мы проверяем только коммиты, отмеченные o на диаграмме?

G---o---o---o---o---o---o---B  main project branch
   /       /       / 
  x---x---x---x---x            dependency
           \ /
            x'                 dependency project taskbranch

Редактировать : добавлена ​​схема для наглядности

Ответы [ 9 ]

11 голосов
/ 12 апреля 2011

Я тоже искал что-то подобное. Насколько я понимаю, git rev-list --bisect --first-parent, кажется, делает то, что вы хотите, и документы для rev-list подразумевают, что опция --bisect - это то, что bisect использует внутренне - но получает git bisect, чтобы добавить этот флаг в его вызов (ы) в rev-list кажется менее тривиальным:

Команда bisect реализована с помощью сценария оболочки git-bisect, который, в свою очередь, использует встроенную команду bisect--helper, чтобы фактически выполнить интересную часть («вычисление, отображение и извлечение» говорит комментарий ...), очевидно основанное на на кучу волшебных файлов состояния в .git /. И, похоже, это команда rev-list, которая повторно использует код из bisect - helper, а не наоборот, как вы могли ожидать.

Итак, вам нужно расширить биссект - фильтрацию коммитов вспомогательного кода, я думаю.

В качестве обходного пути может сработать что-то вроде этого: после того, как bisect проверит что-то для вас, вернитесь к другому с помощью git rev-list --bisect --first-parent, проверьте это и отметьте его как хороший / плохой / пропустите и продолжите с этого момента.

10 голосов
/ 13 апреля 2011

Я подумал об одном возможном решении, но я все еще надеюсь найти что-то более элегантное:

Пометить всех второстепенных всех слияний в основной ветви как хорошие

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

git rev-list --first-parent --merges --parents GOOD..BAD \
| sed 's/^[^ ]\+ [^ ]\+ //' \
| xargs git bisect good

(замените GOOD и BAD соответствующими коммитами)

регулярное выражение в sed удаляет первые два коммита каждой строки;коммит слился сам, а первый родитель оставил остальных родителей (обычно только второго).

Учитывая историю, изложенную в вопросе, запуск oneliner даст вам:

G---o---o---o---o---o---o---B  main project branch
   /       /       / 
  G---x---G---x---G            dependency
           \ /
            x'                 dependency project taskbranch

Это приведет к тому, что пополам будет проходить только коммиты на главной ветви:

    o---o---o---o---o---o

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

8 голосов
/ 13 апреля 2011

Если история выглядит так:

A - B - C - H - I - J - K - L
         \              /
          D - E - F - G

, где L - плохо, B - хорошо, и вы хотите игнорировать ветвь DEFG, затем запустите

$ git bisect start
$ git bisect skip $( git rev-list G ^C )
$ git bisect bad L
$ git bisect good B

где B, C, G и L - соответствующие шасы, кажется, делают то, что вы хотите.

5 голосов
/ 18 июня 2013

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

git rev-list --first-parent --merges --parents HEAD | cut -d' ' -f1,2 > .git/info/grafts

Просто бросьте файл трансплантатов, когда закончите с делением пополам.

2 голосов
/ 24 июля 2018

Ответ Бьорна Штейнбринка прекрасно работает, но недавно начал печатать это:

hint: Support for /info/grafts is deprecated
hint: and will be removed in a future Git version.
hint: 
hint: Please use "git replace --convert-graft-file"
hint: to convert the grafts into replace refs.
hint: 
hint: Turn this message off by running
hint: "git config advice.graftFileDeprecated false"

Вот более современная версия его решения с использованием «git replace» вместо трансплантатов:

git rev-list --first-parent --merges --parents HEAD | \
  while read COMMIT PARENT1 PARENT2; do 
    git replace --graft $COMMIT $PARENT1; 
  done

К сожалению, это намного медленнее для больших репозиториев (около 3 минут для 150k коммитов); git replace, похоже, пока что не имеет режима массового просмотра. Возможно, вы захотите ограничить список ревью только коммитами в рамках вашего раздела.

Чтобы удалить замены, когда вы закончите, вы можете rm .git/refs/replace/*.

2 голосов
/ 20 сентября 2015

Итак, предположение о том, что первый родительский элемент фиксации слияния всегда является одной и той же ветвью, не всегда верно. Например, если вы отключились от ветви темы и мастер слияния с ней обновились (поэтому для этого коммита слияния первый родитель является веткой темы), а затем извлекли мастер и слили тему обратно в нее, вы получите ускоренное слияние, которое просто перемещает мастер к коммиту слияния, у которого первый родительский элемент был вашей веткой темы. Это может показаться надуманным, но на самом деле это довольно нормальный рабочий процесс - я всегда объединяю master с моей веткой, так что мое слияние обратно с master будет тривиальным слиянием (т. Е. С возможностью быстрой перемотки вперед) (извините, Джеймс, всегда забывайте перебазировать его) .

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

Так что я попробовал это, и, похоже, у меня работает. Я написал скрипт на Python, чтобы помочь сделать это на github . Если вы запустите этот скрипт, он попытается проследить в обратном направлении и следовать вашей ветке и выдать список идентификаторов коммитов, которые являются подсказками веток, которые объединены в вашу ветку. С помощью этого списка вы можете передать их «git bisect good», и bisect затем пропустит все коммиты на слитых ветвях из вашего бисекции, достигнув желаемого результата.

1 голос
/ 22 октября 2015

Вы можете использовать git bisect start --no-checkout, чтобы избежать необходимости извлечения коммита в рабочее дерево.Тогда я подозреваю, что вы можете сделать git checkout BISECT_HEAD для коммитов, которые вы на самом деле хотите протестировать (т.е. только коммиты с первым родителем в основной ветке).Я не пробовал это, но я надеюсь, что это будет работать.

1 голос
/ 04 февраля 2014

Вы можете указать git-bisect проходить только через прародителей коммитов слияния, выполнив следующую команду:

git bisect skip $(comm -23 <(git rev-list G | sort) <(git rev-list --first-parent G | sort))
1 голос
/ 12 апреля 2011

Однако я не вижу одношагового метода, основанного на вашем текущем решении: git bisect skip может принять список пропущенных коммитов. git log branchname перечислит коммиты по ветке branchname. Так что это должно позволить вам указать список коммитов.

Если ваша зависимость и ваш основной код находятся в разных пространствах файловой системы, вы можете указать пути для включения в git bisect start. В зависимости от вашего кода, это может быть лучшим вариантом. (Почти наверняка, если у вас есть список файлов, которые могут содержать ошибку!)

Справочная страница содержит подробности; см. также есть интересное чтение.

...