Команда Git для вывода списка объединенных ветвей - PullRequest
0 голосов
/ 07 октября 2019

Есть ли способ перечислить ветви, которые были объединены в текущем рабочем дереве? Следующее близко:

git branch -r --merged

Однако, это также включает пустые ветви. Например, в какой-то момент перед последним коммитом в текущей ветке я выполнил следующее:

git checkout -b empty_branch
git push -u origin empty_branch

Теперь первая команда включает в результирующий список empty_branch . Я нашел связанный вопрос, спрашивающий , как найти пустые ветви в git , но принятый ответ не работает для веток без коммитов. Есть ли способ обнаружить ветки без фиксации в git или иным образом отфильтровать такие ветки из результатов git branch --merged?

1 Ответ

1 голос
/ 07 октября 2019

Вы отбираете хотя бы одно ошибочное предположение о Git. Это не необоснованное предположение, поскольку Git странный, но немного сбивает с толку весь ваш вопрос.

В Git ветка names на самом деле не означаетстолько, сколько думает большинство людей, по крайней мере, на первый взгляд. Имя ветви просто содержит идентификатор хэша некоторого существующего коммита. Существует базовая сущность, которую люди также называют "ветвью", и она состоит из некоторых или всех коммитов, которые достижимы из коммит-подсказки, как определено именем ветви. Более подробно об этом см. Что именно мы подразумеваем под «ветвью»? и Думайте, как (а) Git , но давайте попробуем сделать краткое резюме:

  • На самом деле Git - это commits . Каждый коммит идентифицируется своим уникальным идентификатором хэша. Никакой другой коммит не может иметь этот хэш-идентификатор. Содержимое коммита включает в себя моментальный снимок - сделанный из индекса, а не из рабочего дерева, но я постараюсь не вдаваться во все эти волосатые детали - и включаю имя и адрес электронной почты автора коммита,то же самое для коммиттера (обычно это один и тот же человек) и две отметки даты и времени: одна для автора, другая для коммиттера. Они также включают в себя лог-сообщение, предоставленное коммиттером в тот момент, когда он / она / они / местоимение выбора сделали коммит. Возможно, наиболее важно, что содержимое коммита включает необработанные хэш-идентификаторы любых коммитов, которые следует считать непосредственными предшественниками этого коммита.

  • Другими словами, каждый коммит имеет некоторый набор родительский хеш-идентификаторы, чаще всего один хеш-идентификатор. Эти родительские идентификаторы создают коммиты в виде цепочек, обращенных назад: с last commit мы можем вернуться к предыдущему коммиту. Оттуда мы можем вернуться еще на один шаг и так далее. Таким образом, если имя ветви, такое как master, содержит хэш-идентификатор последнего коммита, который мы должны считать частью ветви, остальные коммиты являются родителем (-ями) этого коммита, родителем (-ями)родитель (ы) и так далее. Если хэш-идентификатор master коммита-коммита равен H, а его родительский элемент равен G, а родительский элемент G равен F и т. Д., Мы имеем:вот что такое ветвь: это либо имя, либо серия коммитов, оканчивающихся на H, либо и то и другое: мы склонны угадывать, что кто-то имеет в виду, когда они говорят "master ветвь".

Что делает git branch --merged:

  • Найти идентификатор хэша текущей ветви (HEAD).
  • Для всех имен филиалов B пропуская текущую ветку (как прочитано из HEAD) упс: Git не пропускает текущую ветку, что немного раздражает:
    • Является ли фиксация, идентифицируемая B , предком фиксации, идентифицируемой HEAD? 1 Если да, выведите имя B . В любом случае перейдите к следующему имени.

Так что если часть графика выглядит так:

             I--J   <-- feature2
            /
...--F--G--H   <-- master (HEAD)
      \
       K--L   <-- feature1

, то два коммита, которые git branch --merged будут проверены J и L по сравнению с текущим коммитом H. Если J является предком H - но это не так - выведите feature2. Если L является предком H - но это не так - выведите feature1. Конечно, H является предком H, поэтому печатает print master (с префиксом *, указывающим, что это текущая ветвь).

Если есть четвертое имя, которое указывает на любое из F, G, H или любой из коммитов "за" F, git branch --merged напечатает , что имя тоже.

Я думаю вам нужно напечатать все имена, которые указывают на любой из коммитов, которые являются настоящими предками, а не любые имена, которые указывают непосредственно на коммит H. Самый простой способ сделать это, вероятно, позволить git branch --merged напечатать все, а затем удалить из списка любое имя, идентификатор хеша которого совпадает с HEAD.

Для удаленияДля таких имен используйте git rev-parse на каждом имени. Используйте git rev-parse HEAD, чтобы найти хэш-идентификатор текущей ветви, т. Е. Фактический хеш-код для H на рисунке выше. Затем, используя git rev-parse снова для каждого имени из git branch --merged, если результат совпадает с первым git rev-parse, отбросьте это имя. В противном случае сохраните это имя.

(Для этого вам придется написать немного кода. Если git for-each-ref может сделать --not и объединить некоторые логические выражения, это, вероятно, можно сделать с этим, ноон не выполняет --not и не комбинирует.)


1 Тест is-ancestor, который использует Git, допускает равенство, т. е. это ≤, а не <(или точнее, предшествует или равно, ≼, против ≺). Это также верно для <code>git merge --is-ancestor.

...