Git - Programatically determine if local commits have not been pushed
Asked Answered
H

4

5

I've seen lots of posts/answers on how to display all of the local commits for all local branches that have not been commited.

I have a narrow use case, and have not found an answer.

I need to determine from within a bash script, if my CURRENT branch has commits that have not been pushed upstream to the same branch. A count would be fine, but I really just need to know if a push has not yet been done. I don't care about any branches except the current branch, and in this case I've already checked to see if the branch is local (i.e. has not yet set upstream origin).

Mainly, I don't want the commits printed out. I just want to know that the number of unpushed commits is > 0.

Humanitarianism answered 8/3, 2021 at 23:46 Comment(0)
X
9

The upstream of the current branch is @{u}. @ is a synonym for HEAD.

@..@{u} selects the commits which are upstream, but not local. If there are any you are behind. We can count them with git rev-list.

# Move 4 commits behind upstream.
$ git reset --hard @{u}^^^

$ git rev-list @..@{u} --count
4

@{u}..@ does the opposite. It selects commits which are local but not upstream.

# Move to upstream
$ git reset --hard @{u}

# Add a commit
$ git commit --allow-empty -m 'test'
[main 6dcf66bda1] test

$ git rev-list @{u}..@ --count
1

And if both are 0 you are up to date.

Note: this will only be "up to date" as of your last fetch. Whether you want to combine this with a fetch is up to you, but one should get used to the fact that Git does not regularly talk to the network.

(I've borrowed from ElpieKay's answer).

See gitrevisions for more about @, .. and many ways to select revisions.

Xever answered 9/3, 2021 at 0:1 Comment(6)
From the git book §3.5 "Git moves [remote-tracking branches] for you whenever you do any network communication". So make sure you made a recent network-based command like fetch.Ridglee
I can see how this gives me a commit tag for local and remote, but if they don't match, it doesn't tell me if I am ahead or behind.Humanitarianism
@Humanitarianism If they're different, if git branch --contains <current>@{upstream} has <current> you're behind. Otherwise ahead. (On a phone)Xever
(sorry I accepted the wrong answer above by mistake, fixed now)Humanitarianism
Yes, exactly. I might also want to know if local needs to do a pull. So I can do both tests.Humanitarianism
@Humanitarianism I borrowed from ElpieKay's answer and streamliined it.Xever
S
0

Suppose the branch is foo.

git fetch origin foo
git rev-list FETCH_HEAD..foo --count

The 1st command gets the latest head of the foo in the remote repository and stores its commit sha1 in FETCH_HEAD.

git rev-list returns a number. If it's 0, all commits of the foo in the local repository have been included in the foo branch in the remote repository. If it's larger than 0, there are this number of commits not included in the remote foo yet.

Being included is different from being pushed if the procedure involves a pending change like a pull request or a merge request. The commands can determine if the local branch's commits have been merged to(included in) its remote counterpart.

Sodom answered 9/3, 2021 at 2:53 Comment(6)
I think this is what I am looking for. Question: Can the returned count be negative, and if so, does this mean that the local repo is behind (n commits) from the remote?Humanitarianism
Or perhaps I do the same command reversing the arguments to foo..FETCH_HEAD to determine if the local repo is behind?Humanitarianism
@Humanitarianism It can't be negative. foo..FETCH_HEAD refers to the commits reachable from FETCH_HEAD and not reachable from foo. If it's larger than 0, it means in the remote branch there are one or more commits you have not merged to the local foo yet. It's completely different from "if local commits have not been pushed".Sodom
Does this assume that the remote upstream for foo is also named foo?Xever
Using git rev-list --count is much better than what I was doing. I combined our answers.Xever
@Xever that's okay.Sodom
C
0

I was looking to detect any local changes, including unpushed changes. This post gave me part of the answer: https://unix.stackexchange.com/questions/155046/determine-if-git-working-directory-is-clean-from-a-script/155077#155077

Then I saw that you can add -b i.e.

git status --porcelain -b

which with changes committed but not pushed gives me:

## mybranch...origin/mybranch [ahead 1]

This should be more reliable than grepping git status as I simply need the output to be empty.

Correction: once pushed, you still get the ## mybranch...origin/mybranch output which I can live with.

Cyclic answered 13/10 at 17:28 Comment(0)
D
-1

You're looking for git status. It will give you output like:

On branch main
Your branch is ahead of 'origin/main' by 1 commit.
(use "git push" to publish your local commits)

nothing to commit, working tree clean

And you can grep for this with:

git status | grep -E "Your branch is ahead of '.*' by ([0-9]*) commit."
Deannadeanne answered 8/3, 2021 at 23:58 Comment(1)
While that's fine for humans, the format of git status output not stable.Xever

© 2022 - 2024 — McMap. All rights reserved.