How can I see which Git branches are tracking which remote / upstream branch?
Asked Answered
P

12

1073

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?

Phenice answered 9/2, 2011 at 21:30 Comment(0)
C
1508

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.

Czerny answered 10/2, 2011 at 1:2 Comment(19)
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).Antimonic
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.Linebacker
@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.Czerny
@Jefromi actually, I just checked and just removing the asterisk worked. so: refs/heads/Linebacker
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.Samekh
Thanks very much for this! Worked like a charm. It also highlights the branch you are on so it's very obvious.Losing
All this does for me is print out the last commit hash and comment for each branch.Nonscheduled
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.Greenwald
@Greenwald 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.)Czerny
get current branch remote: ` git branch -vv | grep '*' | awk -F'[\[\]]' '{print $2}' `Seamus
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 commentUndergo
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/*Stonge
How can I make -vv the default option using .gitconfig?Goodard
@Seamus Simply add --list $currentBranchName, e.g.: git branch -vv --list masterSpeech
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.Adkinson
Does not work! Output is the same as git branch -vRadioactivity
@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.Statement
git branch -vv isn't remotely useful as it continues to list remotes after they have been deleted.Semantic
@Semantic Use --prune first to remove any remote-tracking references for branches that no longer exist on the remote repository. It cleans up obsolete references, ensuring that your local repository accurately reflects the current state of the remote repository. Like this: git fetch --pruneBeaufort
C
359

git remote show origin

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

Cockleshell answered 9/2, 2011 at 21:34 Comment(7)
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...Stephi
@Stephi You can use git remote show -n origin to get some information even when offline. From the git remote documentation: "With -n option, the remote heads are not queried first with git ls-remote <name>; cached information is used instead."Atalanti
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 make it sound like a remote branch is "tracked" only when it's linked/bound to a local branch for push/pull...Anderer
The problem is that I need to call this for all remote names until I see what I am actually looking for.Against
@Against You could run git remote show | xargs git remote show -n to view combined tracking info for all remotes.Euraeurasia
we can use git remote -v also.Slink
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.Bremerhaven
P
161

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.

Porterporterage answered 2/6, 2013 at 5:0 Comment(5)
I couldn't understand that bit in rev-parse despite finding it, so thanks for the clear explanation!Younger
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.Krishnakrishnah
git rev-parse --abbrev-ref HEAD@{upstream} seems to work nicely for the current branch. It also makes for a nice git alias.Mestizo
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.Crayon
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/*Stonge
O
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

Oneida answered 9/2, 2011 at 21:41 Comment(3)
Also git config --get-regex branchUnbosom
Or, more specifically, 'git config --get-regexp branch.*merge'Determinative
So basically, a branch has an upstream if branch.NAME.remote and branch.NAME.merge are set...Bremerhaven
E
62
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 <- 
Enloe answered 20/6, 2015 at 11:34 Comment(3)
Nice, to add some ordering and TAB-bed output: git for-each-ref --sort upstream --format='%(refname:short)%09<- %(upstream:short)' refs/headsParquet
Beautifully concise and the output is actually much more readable than the accepted git branch -vv. 🙏Manilla
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'Manilla
B
43

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.

Beulahbeuthel answered 11/10, 2013 at 0:31 Comment(1)
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.Selfexplanatory
M
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'.
Magnetohydrodynamics answered 23/10, 2014 at 10:23 Comment(2)
Fair enough, but you can accidentally type git checkout ., which is not a no-op.Boughton
You can accidentially type anything, really.Peeper
A
7

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

Annunciata answered 23/1, 2019 at 6:17 Comment(1)
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.Tad
S
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
Shirtwaist answered 5/4, 2012 at 20:36 Comment(2)
I think is worth noting that with two parameters your command configure a track branch.Sundin
Please add an explanation of what the command does and how you use it.Talesman
S
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

Sundin answered 12/11, 2012 at 9:25 Comment(0)
D
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"
Depolymerize answered 21/12, 2017 at 22:24 Comment(0)
J
0

Get info about all remotes, branches and tracking:

for remote in $(git remote show -n); do git remote show -n "${remote:?}"; done

or get just names of remotes with their url

git remote -v show -n
Jovia answered 14/4 at 18:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.