Home > database >  `git checkout refs merge` not merging with HEAD of `main`
`git checkout refs merge` not merging with HEAD of `main`

Time:02-16

I have a problem with GIT, where running: git checkout refs/remotes/pull/534/merge

on public repositories: https://github.com/raycast/extensions

According to docs it should simulate a merge which will happen when you merge the PR - I was expecting this to do simulate a merge with HEAD of main, but instead if merges with a weird commit back in history.

Am I missing something here ? It's a root cause for some other problems I have like detecting changed files by PR.

enter image description here

CodePudding user response:

According to docs it should simulate a merge which will happen when you merge the PR ...

It's not a simulated merge. Instead, GitHub have actually done a merge.

I was expecting this to do simulate a merge with HEAD of main, but instead if merges with a weird commit back in history.

Merges, in Git (and therefore also in GitHub1), are not actually between branches. That's because in an important sense, branches don't even exist in Git.2 Merge commits definitely do exist, so if we bypass this confusing "what exactly is a branch anyway" question and just dive directly into merge commits, we get something we can talk about easily:

  • A merge commit is a lot like a regular commit. A regular commit has a snapshot—a full copy of every file as it appeared at the time you (or whoever) made the commit—and metadata to say who made the commit, when, and so on.

  • The metadata of a normal commit has a single parent commit hash ID stored in it. This links commits together, into a backwards-looking chain. This chain of commits is the history in a Git repository: the commits are the history; history is nothing but a series of commits.

  • The metadata of a merge commit is what makes the commit a merge commit: it lists two parents,3 and those two parent commits are both the history of that commit. One of the two parent commits—the first one—is the commit from which the merge commit was made. The other of the two parents, which is therefore the second one, is the commit (not "the branch", since that's ill-defined) that was merged in.

The commit that GitHub have used as the first parent is the commit that was the tip of the "base branch" (a GitHub-specific term) at the time you (or whoever) posted your (or their) Pull Request. The commit that GitHub will have used as the second parent is the commit at the tip of your (or whoever's) PR. Since then, it's possible for others to have added new commits to that "base branch". The test merge was against the old branch-tip commit. Any commit, once made, can never be changed, so this test merge is the way it is forever. Your future actual merge, if and when you do it, may be different: a different commit, with a different hash ID and a different parents. The first parent of the future actual merge will be the tip of the branch at the time GitHub do the final merge; the second parent of the future actual merge will be the tip of your pull request, which you can update between now and then.

Whether and when you should use this test merge, or make your own merge, is a question that only you can answer. You're in control here: you choose. You can use refs/pull/534/head to refer to the tip commit of the PR itself (parent #2 in the test merge), and—if it exists—you can use refs/pull/534/merge to refer to the GitHub test merge. If the GitHub test had merge conflicts, refs/pull/534/merge won't exist, unless and until someone uses the GitHub interface to resolve the merge conflicts.


1GitHub do not actually use Git directly. Instead, they use a sort of augmented subset of Git. However, the merge results are the same, provided the merge goes without conflicts. When the merge has conflicts, GitHub originally couldn't do the merge at all; they now offer, through their augmentation, a side way of doing conflict resolution that's not part of Git. This non-Git GitHub-specific conflict resolution method is only available on GitHub, since they (GitHub) created it themselves.

2Of course, in other senses, branches do exist. The trick is defining exactly what we mean by branch. See also this SO question, which gets into the various underlying things that do exist, what we call them, and how people confuse them with each other. See also this Wikipedia article, which touches on the metaphysics of naming.

3So-called octopus merges have more than two parents. They don't really do anything you can't do with ordinary merges, though, so we'll just skip right over them for this answer.

  • Related