How to show which commits Git will push or merge

To show which commits Git will push or merge, these are the aliases you need in your Git configuration file (e.g. C:\cygwin\home\<user>\.gitconfig or <project>/.git/config). The explanation is below.

[alias]
    # -M                 Detect and report renames for each commit.
    # --name-status      Show only names and status of changed files.
    # --abbrev-commit    Instead of showing the full 40-byte hexadecimal commit object name, show only a partial prefix.
    l = log -M --name-status --abbrev-commit

    # --oneline          This is a shorthand for "--pretty=oneline --abbrev-commit" used together.
    l1 = log --oneline

    # log commits-to-push
    lctp  = "!LOCAL_BRANCH=$(git branch | grep ^* | gawk -F' ' '{print $NF}'); \
            REMOTE_SERVER=$(git config --get branch.$LOCAL_BRANCH.remote); \
            REMOTE_BRANCH=$(git config --get branch.$LOCAL_BRANCH.merge | gawk -F'/' '{print $NF}'); \
            COMMAND=\"git l $REMOTE_SERVER/$REMOTE_BRANCH..HEAD\"; \
            echo $COMMAND; \
            $COMMAND"
    lctp1 = "!LOCAL_BRANCH=$(git branch | grep ^* | gawk -F' ' '{print $NF}'); \
            REMOTE_SERVER=$(git config --get branch.$LOCAL_BRANCH.remote); \
            REMOTE_BRANCH=$(git config --get branch.$LOCAL_BRANCH.merge | gawk -F'/' '{print $NF}'); \
            COMMAND=\"git l1 $REMOTE_SERVER/$REMOTE_BRANCH..HEAD\"; \
            echo $COMMAND; \
            $COMMAND"

    # log commits-to-merge
    # do not forget to execute "git fetch" first
    lctm  = "!LOCAL_BRANCH=$(git branch | grep ^* | gawk -F' ' '{print $NF}'); \
            REMOTE_SERVER=$(git config --get branch.$LOCAL_BRANCH.remote); \
            REMOTE_BRANCH=$(git config --get branch.$LOCAL_BRANCH.merge | gawk -F'/' '{print $NF}'); \
            COMMAND=\"git l HEAD..$REMOTE_SERVER/$REMOTE_BRANCH\"; \
            echo $COMMAND; \
            $COMMAND"
    lctm1 = "!LOCAL_BRANCH=$(git branch | grep ^* | gawk -F' ' '{print $NF}'); \
            REMOTE_SERVER=$(git config --get branch.$LOCAL_BRANCH.remote); \
            REMOTE_BRANCH=$(git config --get branch.$LOCAL_BRANCH.merge | gawk -F'/' '{print $NF}'); \
            COMMAND=\"git l1 HEAD..$REMOTE_SERVER/$REMOTE_BRANCH\"; \
            echo $COMMAND; \
            $COMMAND"


According to the very good book Pro Git, chapter 6-1, the following command shows you any commits in your current branch (HEAD) that are not in the master branch on your origin remote:

$ git log origin/master..HEAD

If you run a git push and your current branch is tracking origin/master, the commits listed by git log origin/master..HEAD are the commits that will be transferred to the server.

If you are on a branch which is tracking origin/issue1, you can use:

$ git log origin/issue1..HEAD

Still according to Pro Git, if you want to keep the current branch up to date and preview what you are about to merge in, you can reverse the two sides of the double dot syntax:

$ git log HEAD..origin/master

$ git log HEAD..origin/issue1

Of course, for this to work you must first execute $ git fetch origin.

You can also leave off one side of the syntax to have Git assume HEAD:

$ git log origin/master..

$ git log ..origin/issue1

I have some issues with the above commands:
– I prefer to add the options -M --name-status --abbrev-commit to git log.
– When the list of commits-to-push is long, I prefer git log --oneline.
– I don’t like to remember and type the name of the tracked branch. This should be automatic.

Always adding options to a command is easy with an alias in your .gitconfig file (e.g. C:\cygwin\home\<user>\.gitconfig):

