2

When I run

git branch --no-merged

on this repo, the first listed branch is one called dcxl.

But when I view the branch in GitHub, what I see is just

This branch is 1291 commits behind master.

And when I go to GitHub’s pull request interface, I get:

There isn’t anything to compare.

master is up to date with all commits from dcxl.

According to this answer, the way to see commits ahead/behind is

git rev-list --left-right --count [BRANCH]...master

When I run this, I get:

$ git rev-list --left-right --count master...dcxl
426     1717

I read this as “Branch dcxl is 426 commits ahead, 1717 commits behind master.”

Now, 1717 - 426 = 1291, so there’s clearly some relationship between the git rev-list output and what GitHub’s telling me, but GitHub seems to be somehow identifying those 426 “ahead” commits with 426 of the 1717 “behind” commits in a way that git rev-list doesn’t.

From some answer, I’m not sure which, I found the --no-merges option, and tried that, in case merge commits were the difference:

$ git rev-list --left-right --count --no-merges dcxl...master
396     1610

Still different.

I have other repos where the git rev-list output exactly matches GitHub’s. And this particular repo, including branches, was migrated from Mercurial, so there could be all kinds of shenanigans in the history. But I'm pretty sure GitHub is right, here, and there's nothing in this branch that needs merging.

But how can I check that from the command line? Why are the numbers I'm getting different, and what commands / options would I need to get the same numbers GitHub is giving me?

David Moles
  • 48,006
  • 27
  • 136
  • 235
  • In a comment below the linked answer, someone recommended runing `git rev-list --left-right --count origin/master...@ | cut -f1` to get _behinds_, did you try that ? what does it output ? – scharette Jul 12 '18 at 19:39

1 Answers1

2

I'm not entirely sure why you are getting the results you are getting, but it clearly has something to do with the fact that you have your own branches. I just cloned the repository myself, and this is what I get:

$ git clone git://github.com/CDLUC3/mrt-dashboard
Cloning into 'mrt-dashboard'...
remote: Counting objects: 23264, done.
remote: Compressing objects: 100% (142/142), done.
remote: Total 23264 (delta 103), reused 127 (delta 56), pack-reused 23066
Receiving objects: 100% (23264/23264), 121.78 MiB | 3.51 MiB/s, done.
Resolving deltas: 100% (9203/9203), done.
$ cd mrt-dashboard/
$ git rev-list --left-right --count origin/dcxl...origin/master
0       1291

Note that I do not have a branch named dcxl. I do have (my own) master, as my git clone ended by doing a git checkout master which created my master using origin/master, so that they both point to the same commit:

$ git rev-parse master origin/master
4c8616fe9b6eb3d3ea113c07ab307cfb78247c5e
4c8616fe9b6eb3d3ea113c07ab307cfb78247c5e

You obviously must have your own dcxl that points to some commit other than the one to which origin/dcxl points:

$ git rev-parse origin/dcxl
f866dd35916bc7b8154441dce53c76d20b166c37

There are many ways your own repository may be out of sync with another

Remember, every name is simply a human-readable name for some Git hash ID. Branch names have a few special features, including these two:

  • they only ever point to commit objects, and
  • Git knows that it is OK to "move" a branch name using a fast-forward operation.

Remote-tracking names like origin/dcxl share these features with branch names.

What the latter means is that if you ask Git to update a branch name whose current hash is Hold so that its new hash is Hnew, Git will check whether Hold is an ancestor of Hnew. If so, that update is a fast-forward. If not, the requested update is a non-fast-forward: it may still be allowed (depending on how you asked for it), but making the change might lose commits.

If you are on some branch and run git merge commit-specifier, for any valid commit specifier—see the gitrevisions documentation for all the ways to spell a commit—Git will check to see if the change can be done as a fast-forward. If so, Git will update your index and work-tree and do the fast-forward on the branch name. This is not a merge at all! But if the operation cannot be done as a fast-forward, Git will go through the process of merging, and if that succeeds, make a merge commit to remember both the previously-current commit and the commit that you just merged. This is a true merge.

Your own branch names like dcxl may therefore not correspond to origin/name remote-tracking names, either because you have not done a fast-forward, or because you did a merge that was not a fast-forward. Or you may even have a combination of these: some merge(s) and/or fast-forwards done, but your branch name remains behind another.

Alternatively, or in addition, the other Git repository may have had its branch names rudely shoved about in non-fast-forward fashion. In this case you may have commits on your local branch that are no longer reachable from the current value of the remote-tracking name.

(And, of course, it's important to run git fetch first. This updates your own remote-tracking names to remember what the current values of the branch names are, as stored in the Git repository on GitHub. You will see, at this time, which remote-tracking names are being fast-forwarded, and which are being force-updated instead. This point is a bit subtle, even though git fetch actually displays it three ways (!).)

torek
  • 448,244
  • 59
  • 642
  • 775