3

I've been working on a local branch for too long without pushing upstream and losing count of how many commits I have locally.

I am now ready to push my commits, but I need the exact number of my commits in order to squash them with git rebase -i HEAD~4 (4 is just an example).

How do I find that number?

I've tried git rev-list --count my-local-branch, but it shows an insanely high number which is not what I want (I have roughly 6 commits).

Also git log --graph --all --decorate --oneline didn't give what I wanted.

I think the problem is that my-local-branch isn't a tracked remote branch.

So I've tried to set that up manually with git branch -u upstream/my-local-branch, but that returns error: the requested upstream branch 'upstream/my-local-branch' does not exist.

To fix that, I could of course just push my branch upstream, but that would defeat my original intent of squashing my commits.

So I feel stuck. Anyone able to advise?

U r s u s
  • 6,680
  • 12
  • 50
  • 88
  • If you only have a handful of commits (say less than 10 or so), then I would just use `git log` and count how many commits you want to include. If you have dozens of commits (bad Git etiquette), then there is probably a way to find the most recent commit which you did _not_ make, and you could count from there assuming you made all commits happening after that point. – Tim Biegeleisen Jun 06 '16 at 16:04
  • Related: http://stackoverflow.com/questions/31982954/how-can-i-check-whether-two-branches-are-even/31985138#31985138 – jub0bs Jun 06 '16 at 17:20
  • git cherry -v origin/master | wc -l (but I'm not sure, that it's most easy way) – Yura Shinkarev Mar 24 '17 at 09:15
  • Answered here https://stackoverflow.com/a/27940027/80428 – Jay Wick Sep 04 '17 at 06:56

2 Answers2

8

I think your fundamental problem here may lie in the way you are viewing the "branchness of commits" (to make up a phrase). Or, it may just be that you're limiting your concept of "upstream".

Let me illustrate with this:

...--o--o--o--o   <-- master, origin/master

This is a drawing of at least four commits on branch master, with master in sync with origin/master.

...--o--o--o--o   <-- origin/master
               \
                o   <-- master

This is the same repository after adding one commit on master that is not on origin/master, so that branch master is "ahead 1", as git status would put it.

Now let's put master back where it was, but keep that new commit, having added it on newbr which we made with git checkout -b newbr instead of just adding it on master:

...--o--o--o--o   <-- master, origin/master
               \
                o   <-- newbr

You want Git to be able to tell you that newbr is "1 ahead" of something. The problem lies in defining the "something".

Here's the fundamental trick: all those commits that are on master and also on origin/master, are also on newbr. Commits can be on many branches at once, including multiple local and remote-tracking branches.

The way git status calculates the "ahead" and "behind" numbers is to use git rev-list --count, and use the "upstream" setting to exclude commits that are on both the current branch and the upstream. So in our second illustration, when master was "ahead 1", both master and origin/master had at least the original four commits, but master had one more than origin/master.

(What git status is doing is git rev-list --count origin/master..master, i.e., count everything that remains after selecting all commits on master minus all commits on origin/master. Of course instead of a literal master, it uses your current branch, and instead of a literal origin/master, it uses your current branch's upstream.)

What this means is that, to get git status to report things like this, we must choose—at least temporarily—some branch, perhaps even a local branch rather than a remote-tracking branch, to set as the "upstream" for newbr.

In this particular drawing, both master and origin/master are suitable values for the upstream in git branch --set-upstream-to. Your repository will differ somewhat, but there will be some name for the commit you would like your Git to start excluding. (Even if there isn't, you can simply make a new branch for the exclusion point. But there's almost always one out there already.)

Use git log --graph --oneline --decorate --all to get Git to draw a text version of these graphs (vertically, instead of horizontally) with labels showing which branch and tag names point to which commits. This usually makes it visually obvious which branch name(s) are suitable for the upstream name.

Remember, local branches work fine as an upstream, as long as you remember to re-set the upstream once you have the appropriate remote-tracking branch.

(Incidentally, if you don't like using a local branch as your upstream for your new branch, you can create the branch on your remote, pointing to the commit your branch "starts from". For instance, in the example illustration above, you might want origin/newbr to point to the same commit as master and origin/master. So you can use:

git push origin master:newbr

to create newbr on remote origin, pointing to the same commit your local master points to. Once you've done that, origin/newbr now exists, so now you can set it as the upstream for newbr.

If there's a more specific commit, identifiable only by its hash ID, you can even use that:

git push origin a123456:refs/heads/newbr

When identifying a commit by its raw SHA-1 hash, you should spell out full reference names like this, since Git can no longer use your local name to figure out whether you intended a branch or a tag.)

torek
  • 448,244
  • 59
  • 642
  • 775
2

git status will tell you how many commits behind the tracked remote branch that you are.

you were correct to set the tracking on the remote with git branch -u upstream/my-local-branch but you need to specify the remote branch name if it's different, and it must exist.

git checkout master
git branch -u upstream/remote-branch-name
Branch master set up to track remote branch remote-branch-name from upstream.

Now you should receive the count with git status

git status 
On branch master
Your branch is ahead of 'upstream/remote-branch-name' by 1 commit.
  (use "git push" to publish your local commits)
nothing to commit, working directory clean
Jeff Puckett
  • 37,464
  • 17
  • 118
  • 167