[alias]
    # -M                 Detect and report renames for each commit.
    # --name-status      Show only names and status of changed files.
    # --abbrev-commit    Instead of showing the full 40-byte hexadecimal commit object name, show only a partial prefix.
    l = log -M --name-status --abbrev-commit

    # --oneline          This is a shorthand for "--pretty=oneline --abbrev-commit" used together.
    l1 = log --oneline

You can also have an alias to list the commits you are about to push or merge in:

[alias]
    # log commits-to-push
    lctp = "!git l origin/master..HEAD"

    # log commits-to-merge
    # do not forget to execute "git fetch" first
    lctm = "!git l HEAD..origin/master"

An alias which starts with a ! character runs an external command. This way you can reuse the “l” alias.

This is somewhat awkward if you use more than just the master branch. You would need a new alias for every tracking branch, e.g.:

[alias]
    # log commits-to-push
    lctp_issue1 = "!git l origin/issue1..HEAD"

    # log commits-to-merge
    # do not forget to execute "git fetch" first
    lctm_issue1 = "!git l HEAD..origin/issue1"

We need something more dynamic.

Your git repository configuration file (<project>/.git/config) contains the information of your tracking branches.

[branch "master"]
    remote = origin
    merge = refs/heads/master
[branch "my-issue1"]
    remote = origin
    merge = refs/heads/issue1

We need to combine the “remote” value (here: origin) with the last part of the “merge” value (here: master and issue1) of the correct branch.

$ git config --get branch.master.remote
origin

$ git config --get branch.master.merge
refs/heads/master

$ git config --get branch.my-issue1.remote
origin

$ git config --get branch.my-issue1.merge
refs/heads/issue1

To get the last part of the “merge” value, we can use (g)awk:

$ git config --get branch.master.merge | gawk -F'/' '{print $NF}'
master

$ git config --get branch.my-issue1.merge | gawk -F'/' '{print $NF}'
issue1

Now we need to get the correct current branch name to replace the values “master” and “my-issue1” in the configuration keys “branch.master.remote” and “branch.my-issue1.merge“.

git branch lists existing branches and the current branch is highlighted with an asterisk.
grep ^* gets the line starting with an asterisk.
gawk -F' ' '{print $NF}' splits a line into fields using a space as the field separator and prints the last field.

$ git checkout master

$ git branch
* master
  my-issue1

$ git branch | grep ^*
* master

$ git branch | grep ^* | gawk -F' ' '{print $NF}'
master

$ git checkout my-issue1

$ git branch | grep ^* | gawk -F' ' '{print $NF}'
my-issue1

Putting everything together, you get (without character escaping):

[alias]
    # log commits-to-push
    lctp = "!LOCAL_BRANCH=$(git branch | grep ^* | gawk -F' ' '{print $NF}');
            REMOTE_SERVER=$(git config --get branch.$LOCAL_BRANCH.remote);
            REMOTE_BRANCH=$(git config --get branch.$LOCAL_BRANCH.merge | gawk -F'/' '{print $NF}');
            COMMAND="git l $REMOTE_SERVER/$REMOTE_BRANCH..HEAD";
            echo $COMMAND;
            $COMMAND"

    # log commits-to-merge
    # do not forget to execute "git fetch" first
    lctm = "!LOCAL_BRANCH=$(git branch | grep ^* | gawk -F' ' '{print $NF}');
            REMOTE_SERVER=$(git config --get branch.$LOCAL_BRANCH.remote);
            REMOTE_BRANCH=$(git config --get branch.$LOCAL_BRANCH.merge | gawk -F'/' '{print $NF}');
            COMMAND="git l HEAD..$REMOTE_SERVER/$REMOTE_BRANCH";
            echo $COMMAND;
            $COMMAND"

$LOCAL_BRANCH becomes master or my-issue1;
$REMOTE_SERVER becomes origin;
$REMOTE_BRANCH becomes master or issue1;
git l $REMOTE_SERVER/$REMOTE_BRANCH..HEAD becomes
    git l origin/master..HEAD or
    git l origin/issue1..HEAD.

You can use the aliases like this:

$ git commit -m "..."

$ git lctp

...

$ git fetch

$ git lctm

Comments are closed.