The only real answer here is that you don't.
What Git has—what it stores—is a graph of commits. Each commit has its own unique hash ID, never to be used by any other commit in this or any other repository.1 Each commit also points (backwards) to its parent commit(s); this is what forms the graph.
That is, given a linear chain of commits, using uppercase letters to stand in for their actual big ugly hash IDs, we can draw them like this:
... <-F <-G <-H ...
The commit whose hash is H
contains the hash ID of commit G
, so that H
points to G
. The commit whose hash is G
contains the hash ID of commit F
: G
points to F
. This goes on all the way back to an initial commit, that doesn't point backwards any further. (Usually there is just one such commit, the root commit, though Git permits multiple root commits.)
A branch name like master
or develop
or whatever just points to one specific commit. That commit is the last commit in that branch. In situations like this:
I--J <-- branch1
/
...--G--H
\
K--L <-- branch2
we need two branch names to find all the commits, because Git works by having a branch name point to the last commit that we'll call "part of the branch". Commit J
is the last commit on branch1
. J
points back to I
, which points back to H
. Meanwhile the name branch2
points to commit L
, which points back to K
, which points back to H
. Note that commit H
is on both branches (as are commits G
and earlier).
If H
has a name pointing to it:
I--J <-- branch1
/
...--G--H <-- master
\
K--L <-- branch2
that's fine: commit H
i the last commit of branch master
, and H
is on all three branches.
Commits are called reachable from some point if, by following the internal backwards-pointing arrows, we can walk from that point (whatever it is) to the commit we're calling reachable. So H
is reachable from all three branches, but I
and J
are reachable only from branch1
.
When Git says that one branch name is "ahead of" another, this is because there are commits that are only reached from that one branch name. Hence branch1
is 2 commits ahead of master
, and two commits ahead of branch2
. master
is not at all ahead of either of the other names, but branch2
is 2 commits ahead of both master
and branch1
.
A regular git merge
operation combines changes and makes a new commit, and the new commit points back to both earlier commits:
I--J
/ \
...--G--H M <-- branch1 (HEAD)
\ /
K--L <-- branch2
The multiple backwards arrows coming out of M
, pointing to both J
and L
, mean that branch1 is now three commits ahead of branch2
: from branch1
we can reach commits M
, J
, and I
, as well as L
and K
and of course H
and earlier. From branch2
, we can reach L
and K
and H
and earlier, but we cannot go forward from H
to I
.
Using git merge --squash
, Git will make a new commit with the same content as the merge M
, but instead of two backwards arrows, you get just one:
I--J
/ \
...--G--H M <-- branch1 (HEAD)
\
K--L <-- branch2
It is no longer possible to move from M
to L
, so branch2
remains two commits "ahead of" branch1
.
Note, however, that commit M
has anything good from K
and L
in it. So what you can do is simply delete the name branch2
entirely:
...--G--H--I--J--M <-- branch1 (HEAD)
\
K--L [abandoned]
If there is no name by which you can find commit L
, you'll never see it again. Since commit L
was the method you used to find commit K
, you will never see that one again either. They remain in your Git repository for a while—exactly how long is hard to predict as it depends on both any hidden (reflog-only) names that still find commit L
, and on how soon the maintenance git gc
command get around to sweeping up unused commits and really removing them. But deleting the name branch2
deletes the branch2 reflog, so the only reflog that probably still remembers L
's raw hash ID is that for HEAD
.
(If you have other branch and/or tag names that remember commits L
and/or K
, they'll still be findable that way, and won't ever be collected by the git gc
garbage collector.)
Usually, after git merge --squash
, the right thing to do is to delete the other branch name, and totally forget that those commits ever existed.
1Technically, any Git repositories that never "meet" could re-use IDs from each other harmlessly. In practice, they just don't anyway. The chance of one Git object having the same hash ID as some Git object is, on its own, one in 2160. Because of the Birthday paradox, this chance rises pretty fast as the number of objects increases, but it's still on the order of 1 in 10-17 when you have fewer than many trillions of objects. See also Git hash duplicates.