Единственный реальный ответ здесь заключается в том, что вы этого не делаете.
То, что имеет Git - то, что оно хранит - это график коммитов. Каждый коммит имеет свой уникальный идентификатор ha sh, который никогда не будет использоваться никаким другим коммитом в этом или любом другом репозитории. 1 Каждый коммит также указывает (в обратном направлении) на свой родительский коммит (ы); это то, что формирует график.
То есть, учитывая линейную цепочку коммитов, используя заглавные буквы, чтобы заменить их настоящие большие уродливые идентификаторы ha sh, мы можем нарисовать их так:
... <-F <-G <-H ...
Коммит, чей ha sh равен H
, содержит идентификатор * ha sh commit G
, так что H
указывает на G
. Коммит, чье значение ha sh равно G
, содержит идентификатор кома ha sh F
: G
указывает на F
. Это продолжается вплоть до первоначального коммита, который больше не указывает назад. (Обычно существует только один такой коммит, root, хотя Git допускает несколько root коммитов.)
Имя ветви, подобное master
или develop
или что-то просто указывает на один конкретный c коммит. Этот коммит является последним коммитом в этой ветке. В таких ситуациях:
I--J <-- branch1
/
...--G--H
\
K--L <-- branch2
нам нужны два имени ветви, чтобы найти все коммиты, потому что Git работает, когда имя ветки указывает на последний коммит, который мы будем использовать назовите "часть ветви". Commit J
- последний коммит branch1
. J
указывает на I
, что указывает на H
. Между тем имя branch2
указывает на коммит L
, который указывает на K
, который указывает на H
. Обратите внимание, что коммит H
находится на в обеих ветвях (как и коммиты G
и ранее).
Если H
имеет имя, указывающее на него:
I--J <-- branch1
/
...--G--H <-- master
\
K--L <-- branch2
все в порядке: commit H
i last commit ветви master
, а H
on все три ветви .
Commits is называется достижимым с некоторой точки, если, следуя внутренним стрелкам, направленным назад, мы можем перейти от этой точки (какой бы она ни была) к коммиту, который мы называем достижимым. Так что H
достижимо из всех трех ветвей, но I
и J
достижимо только из branch1
.
Когда Git говорит, что одно имя ветви «опережает» другое, это потому что есть коммиты, которые достигаются только с этой одной ветки. Следовательно, branch1
на 2 коммита опережает master
, а два коммита опережают branch2
. master
вовсе не опережает ни одно из других имен, но branch2
на 2 коммита опережает как master
, так и branch1
.
Обычная операция git merge
объединяет изменения и создает новый коммит и новые коммиты возвращаются к обоим более ранним коммитам:
I--J
/ \
...--G--H M <-- branch1 (HEAD)
\ /
K--L <-- branch2
Множество стрелок назад, выходящих из M
, указывающих на J
и L
означает, что branch1 теперь на три коммита впереди branch2
: с branch1
мы можем достичь коммитов M
, J
и I
, а также L
и K
и, конечно, H
и ранее. С branch2
мы можем достичь L
и K
и H
и ранее, но мы не можем go переместиться с H
на I
.
Используя git merge --squash
, Git сделает новый коммит с тем же содержимым , что и при слиянии M
, но вместо двух стрелок назад вы получите только одну:
I--J
/ \
...--G--H M <-- branch1 (HEAD)
\
K--L <-- branch2
Это больше невозможно чтобы перейти от M
к L
, так что branch2
остается на два коммита "впереди" branch1
.
Обратите внимание, однако, что коммит M
имеет что-то хорошее от K
и L
в нем. Так что вы можете просто полностью удалить имя branch2
:
...--G--H--I--J--M <-- branch1 (HEAD)
\
K--L [abandoned]
Если нет имени , по которому можно найти коммит L
, вы никогда не увидите это снова. Так как commit L
был методом, который вы использовали для поиска commit K
, вы никогда не увидите его снова. Они некоторое время остаются в вашем хранилище Git - сколько именно времени трудно предсказать, поскольку это зависит как от любых скрытых (только для reflog) имен, которые все еще находят коммит L
, так и от того, как скоро команда техобслуживания git gc
пытается найти неиспользованные коммиты и действительно удалить их. Но удаление имени branch2
удаляет reflog branch2, поэтому единственный reflog, который, вероятно, все еще помнит необработанный ha sh ID L
, - это для HEAD
.
(Если у вас есть другая ветвь и / или имена тегов, которые запоминают коммиты L
и / или K
, они все равно будут найдены таким образом и никогда не будут собраны сборщиком мусора git gc
. *
Обычно после git merge --squash
правильнее всего удалить имя другой ветви и полностью забыть, что эти коммиты когда-либо существовали.
1 Технически, любой Git хранилища, которые никогда не "встречаются", могут безвредно использовать идентификаторы друг друга. На практике они просто не в любом случае. Вероятность того, что один объект Git будет иметь тот же идентификатор ha sh, что и некоторый объект Git, составляет один на 2 160 . Из-за парадокса Дня Рождения этот шанс возрастает довольно быстро по мере увеличения количества объектов, но он все равно порядка 1 в 10 -17 , когда у вас меньше, чем триллионы объекты. См. Также Git га sh дубликаты .