Git branch --merged/--no-merged и опция -squash

git branch --merged, похоже, не играет хорошо с --squash.

Если вы делаете обычный git merge, то git branch --merged сообщает, какие ветки были объединены. Однако это не так, если используется опция -squash, хотя результирующее дерево одинаков.

Я сомневаюсь, что это дефект git и хотел бы знать, есть ли какой-либо git -fu, который я пропускаю, или если я что-то неправильно понял.

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

Ответ 1

Вы не можете добраться отсюда (как сказал тот, кто дал указания). Точнее, это не имеет смысла.

Проблема заключается в том, что git merge --squash фактически не выполняет слияние. Предположим, что ваша история ветвей выглядит, например (с ветвями topic и devel):

          H ⬅ I ⬅ J     <-- topic
        ⬋
⬅ F ⬅ G
        ⬉
          K ⬅ L         <-- devel

Если вы выберете devel и смените topic, вы получите новое слияние commit M, которое содержит результат слияния, а M имеет два родителя:

          H ⬅ I ⬅ J     <-- topic
        ⬋         ⬆
⬅ F ⬅ G           ⬆
        ⬉         ⬆
          K ⬅ L ⬅ M     <-- devel

Но если вы используете git merge --squash topic, вместо этого вы получаете новый фиксатор (пусть обозначают его S для сквоша):

          H ⬅ I ⬅ J     <-- topic
        ⬋
⬅ F ⬅ G
        ⬉
          K ⬅ L ⬅ S     <-- devel

где (как вы уже отметили) содержимое (дерево) commit S делает все файлы такими же, как и в commit M. Но там нет обратной ссылки (родительская стрелка) от S до topic. Это не слияние вообще, оно просто принимает все изменения от topic, сбрасывая их в одно изменение и добавляя это как полностью независимую фиксацию.

Теперь, еще о git merge --squash заключается в том, что он не делает окончательную фиксацию. Таким образом, вы можете создать файлы .git, которые git будут использовать для "регулярного" слияния, и сделать фиксацию, в которой у вас есть два родителя с "реальным" слиянием. И тогда вы получите... точно то, что вы получите, если вы запустите git merge topic, commit (отметьте его S или M, это не имеет значения), у которого есть то же дерево снова, но теперь имеет два родителя - стрелки, указывающие на L и J, как и на M.

Фактически, запуск git merge --squash почти точно совпадает с запуском git merge --no-commit, за исключением файлов отслеживания, оставшихся после завершения слияния (git commit использует некоторые из них для настройки родителей). Версия squash не записывается в .git/MERGE, .git/MERGE_HEAD и .git/MERGE_MODE. (Он создает .git/MERGE_MSG, то же самое, что и git merge --no-commit, а также создает .git/SQUASH_MSG.)

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