1049

I know I can do git branch --all, and that shows me both local and remote branches, but it's not that useful in showing me the relationships between them.

How do I list branches in a way that shows which local branch is tracking which remote?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
joachim
  • 28,554
  • 13
  • 41
  • 44

11 Answers11

1479

Very much a porcelain command, not good if you want this for scripting:

git branch -vv   # doubly verbose!

Note that with git 1.8.3, that upstream branch is displayed in blue (see "What is this branch tracking (if anything) in git?")


If you want clean output, see Carl Suster's answer - it uses a porcelain command that I don't believe existed at the time I originally wrote this answer, so it's a bit more concise and works with branches configured for rebase, not just merge.

AncientSwordRage
  • 7,086
  • 19
  • 90
  • 173
Cascabel
  • 479,068
  • 72
  • 370
  • 318
  • 3
    FWIW I was confused because -v and -vv show such similar output. The tracked branch is shown in square brackets after the hash and before the most recent commit (on my default OSX homebrew install). – jerclarke Oct 24 '12 at 17:31
  • 1
    the second option doesn't seem to work for branches within namespaces. e.g. `bugs/bug1234`. To fix this, I removed the: `refs/heads/*` part from the command. – Jake Berger Feb 06 '13 at 02:28
  • @jberger If you don't put that there, you're going to get tags, remote branches, and everything else, not just branches. You probably want to pipe through `grep '^refs/heads'` if you want to include branches with slashes in their names. – Cascabel Feb 06 '13 at 02:30
  • @Jefromi actually, I just checked and just removing the asterisk worked. so: `refs/heads/` – Jake Berger Feb 06 '13 at 04:34
  • This is the correct solution. If you don't see the remote branches, that means you don't have any set to track remote branches. – wisbucky Oct 03 '13 at 05:45
  • Thanks very much for this! Worked like a charm. It also highlights the branch you are on so it's very obvious. – RHE Aug 18 '14 at 08:49
  • 6
    All this does for me is print out the last commit hash and comment for each branch. – capybaralet Feb 26 '15 at 19:35
  • The answer arcresu gives below is better as it's a single git command per branch, whereas this solution uses two git commands per branch with additional munging. – markshep Aug 05 '15 at 17:45
  • @markshep Way more importantly, the porcelain commands should work with both rebase and merge upstream branches. (I don't think optimizing number of git commands is terribly important in this kind of thing unless you have a repository with thousands of branches, or need to do this on hundreds of repos. Worry about functionality first.) – Cascabel Aug 05 '15 at 18:01
  • 1
    get current branch remote: ` git branch -vv | grep '*' | awk -F'[\\[\\]]' '{print $2}' ` – qxo Jun 23 '16 at 08:26
  • 2
    Is the `git branch -vv` still working on git 2.16? When I run that command it does only list the branchname followed by a short SHA1 and its last commit's comment – Mattia Righetti May 04 '18 at 04:16
  • At least since git 2.5.1, you can use a less-porcelained command : `git for-each-ref --format='%(refname:short) : %(upstream:short)' refs/heads/*` – Mat M Aug 08 '18 at 06:26
  • 1
    How can I make `-vv` the default option using `.gitconfig`? – Luke Davis Oct 31 '18 at 05:27
  • @qxo Simply add `--list $currentBranchName`, e.g.: `git branch -vv --list master` – Murmel Nov 21 '18 at 09:47
  • I have a local branch that is `configured for 'git push'` _and_ whose remote counterpart is `tracked` according to `git remote show origin`. Indeed, if I push from it (with no arguments), the local branch is pushed to the remote. But `git branch -vv` does not list a remote branch for my local one. So, this answer seems wrong. – Carsten Führmann Dec 14 '18 at 09:58
  • 1
    Does not work! Output is the same as `git branch -v` – Green Apr 10 '19 at 09:06
  • @LukeDavis This doesn't do exactly what you want, but here it is anyway: `alias br = branch -vv`. I like having short-name aliases for common commands, and I know that I will never remember `-vv`, so it's a natural fit for the alias. – Andrew Keeton Nov 07 '19 at 16:24
  • `git branch -vv` isn't remotely useful as it continues to list remotes after they have been deleted. – Neutrino May 05 '21 at 10:00
350

git remote show origin

Replace 'origin' with whatever the name of your remote is.

kubi
  • 48,104
  • 19
  • 94
  • 118
  • 19
    Even though this porcelain command kinda works for a human (not so much for a script, as it would have to parse the porcelain output), what I don't like about this approach is that `git remote show` command actually connects to the remote repo... and hence it fails if you happen to be off-line or unable to connect to the repo for whatever reason... – pvandenberk Sep 08 '13 at 12:37
  • 28
    @pvandenberk You can use `git remote show -n origin` to get some information even when offline. From the [git remote documentation](http://git-scm.com/docs/git-remote): "With -n option, the remote heads are not queried first with git ls-remote ; cached information is used instead." – Cerran Mar 05 '14 at 12:21
  • 8
    One odd thing about this command: it lists remote branches as "tracked", even if there's no local branch configured for pull/push. I always find this confusing. I'm actually not clear on what "tracked" is supposed to mean in this output. [The git docs on the subject](http://git-scm.com/book/en/v2/Git-Branching-Remote-Branches#Tracking-Branches) make it sound like a remote branch is "tracked" only when it's linked/bound to a local branch for push/pull... – Hawkeye Parker Feb 07 '15 at 00:44
  • The problem is that I need to call this for all remote names until I see what I am actually looking for. – jolvi Jan 20 '16 at 10:15
  • 2
    @jolvi You could run `git remote show | xargs git remote show -n` to view combined tracking info for all remotes. – Synoli May 20 '16 at 08:48
  • we can use git remote -v also. – xpioneer Jan 03 '19 at 02:08
  • How do I create a branch that `git remote show` lists as untracked? It looks like this command shows what will happen when I do `git push`/`git pull`, rather than whether branches are tracked. – x-yuri Nov 19 '22 at 01:27
153

If you look at the man page for git-rev-parse, you'll see the following syntax is described:

<branchname>@{upstream}, e.g. master@{upstream}, @{u}

The suffix @{upstream} to a branchname (short form <branchname>@{u}) refers to the branch that the branch specified by branchname is set to build on top of. A missing branchname defaults to the current one.

Hence to find the upstream of the branch master, you would do:

git rev-parse --abbrev-ref master@{upstream}
# => origin/master

To print out the information for each branch, you could do something like:

while read branch; do
  upstream=$(git rev-parse --abbrev-ref $branch@{upstream} 2>/dev/null)
  if [[ $? == 0 ]]; then
    echo $branch tracks $upstream
  else
    echo $branch has no upstream configured
  fi
done < <(git for-each-ref --format='%(refname:short)' refs/heads/*)

# Output:
# master tracks origin/master
# ...

This is cleaner than parsing refs and config manually.

Michael
  • 8,362
  • 6
  • 61
  • 88
Carl Suster
  • 5,826
  • 2
  • 22
  • 36
  • I couldn't understand that bit in rev-parse despite finding it, so thanks for the clear explanation! – Alice Purcell Sep 19 '13 at 13:35
  • 4
    For those of us using git-flow, with branches named "feature/blahblah", the closing statement of the while loop should read: `done < <(git for-each-ref --format='%(refname:short)' refs/heads/**)` Note the **two** asterisks at the end of the glob pattern. – markeissler Jan 31 '15 at 22:29
  • 10
    `git rev-parse --abbrev-ref HEAD@{upstream}` seems to work nicely for the current branch. It also makes for a nice git alias. – Digikata Nov 22 '17 at 19:52
  • The `while` loop syntax looks a bit weird to me. You can just use `git for-each-ref ... | while read branch; do ...` which doesn't need a FIFO and runs in the same order like the commands written. – Daniel Böhmer May 03 '18 at 07:21
  • At least since git 2.5.1, you have a one-liner with `git for-each-ref --format='%(refname:short) tracks %(upstream:short)' refs/heads/*` – Mat M Aug 08 '18 at 06:25
95

An alternative to kubi's answer is to have a look at the .git/config file which shows the local repository configuration:

cat .git/config

Alojz Janez
  • 530
  • 1
  • 3
  • 13
Abizern
  • 146,289
  • 39
  • 203
  • 257
60
git for-each-ref --format='%(refname:short) <- %(upstream:short)' refs/heads

will show a line for each local branch. A tracking branch will look like:

master <- origin/master

A non-tracking one will look like:

test <- 
Aurélien
  • 1,742
  • 1
  • 19
  • 30
  • Nice, to add some ordering and TAB-bed output: _git for-each-ref --sort upstream --format='%(refname:short)%09<- %(upstream:short)' refs/heads_ – dimir Jun 07 '19 at 11:45
  • Beautifully concise and the output is actually much more readable than the accepted `git branch -vv`. – joki Nov 20 '19 at 13:14
  • 1
    The only problem is that I can't remember this, so I used `git config --global alias.track 'for-each-ref --format='\''%(refname:short) <- %(upstream:short)'\'' refs/heads'` – joki Nov 20 '19 at 13:35
42

For the current branch, here are two good choices:

% git rev-parse --abbrev-ref --symbolic-full-name @{u}
origin/mainline

or

% git for-each-ref --format='%(upstream:short)' $(git symbolic-ref -q HEAD)
origin/mainline

That answer is also here, to a slightly different question which was (wrongly) marked as a duplicate.

Community
  • 1
  • 1
cdunn2001
  • 17,657
  • 8
  • 55
  • 45
  • 6
    Based on that, all branches can be listed in a script friendly fashion: `git for-each-ref --shell --format='%(refname:short) %(upstream:short)' refs/heads`. – Daniel James Feb 17 '14 at 11:32
22

For the current branch, you could also say git checkout (w/o any branch). This is a no-op with a side-effects to show the tracking information, if exists, for the current branch.

$ git checkout 
Your branch is up-to-date with 'origin/master'.
Eugene Yarmash
  • 142,882
  • 41
  • 325
  • 378
8

Here is a neat and simple one. Can check git remote -v, which shows you all the origin and upstream of current branch.

MJeremy
  • 1,102
  • 17
  • 27
  • This may be true for the "main" (or "master") branch. But would not show which branch a feature branch would push to if you simply typed `git push` (without specifying any remote branch name) from inside that feature branch. You can set the remote branch a feature branch should push to by default via `git push -u origin remoteFeatureBranchName`. Generally, remoteFeatureBranchName will be the same name as the local feature branch you are pushing from, but it need not be. the command you suggest does *not* show this connection; it shows the origin and upstream repos, but not the linked branches. – SherylHohman Jan 28 '22 at 21:28
6

I use this alias

git config --global alias.track '!f() { ([ $# -eq 2 ] && ( echo "Setting tracking for branch " $1 " -> " $2;git branch --set-upstream $1 $2; ) || ( git for-each-ref --format="local: %(refname:short) <--sync--> remote: %(upstream:short)" refs/heads && echo --Remotes && git remote -v)); }; f'

then

git track
Olivier Refalo
  • 50,287
  • 22
  • 91
  • 122
4

Based on Olivier Refalo's answer

if [ $# -eq 2 ] 
then
    echo "Setting tracking for branch " $1 " -> " $2
    git branch --set-upstream $1 $2
else
    echo "-- Local --" 
    git for-each-ref --shell --format="[ %(upstream:short) != '' ] && echo -e '\t%(refname:short) <--> %(upstream:short)'" refs/heads | sh
    echo "-- Remote --" 
    REMOTES=$(git remote -v) 
    if [ "$REMOTES" != '' ]
    then
        echo $REMOTES
    fi  
fi

It shows only local with track configured.

Write it on a script called git-track on your path an you will get a git track command

A more elaborated version on https://github.com/albfan/git-showupstream

Community
  • 1
  • 1
albfan
  • 12,542
  • 4
  • 61
  • 80
1

git config --get-regexp "branch\.$current_branch\.remote"

will give you the name of the remote that is being tracked

git config --get-regexp "branch\.$current_branch\.merge"

will give you the name of the remote branch that's being tracked.

You'll need to replace $current_branch with the name of your current branch. You can get that dynamically with git rev-parse --abbrev-ref HEAD

The following mini-script combines those things. Stick it in a file named git-tracking, make it executable, and make sure it's in your path.

then you can say

$ git  tracking
<current_branch_name>-><remote_repo_name>/<remote_branch_name>

note that the remote branch name can be different from your local branch name (although it usually isn't). For example:

$git tracking 
xxx_xls_xslx_thing -> origin/totally_bogus

as you can see in the code the key to this is extracting the data from the git config. I just use sed to clear out the extraneous data.

#!/bin/sh

current_branch=$(git rev-parse --abbrev-ref HEAD)
remote=$(git config --get-regexp "branch\.$current_branch\.remote" | sed -e "s/^.* //")
remote_branch=$(git config --get-regexp "branch\.$current_branch\.merge" | \
  sed -e "s/^.* //" -e "s/refs\/.*\///")

echo "$current_branch -> $remote/$remote_branch"
masukomi
  • 10,313
  • 10
  • 40
  • 49