You have snipped so much that it is not possible to tell whether the commit in question is a merge commit. I suspect it is: that someone ran git merge
, perhaps by running git pull
(git pull
runs git fetch
and after the fetch is done, runs either git merge
or git rebase
, defaulting to the wrong one—I advise new users to avoid git pull
as its convenience turns out to be more of a trap than a help).
Background
The default (single) parent of a new commit is the current commit. Branch names are not relevant to this part of the process; what matters is the current commit.
When you make a new ordinary commit with git commit
, this is what normally happens, in this order:
- Git checks that the index (also called the staging area) has different content from the
HEAD
commit. (This is to prevent you from accidentally making trivial commits with no difference from the previous commit.)
- Git collects a commit message.
- Git turns the index into a snapshot.
- Git writes a new commit with:
- the message you provided as the log message,
- the user making the commit as both author and committer,
- the current time and date as the time-stamp, and
- the current commit ID (from
git rev-parse HEAD
) as the parent commit ID.
- Finally, Git takes the new commit ID generated in step 4 and writes that to the current branch name.
Note that except for step 5—the part that updates the current branch, so that the new commit as now at the branch's tip—the current branch's name does not enter into the picture here. (Of course the last step is important, in the end.)
There are various ways to modify the above steps, e.g., git commit --amend
sets the new commit's parent(s) the same as the current commit's parent(s), and doing a regular merge that is either conflicted, or stopped-before-committing (via --no-commit
), leaves behind traces that make the next commit record multiple parents. And of course a regular (successful) merge writes a commit with at least two parents, i.e., a merge commit.
Besides the above, two of the bullet-point items—author and committer, and the corresponding time-stamps—can be set to anything the person making the commit likes, either through configuration items (user.name
and user.email
) or through environment variables (GIT_COMMITTER_NAME
, GIT_AUTHOR_DATE
, and so on). The git commit
command even has flags --author=
and --date=
to override them.
So, there are multiple ways for these things to happen, and branch names are the wrong place to focus. What matters is not so much the names, as the commit IDs. Of course, the new commit—whether it is an ordinary commit from git commit
, or a merge commit from git merge
—does go on the current branch, so here the name does matter.
Merge commits
I mentioned merge commits several times above. A merge commit is simply a commit with two or more parents. More than two is unusual—it's called an octopus merge, and mostly they are made by mistake when people run git pull
, because git pull
doesn't do what people expect it to do.
The first parent of any merge commit is handled the same way as the only parent of any ordinary, non-merge commit: it's the commit that was current when you made the merge. The second parent, and any additional parents, are all the other commits you passed as arguments to git merge
.
Note that if you mistakenly do:
git pull origin branch1 branch2
Git translates this into, in effect:1
git fetch origin &&
git merge origin/branch1 origin/branch2 # DANGER
This second command, merging two branches into the current branch, is what makes an octopus merge. Chances are you did not want that.
(Recovering from this is ... annoying and difficult, once it's pushed back. Until then, it's not too bad: as long as you keep the mistake in your own Git repository, you can back it out without consequences to anyone else, using git reset
.)
1There are some minor technical differences in the git merge
step, since it's actually done by commit IDs recorded in FETCH_HEAD
and with an explicit merge commit message that uses, e.g., "branch 'branch1' of remote 'origin'" as its string, rather than "remote-tracking branch 'origin/branch1'" as its string. But the idea is the same.