Вы отбираете хотя бы одно ошибочное предположение о 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.