Я полагаю, что нашел способ справиться со всеми упомянутыми здесь угловыми случаями:
branch=branch_A
merge=$(git rev-list --min-parents=2 --grep="Merge.*$branch" --all | tail -1)
git merge-base $merge^1 $merge^2
Чарльз Бэйли совершенно прав, что решения, основанные на порядке предков, имеют лишь ограниченную ценность; в конце дня вам нужна какая-то запись «этот коммит произошел из ветви X», но такая запись уже существует; по умолчанию «git merge» будет использовать сообщение коммита, например «Merge branch 'branch_A' to master», это говорит о том, что все коммиты от второго родителя (commit ^ 2) пришли из 'branch_A' и были объединены с первым parent (commit ^ 1), который является 'master'.
Вооружившись этой информацией, вы можете найти первое слияние 'branch_A' (когда действительно появилось 'branch_A') и найти базу слияния, которая будет точкой ветвления:)
Я пробовал с репозиториями Марка Бута и Чарльза Бейли, и решение работает; как это не могло? Единственный способ, которым это не сработает, - это если вы вручную изменили сообщение о фиксации по умолчанию для слияний, чтобы информация о ветвях действительно терялась.
За полезность:
[alias]
branch-point = !sh -c 'merge=$(git rev-list --min-parents=2 --grep="Merge.*$1" --all | tail -1) && git merge-base $merge^1 $merge^2'
Тогда вы можете сделать 'git branch-point branch_A
'.
Наслаждайся;)