1

Normally, when I "need" a branch name in the Git command line, I'll either retype the name (using auto-complete when available), or select+right-click with the mouse. This feels too slow and repetitive.

  • What is a 'lazy' way to refer to the expanded NAME of the current branch in git commands?

  • Is there built-in and consistent support for such, or does it require shell expansion?

Here are two example use-cases of when having the NAME is handy. I'm not looking for a git alias, unless such can be generalized to all commands. Even if the answer is "no", hints on how to improve such workflows are appreciated as secondary information - just ensure to answer the questions above first.

Example #1

Rebase onto a different commit.

git checkout -b mybranch                    # on 'mybranch'
touch x; git commit -mx -- x                # on 'mybranch'

# Is is possible to avoid 'mybranch' here?
# Using HEAD will switch from 'mybranch' to a commit.
git rebase --onto otherbranch mybranch^ mybranch

Example #2

Comparing the local and remote branch, assuming standard same-names.

# Standard way..
git diff origin/mybranch

# I often find myself wanting to do something like..
git diff origin/NAME
git log -1 origin/NAME
user2864740
  • 54,112
  • 10
  • 112
  • 187
  • Probably duplicate-ish of https://stackoverflow.com/questions/6245570/how-to-get-the-current-branch-name-in-git .. which indicates "no". However, answers there might be outdated. – user2864740 May 22 '20 at 17:53

2 Answers2

3

For completeness, I'll edit this to add: For the specific case of the upstream of the current branch (origin/NAME in your git log example), TTT's answer using @{u} is the way to go. That is, if you're on your branch xyz, and its upstream is origin/xyz, you can just run:

git diff @{u}

or:

git log @{u}..

(note: some shells may require that you quote the curly brackets).

Note that if the upstream of your current branch xyz is origin/abc, xyz@{u} or @{u} means origin/abc, not origin/xyz! This is usually what you want; using origin/$(git command) will as I note below will get you the other answer, i.e., origin/xyz instead of origin/abc for this case.

The upstream of a (local) branch can be another (local) branch: if the upstream of your current brnch xyz is your own branch ghi, @{u} is just a way of writing ghi without having to think about it. And of course, your current branch must have an upstream set.

Each of your branch names can have at most one upstream: you either have one, or you have none. To set a new upstream, use git branch --set-upstream-to=upstream. To remove the upstream entirely (though there's rarely any reason for that), use git branch --unset-upstream. Both commands can take a branch name as well; both operate, by default, on the current branch.

The general case

What is a 'lazy' way to refer to the expanded NAME of the current branch in git commands?

There is a way, but it's terrible: use the word HEAD.

The reason it is terrible is that it works for some commands and not for others:

Is there built-in and consistent support for such, or does it require shell expansion?

To make it work for all commands, you need shell expansion.

Essentially, whenever Git looks up the name HEAD, it can do that with one of two questions:

  1. What branch name does HEAD refer to?

    These four commands all do mostly the same job, in slightly different ways:1

    git symbolic-ref HEAD
    git symbolic-ref --short HEAD
    git rev-parse --symbolic-full-name HEAD
    git rev-parse --abbrev-ref HEAD
    

    Other Git commands will sometimes internally use one of these commands, or an equivalent, to find the branch name.

  2. What commit (hash ID) does HEAD refer to?

    The command:

    git rev-parse HEAD
    

    asks and answers this question.

    Other Git commands sometimes internally do this as well.

As a rather interesting example, the git push command asks both questions:

git push -u origin HEAD

will look up the name, as if by git symbolic-ref HEAD, and then also look up the hash ID, as if by git rev-parse HEAD, and will run the equivalent of the shell-expanded command:

git push -u origin $(git rev-parse HEAD):$(git symbolic-ref HEAD)

If you need to control which expansion occurs, explicitly, you'll have to use your own $(git ...) command in the right place in your shell command.


1The git symbolic-ref variants produce the full or abbreviated branch name but fail when you are in detached-HEAD mode. The git rev-parse variants produce the full or abbreviated branch name but simply print HEAD when you are in detached-HEAD mode.

torek
  • 330,127
  • 43
  • 437
  • 552
  • I took a different approach with my answer because I felt the goal was more about less typing. But I just learned quite a bit from your answer, so thank you. +1 – TTT May 22 '20 at 20:36
  • 1
    @TTT: that's a good point: I added a lot more including a link to your own answer. – torek May 22 '20 at 21:06
2

These two shorthands almost get you what you want:

@    # this is the same as writing HEAD
@{u} # this is the same writing origin/{your-branch-name}

With this you can achieve Example 2 with simply:

git diff @{u}
git log -1 @{u}

Example 1 is tougher, because as you point out, HEAD will detach during rebase. But it isn't really that big of a deal if you detach, because you can easily recover:

git rebase --onto otherbranch @^ @ # detached on a new commit
git checkout -B mybranch # reset mybranch to point to the current commit

The nice thing about the @ symbol is it's easy to type in conjunction with the ^ and ~ characters. For example, if you have 5 commits you want to move onto another branch instead of just 1, @~5 is nearly as easy to type as @^.

TTT
  • 7,472
  • 5
  • 41
  • 50