Merge does not delete commits. Merge either adds commits, or, in the case of a "fast forward" merge, simply "slides the label forward".
I find drawings of the commit graph, even (or maybe "especially") simplified ones, help a lot.
According to your description you had something like this:
..- o - o - o - o - o - o <-- root
\
o - C - P <-- production_support
\
o - o <-- feature
where each o
is an "uninteresting" commit (or maybe even quite a few commits) and the uppercase letters are commits that I intend to talk about below, so that I have given them letter-names.
Here there are three branches, whose branch-tips are labeled root
, production_support
, and feature
. Commit C
is the one common to both production_support
and feature
, and commit P
is reachable only by the branch-tip-label production_support
.
Again, according to your description, someone deleted the branch label production_support
. The graph now looks like this:
..- o - o - o - o - o - o <-- root
\
o - C - P [no label - abandoned]
\
o - o <-- feature
Commit P
is now unreachable, except through git's "reflogs", which keep a record of where labels used to point.
The reflog for branch label production_support
is deleted when the label is deleted, so that one is no help; but in at least one repository, at the time commit P
was made, it was made on HEAD
as well as on production_support
. That particular HEAD-reflog-entry can protect P
for a little while (30 days by default).
Once the last reference to a commit is gone, the commit is eligible for garbage collection. So if nothing else is hanging on to commit P
, it will be collected with other garbage and discarded.
Going back to your description, after the above occurred (and possibly after P
has been garbage collected as well), someone made a new branch label spelled the same way as the old branch label, and then made commits there, changing the picture to something like this:
o <-- production_support
/
..- o - o - o - o - o - o <-- root
\
o - C
\
o - o <-- feature
You then did:
$ git checkout production_support && git merge feature
which made a new merge commit M
(the graph now gets very messy :-) ... we could redraw it but that's probably just as bad, at this point):
o - M <-- production_support
/ /
..- o - o - o - o - o - o <-------- root
\ |
o - C |
\ /
o - o <---- feature
It's true that commit P
is (still) nowhere to be seen, but this is not because of the merge. The merge just added a new commit, M
, with two parents. M
's first parent is the old branch-tip (the o
to the left of M
; production_support
now points to M
instead) and its second parent is the merged-in commit (the commit to which feature
points).
To get commit P
back, if it exists at all (has not been garbage-collected), you must find it by some means other than a branch-label-name, because that went away when branch label production_support
was first deleted. Look in the HEAD
reflog on the repository on which it was created, or use git fsck
to see if there are "dangling commits" that can be restored by adding a label (such as branch or tag name) to them.
In this particular case, where commit P
has C
as its immediate ancestor, if you find a commit by SHA-1 ID and think it might be P
, you can check by looking at it and its parent(s). For instance:
$ git fsck
...
dangling commit de7c26f2b124f0038ab0ed03da9cb47647fc9867
...
$ git log de7c26f2b124f0038ab0ed03da9cb47647fc9867
This will show the log of "might-be-P" and its parents, and if commit C
shows up that's probably it. Or, you can automate it by collecting all the candidates, finding the raw SHA-1 for commit C, and comparing the parents of each candidate:
$ id_for_c=... # find SHA-1 for commit C, put that in here
$ for id in $(cat /tmp/candidates); do
> [ $(git rev-parse ${id}^) = $id_for_c ] && echo "likely match: ${id}"
> done
(not actually tested, could contain typos or similar).
If P
really represents a whole series of commits, checking for C
as immediate parent would be pointless (you'd need to know how far back to look for C
) but you can still do an ancestry test (see the --is-ancestor
option to git merge-base
).