1560

I want to get a list of all the branches in a Git repository with the "freshest" branches at the top, where the "freshest" branch is the one that's been committed to most recently (and is, therefore, more likely to be one I want to pay attention to).

Is there a way I can use Git to either (a) sort the list of branches by latest commit, or (b) get a list of branches together with each one's last-commit date, in some kind of machine-readable format?

Worst case, I could always run git branch to get a list of all the branches, parse its output, and then git log -n 1 branchname --format=format:%ci for each one, to get each branch's commit date. But this will run on a Windows box, where spinning up a new process is relatively expensive, so launching the Git executable once per branch could get slow if there are a lot of branches. Is there a way to do all this with a single command?

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Joe White
  • 87,312
  • 52
  • 206
  • 320
  • 2
    http://stackoverflow.com/a/2514279/1804124 Has a better answer. – Spundun Jan 25 '13 at 03:36
  • 15
    @Spundun, you lost me there. How is a combination of multiple commands, including stuff piped through perl and sed, "better" than using a command that Git already has? – Joe White Jan 25 '13 at 03:40
  • Because with the answer here , I didn't get all the branches in the repo. In my particular case, the answer would give me one branch and the answer there gave me 20 or so branches(with the -r option). – Spundun Jan 25 '13 at 18:18
  • 41
    @Spundun regarding the answer with `git for-each-ref` from Jakub Narębski: you can get remote branches passing `refs/remotes/` instead of `refs/heads/` (or you can pass both, whitespace-separated); `refs/tags/` for tags, or just `refs/` for all three kinds. – jakub.g Jan 27 '13 at 04:45
  • 6
    Starting git 2.7 (Q4 2015), no more `for-each-ref`! You will use directly `git branch --sort=-committerdate`: see [my answer below](http://stackoverflow.com/a/33163401/6309) – VonC Oct 16 '15 at 05:58
  • @VonC, do you mean `for-each-ref` will no longer be available, or just that it won't be needed here because there'll be a better way? – Joe White Oct 17 '15 at 10:44
  • @JoeWhite it will still be available, but part of its semantic will be directly accessible from git branch itself. – VonC Oct 17 '15 at 10:53
  • I have completed [my answer below](http://stackoverflow.com/a/33163401/6309): when the comparison doesn't tiebreak branches (for instance same timestamp because committed together), it fallback on alphabetical comparison. – VonC Nov 08 '15 at 09:07
  • 1
    Possibly a duplicate of https://stackoverflow.com/questions/9236219/git-list-git-branches-sort-by-and-show-date?noredirect=1#comment81524670_9236219 – Ondra Žižka Nov 14 '17 at 16:16
  • Is there a way to achieve this without cloning, ie.in the style of `git ls-remote` ? – Ed Randall Oct 04 '18 at 07:50

31 Answers31

2195

Use the --sort=-committerdate option of git for-each-ref;

Also available since Git 2.7.0 for git branch:

Basic Usage:

git for-each-ref --sort=-committerdate refs/heads/

# Or using git branch (since version 2.7.0)
git branch --sort=-committerdate  # DESC
git branch --sort=committerdate  # ASC

Result:

Result

Advanced Usage:

git for-each-ref --sort=committerdate refs/heads/ --format='%(HEAD) %(color:yellow)%(refname:short)%(color:reset) - %(color:red)%(objectname:short)%(color:reset) - %(contents:subject) - %(authorname) (%(color:green)%(committerdate:relative)%(color:reset))'

Result:

Result

Pro Usage (Unix):

You can put the following snippet in your ~/.gitconfig. The recentb alias accepts two arguments:

  • refbranch: which branch the ahead and behind columns are calculated against. Default master
  • count: how many recent branches to show. Default 20
[alias]
    # ATTENTION: All aliases prefixed with ! run in /bin/sh make sure you use sh syntax, not bash/zsh or whatever
    recentb = "!r() { refbranch=$1 count=$2; git for-each-ref --sort=-committerdate refs/heads --format='%(refname:short)|%(HEAD)%(color:yellow)%(refname:short)|%(color:bold green)%(committerdate:relative)|%(color:blue)%(subject)|%(color:magenta)%(authorname)%(color:reset)' --color=always --count=${count:-20} | while read line; do branch=$(echo \"$line\" | awk 'BEGIN { FS = \"|\" }; { print $1 }' | tr -d '*'); ahead=$(git rev-list --count \"${refbranch:-master}..${branch}\"); behind=$(git rev-list --count \"${branch}..${refbranch:-master}\"); colorline=$(echo \"$line\" | sed 's/^[^|]*|//'); echo \"$ahead|$behind|$colorline\" | awk -F'|' -vOFS='|' '{$5=substr($5,1,70)}1' ; done | ( echo \"ahead|behind||branch|lastcommit|message|author\\n\" && cat) | column -ts'|';}; r"

Result:

Recentb alias result

Florian
  • 2,803
  • 1
  • 24
  • 26
Jakub Narębski
  • 268,805
  • 58
  • 209
  • 228
  • 17
    Perfect! I can even restrict the output to just the ref names by appending `--format=%(refname)`. – Joe White Mar 04 '11 at 12:45
  • 38
    This is better for me: `git for-each-ref --sort=-committerdate refs/heads/ --format='%(refname) %(committerdate) %(authorname)' | sed 's/refs\/heads\///g'` – saeedgnu Jan 30 '12 at 10:01
  • 2
    @ilius: why not use `:shortname`? – Jakub Narębski Feb 05 '12 at 21:45
  • 37
    @ilius: As @BeauSmith wrote: `git for-each-ref --sort=-committerdate --format='%(refname:short)' refs/heads/`. git-for-each-ref(1) manpage says: *For a non-ambiguous short name of the ref append `:short`.* – Jakub Narębski Feb 06 '12 at 10:21
  • I used refname:short but still a bunch of "heads/" are there while the branch name itself is not ambiguous. – saeedgnu Feb 07 '12 at 12:00
  • Docs are here: http://www.kernel.org/pub/software/scm/git/docs/git-for-each-ref.html – Peter Ehrlich Sep 05 '12 at 17:32
  • @Spundun: while `git-for-each-ref` doesn't support all the bells and whistles that `--pretty` option in `git show` does, it does allow for advanced formatting of output via `--format` option. – Jakub Narębski Jan 25 '13 at 13:01
  • pretty option is nice. But I liked the other answer mainly because this answer gave me only one branch while the other answer (with the -r option) gave me more than 20 branches. – Spundun Jan 25 '13 at 18:20
  • @Spundun: The original question was about **list of branches** (not a single branch), **sorted**. You can always pipe to `head -1` – Jakub Narębski Jan 25 '13 at 19:08
  • I also wanted a list of branches, but I only got one branch. The other answer gave me the whole list of branches. – Spundun Jan 25 '13 at 19:12
  • 1
    To get the commit message as well: `git for-each-ref --sort=-committerdate refs/heads/ --format='%(refname) %(committerdate) %(authorname) - %(contents:subject)' | sed 's/refs\/heads\///g'` Thanks! – Poni Apr 22 '14 at 08:00
  • 1
    @Poni: Nice. Though you can use `%(refname:short)` instead of piping output to sed (and hoping that commit message does not contain `refs/heads/`). – Jakub Narębski Apr 22 '14 at 09:45
  • It's easier to read the output if you format it with the date first, as the dates are (to 1 character) the same length. – joachim Jul 07 '14 at 08:10
  • 1
    To colorize the output: `git for-each-ref --sort='-committerdate' --format='%(color:green)%(committerdate:iso) %(color:blue)%(authorname)%09%(color:reset)%(refname:short)'` – sshaw Dec 20 '14 at 18:28
  • 83
    This is a colorized version including hashes, messages, ordered ascending based on commit date, with the relative age of the last commit on each branch. I stole all of the ideas from you guys above. It's in my .gitconfig in the `[alias]` section and I love it. `br = for-each-ref --sort=committerdate refs/heads/ --format='%(HEAD) %(color:yellow)%(refname:short)%(color:reset) - %(color:red)%(objectname:short)%(color:reset) - %(contents:subject) - %(authorname) (%(color:green)%(committerdate:relative)%(color:reset))'` – Michael Percy Mar 13 '15 at 22:01
  • 1
    And this version will only show the last 10 entries, use `--count` to show more, also works as an alias if you want to: `git for-each-ref --sort=-committerdate --count=10 refs/heads/ --format='%(HEAD) %(color:yellow)%(refname:short)%(color:reset) - %(color:red)%(objectname:short)%(color:reset) - %(contents:subject) - %(authorname) (%(color:green)%(committerdate:relative)%(color:reset))'` – Willem D'Haeseleer Mar 17 '16 at 20:06
  • As of Git 2.7(ish), you can also add `align` fields to clean up the formatted output. – jstevenco Jun 29 '16 at 20:57
  • 1
    Also since Git 1.7.0 you don't need to resort to plumbing (low-level) commands; thanks to GSoC project of branch / tag / for-each-ref code unification, you can simply use `git branch --sort=-committerdate`. – Jakub Narębski Jul 01 '16 at 13:37
  • `git branch --sort=-committerdate` is not working in git version 2.1.4 @jakub-narębski – Qi Luo Jul 11 '16 at 22:37
  • @QiLuo: I'm sorry, a typo: it was meant to be Git **2.7.0** is the version from which you can use `git branch --sort=-committerdate`. See also e.g. https://git-blame.blogspot.com/2016/05/fun-with-new-feature-in-recent-git.html – Jakub Narębski Jul 19 '16 at 15:18
  • Advanced Usage is a bit inconsistent with Basic Usage in sort order as it uses `--sort=committerdate`. Is it worth to use `--sort=-committerdate` (with dash) as well? – ks1322 Jul 29 '16 at 10:04
  • Love the format. I changed it to accommodate my 'I don't want to have old branches lying around'-obsession and modified the format to my need: `git for-each-ref --sort=committerdate refs/heads/ --format='%(HEAD) %(color:yellow)%(refname:short)%(color:reset) - %(color:red)%(objectname:short)%(color:reset) - %(contents:subject) - %(authorname) (%(color:green)%(committerdate:relative)%(color:reset))'` – mraxus Sep 13 '16 at 10:43
  • Using the idea to pipe the output through `column` from @dimid [below](http://stackoverflow.com/a/30076212/3991403) my version of the command is: `git for-each-ref --sort=-committerdate refs/heads/ --format='%(HEAD) %(color:red)%(objectname:short)%(color:reset)|%(color:yellow)%(refname:short)%(color:reset)|%(contents:subject)|%(authorname) (%(color:green)%(committerdate:relative)%(color:reset))' | column -ts'|'` – Joshua Skrzypek Sep 19 '16 at 11:18
  • 2
    @MikePercy ...what uh...what else you got in your `.gitconfig[alias]`? :) – Kevin Friedheim Dec 15 '16 at 20:16
  • 2
    @KevinFriedheim mostly just this and git log colorization stuff, but if you really want to know: https://github.com/mpercy/Dotfiles/blob/master/gitconfig :) – Michael Percy Mar 07 '17 at 01:47
  • 2
    Jakub's "Advanced Usage" example is the ascending type, for those who'd prefer the "Descending Usage", don't overlook the subtle difference he points out in his simple examples (the "-" sign). Here it is: `git for-each-ref --sort=-committerdate refs/heads/ --format='%(HEAD) %(color:yellow)%(refname:short)%(color:reset) - %(color:red)%(objectname:short)%(color:reset) - %(contents:subject) - %(authorname) (%(color:green)%(committerdate:relative)%(color:reset))'`.Makes more sense as a super minor edit to show both "Advanced Usage" versions as an edit to the answer, but my minor edit was rejected. – Gabriel Staples Mar 09 '18 at 02:10
  • Seems also `git branch` takes a format parameter (version 2.17.1), so the coloring works for it to. `branch` have the perk that it accepts `-r` or `-a` to show remote/all branches. I use alias `work = branch --sort=-committerdate --format='%(HEAD) %(color:yellow)%(refname:short)%(color:reset) - %(color:red)%(objectname:short)%(color:reset) - %(contents:subject) - %(authorname) (%(color:green)%(committerdate:relative)%(color:reset))'` – Love Apr 15 '19 at 17:12
  • Windows: Replace single quotes with double quotes – Matt Kneiser Dec 31 '19 at 01:09
  • `man git branch` shows the sort option: `--sort=`. How can I see a list of all "keys" one can use here to sort by? – Gabriel Staples Mar 23 '20 at 01:03
  • For the current branch to stand out, consider using `%(if)%(HEAD)%(then)* %(color:red bold)%(refname:short)%(color:reset)%(else) %(refname:short)%(end) `, which will color and bold it. – Yuriy Nemtsov Jul 01 '20 at 15:41
  • Since the `git branch` version doesn't take a count=n parameter, I added `--color=always` and piped it through `head -n 5`. – Noumenon Aug 12 '20 at 16:11
  • including remote branches `git branch -a --sort=-committerdate` – Vladimir Stazhilov May 07 '21 at 09:37
139

List of Git branch names, ordered by most recent commit…

Expanding on Jakub’s answer and Joe’s tip, the following will strip out the "refs/heads/" so the output only displays the branch names:


Command:

git for-each-ref --count=30 --sort=-committerdate refs/heads/ --format='%(refname:short)'

Result:

Recent Git branches

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Beau Smith
  • 29,103
  • 12
  • 82
  • 88
  • 4
    You can also use `--format=%(refname:short)` instead of relying on `cut`. – Chaitanya Gupta Feb 01 '12 at 05:49
  • 5
    Is there any way to do this for the REMOTE repository? – Allan Bowe Jun 24 '14 at 14:50
  • 12
    aah - @jakub.g already explained: you can get remote branches passing refs/remotes/ instead of refs/heads/. Perfect!! – Allan Bowe Jun 24 '14 at 14:52
  • I like this one, if you're trying to alias it, which I did, to `git rb` remember to surround the command in quotes: `git config --global alias.rb "for-each-ref --count=20 --sort=-committerdate refs/heads/ --format=\'%(refname:short)\'"` – Michael Discenza Feb 27 '15 at 16:49
  • 3
    And now you can do this with `git branch`, so getting local, remote or all branches works like on git-branch (i.e. -r, -a). `git branch -r --sort=committerdate --format='%(HEAD) %(color:yellow)%(refname:short)%(color:reset) - %(color:red)%(objectname:short)%(color:reset) - %(contents:subject) - %(authorname) (%(color:green)%(committerdate:relative)%(color:reset))'` – phord Mar 16 '17 at 16:58
  • To align the results, you can use tab (`%09`) instead of ` - `; then pipe it into columns. So, `git for-each-ref --sort=-committerdate refs/ --format='%(HEAD)%09%(color:yellow)%(refname:short)%(color:reset)%09%(color:red)%(objectname:short)%(color:reset)%09%(contents:subject)%09%(authorname)%09(%(color:green)%(committerdate:relative)%(color:reset))' | column -t -s $'\t'` – Drasill Feb 05 '18 at 09:34
  • 1
    @AllanBowe the following will output the top 5 active branches in a repo: `git branch -va --sort=committerdate | tail -5`. Perhaps that's an alternative to what you were asking and discovered. – marckassay Jul 21 '20 at 14:04
110

Here is a simple command that lists all branches with latest commits:

git branch -v

To order by most recent commit, use

git branch -v --sort=committerdate

Source: http://git-scm.com/book/en/Git-Branching-Branch-Management

Ben Claar
  • 2,988
  • 15
  • 32
user1682406
  • 1,549
  • 1
  • 10
  • 9
96

Here's the optimal code, which combines the other two answers:

git for-each-ref --sort=-committerdate refs/heads/ --format='%(committerdate:short) %(authorname) %(refname:short)'
nikolay
  • 2,176
  • 17
  • 13
  • 11
    Even a little mor optimized to get a tabular output: `git for-each-ref --sort=-committerdate refs/heads/ --format='%(committerdate:short) %(authorname) %(refname:short)'` – schoetbi Mar 01 '13 at 12:58
  • 4
    for some reason i had to use double-quotes on windows, but otherwise these work just fine :) – amenthes Feb 25 '16 at 13:35
  • 1
    @schoetbi That code looks exactly like the one from nikolay, what did you change to make it tabular? – Enrico Mar 22 '16 at 13:33
  • 1
    @Enrico and others that may wonder about the same thing. nikolay changed his answer using schoetbis suggestion. By moving date first which is always the same length the result seems more tabular. – johnny Feb 11 '20 at 07:21
77

I use the following alias:

recent = "!r() { count=$1; git for-each-ref --sort=-committerdate refs/heads --format='%(HEAD)%(color:yellow)%(refname:short)|%(color:bold green)%(committerdate:relative)|%(color:blue)%(subject)|%(color:magenta)%(authorname)%(color:reset)' --color=always --count=${count:=10} | column -ts'|'}; r"

which produces:

Result

We can also give a custom count, e.g.,

git recent 20 (the default is 10).

dimid
  • 6,179
  • 1
  • 38
  • 70
  • 3
    Great alias! I would suggest `column -ts'|'` and pipe characters if the comma char can occur inside relative timestamps in your locale. – Björn Lindqvist Jun 29 '15 at 06:44
  • 1
    great alias, thank you very much. can you improve it to show the current branch with an other colour or with * at the beginning? – elhadi dp ıpɐɥןǝ Sep 03 '15 at 10:31
  • In case the ```sed \"s/m${cur}|/m* ${cur}|/\"``` gives you an error about an unknown option to s, the solution is to replace ```\"``` by a simple quote. – thoroc Jun 01 '16 at 08:33
  • @thoroc but then I won't be able to expand `cur` – dimid Jun 01 '16 at 09:42
  • 3
    At least in the latest version of git you can just add `'%(HEAD) ...'` at the start of the format string to get the same effect without piping throught the `sed` command – Joshua Skrzypek Sep 19 '16 at 11:15
  • 5
    I could not git this to work as a git alias. I had to use `[alias] recent = !git for-each-ref --sort=-committerdate refs/heads --format='%(HEAD)%(color:yellow)%(refname:short)|%(color:bold green)%(committerdate:relative)|%(color:blue)%(subject)|%(color:magenta)%(authorname)%(color:reset)'|column -ts'|'` – Wesley Smith Oct 06 '16 at 11:44
  • Any idea how to use `git branch --color[=]` to display branches in multiple colors – Avi Kenjale Jan 27 '17 at 23:00
  • these anonymous function are not supported in fish :(. nice work, Id pipe it through some command to truncate the commit message. some are longer than they should be, on occasion. – wprater Jan 25 '18 at 01:11
  • 15
    I had to add --color=always to get color. `git for-each-ref --sort=-committerdate refs/heads --format='%(HEAD)%(color:yellow)%(refname:short)|%(color:bold green)%(committerdate:relative)|%(color:blue)%(subject)|%(color:magenta)%(authorname)%(color:reset)' --color=always|column -ts'|'}` – JohnFlux Jun 19 '18 at 21:29
  • Could you include example shell commands necessary to set up and test this? On my git (2.17.1), I basically get `r: not found`. – mwfearnley Mar 02 '19 at 20:53
  • @mwfearnley Nothing special really, just add this alias to your git config file and call `git recent` from the shell. – dimid Mar 03 '19 at 07:43
  • Thanks, that's pretty much what I tried though. You can see my ~/.gitconfig file at https://pastebin.com/JS2VJDwR . I basically get: `r(){git for-each-ref ... }; r: r: not found`. Does it work for you? – mwfearnley Mar 04 '19 at 13:04
  • 1
    Note there should be a space after `{`, also it might be an issue wit the shell, e.g. https://stackoverflow.com/questions/46435606/how-to-use-a-bash-function-in-a-git-alias – dimid Mar 04 '19 at 13:14
  • 1
    What does the `!r()` do? – Brian Low May 15 '19 at 21:51
  • 1
    @BrianLow Defines a function. See here https://jondavidjohn.com/git-aliases-parameters/ – dimid May 16 '19 at 07:43
  • 4
    @mwfearnley: For me, putting a semicolon inside the braces helped `!r(){git for-each-ref ... ;}; r` – Karl Bartel Jun 27 '19 at 12:34
  • 2
    I also need to add a semi-colon after `-ts'|'` i.e. `"!r(){ git ... -ts'|'; }; r"` – Emmanuel N K Oct 18 '19 at 02:15
  • `column` is a great addition! – CIsForCookies Jul 14 '20 at 08:13
  • Removing the `r` function would also work: `!git for-each-ref --sort=-committerdate refs/heads --format='%(HEAD)%(color:yellow)%(refname:short)|%(color:bold green)%(committerdate:relative)|%(color:blue)%(subject)|%(color:magenta)%(authorname)%(color:reset)' --color=always | column -ts'|'` – Visya Nov 04 '20 at 12:17
57

I was able to reference the previous examples to create something that works best for me.

git for-each-ref --sort=-committerdate refs/heads/ --format='%(authordate:short) %(color:red)%(objectname:short) %(color:yellow)%(refname:short)%(color:reset) (%(color:green)%(committerdate:relative)%(color:reset))'

Screenshot of Output

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Andrew
  • 3,067
  • 1
  • 27
  • 33
  • 1
    That looks nice, more colorful than using directly git branch as I suggested in https://stackoverflow.com/a/33163401/6309. +1 – VonC Jun 13 '17 at 19:25
  • Thanks, @VonC glad you like it! – Andrew Jun 13 '17 at 20:47
  • 2
    This one worked out of the box for me, unlike some of the others, so I voted for it. – Casey Jun 26 '17 at 17:14
  • 2
    Worked as is really nicely! Thanks! :-) – FrozenTarzan Jun 30 '17 at 09:45
  • 1
    Ditto - this one worked out-of-box, unlike a number of others I just tried. Thanks. – Dan Nissenbaum Nov 18 '17 at 23:56
  • 8
    This one is clean and neat. Sometime I'd add remote and authorname as this: `git for-each-ref --sort=-committerdate refs/heads/ refs/remotes --format='%(authordate:short) %(authorname) %(color:red)%(objectname:short) %(color:yellow)%(refname:short)%(color:reset) (%(color:green)%(committerdate:relative)%(color:reset))'` – ywu Oct 21 '19 at 15:14
41

I also needed colors, tags and remote references without any duplicates:

for ref in $(git for-each-ref --sort=-committerdate --format="%(refname)" refs/heads/ refs/remotes ); do git log -n1 $ref --pretty=format:"%Cgreen%cr%Creset %C(yellow)%d%Creset %C(bold blue)<%an>%Creset%n" | cat ; done | awk '! a[$0]++'

Because quoting can be hard, here is the alias for Bash:

alias glist='for ref in $(git for-each-ref --sort=-committerdate --format="%(refname)" refs/heads/ refs/remotes ); do git log -n1 $ref --pretty=format:"%Cgreen%cr%Creset %C(yellow)%d%Creset %C(bold blue)<%an>%Creset%n" | cat ; done | awk '"'! a["'$0'"]++'"
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
estani
  • 17,829
  • 2
  • 74
  • 52
  • $ awk: syntax error near line 1 awk: bailing out near line 1 – Jamie Mason Nov 08 '13 at 09:12
  • @GotNoSugarBaby You are using single quotes like the example right? which shell are you using? Bash gives that character a special meaning otherwise. – estani Nov 08 '13 at 10:19
  • hey, I ran this on /bin/bash (GNU bash, version 4.0.28(1)-release (i386-pc-solaris2.11)) with a straight copy and paste of your example — but since then I've run it on /bin/bash (GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin12)) and it works, so I'll remove the down-vote. Thanks a lot estani. – Jamie Mason Nov 08 '13 at 14:12
  • @GotNoSugarBaby I use 4.2.25(1)-release (x86_64-pc-linux-gnu) nad tried on 3.x and worked. I'm not sure what issue it was... but it might have bennn a git version related issue, instead of a bash one. In any case, I'm glad it works for you! – estani Nov 25 '13 at 09:47
  • How would I limit this command to say the 20 most recent branches? On the repo I run it on, it gives me tons of pages full of branches over the past two years (I know we probably shouldn't have so many old, un-merged branches lying around in the repo) – Michael Discenza Feb 27 '15 at 16:55
  • 1
    @MichaelDiscenza just pipe everything to head. that would be to add `| head -n20` at the end. If you are using the alias, be sure this goes *within* the quotes. – estani Feb 28 '15 at 13:42
  • Best answer for remote branches, sadly the colors are not working for me – NicolasElPapu Apr 08 '21 at 12:51
  • Best answer since this supports remote branches. – Thorkil Værge May 03 '21 at 13:51
31

git 2.7 (Q4 2015) will introduce branch sorting using directly git branch:
See commit aa3bc55, commit aedcb7d, commit 1511b22, commit f65f139, ... (23 Sep 2015), commit aedcb7d, commit 1511b22, commit ca41799 (24 Sep 2015), and commit f65f139, ... (23 Sep 2015) by Karthik Nayak (KarthikNayak).
(Merged by Junio C Hamano -- gitster -- in commit 7f11b48, 15 Oct 2015)

In particular, commit aedcb7d:

branch.c: use 'ref-filter' APIs

Make 'branch.c' use 'ref-filter' APIs for iterating through refs sorting. This removes most of the code used in 'branch.c' replacing it with calls to the 'ref-filter' library.

It adds the option --sort=<key>:

Sort based on the key given.
Prefix - to sort in descending order of the value.

You may use the --sort=<key> option multiple times, in which case the last key becomes the primary key.

The keys supported are the same as those in git for-each-ref.
Sort order defaults to sorting based on the full refname (including refs/... prefix). This lists detached HEAD (if present) first, then local branches and finally remote-tracking branches.

Here:

git branch --sort=-committerdate 

Or (see below with Git 2.19)

# if you are sure to /always/ want to see branches ordered by commits:
git config --global branch.sort -committerdate
git branch

See also commit 9e46833 (30 Oct 2015) by Karthik Nayak (KarthikNayak).
Helped-by: Junio C Hamano (gitster).
(Merged by Junio C Hamano -- gitster -- in commit 415095f, 03 Nov 2015)

When sorting as per numerical values (e.g. --sort=objectsize) there is no fallback comparison when both refs hold the same value. This can cause unexpected results (i.e. the order of listing refs with equal values cannot be pre-determined) as pointed out by Johannes Sixt ($gmane/280117).

Hence, fallback to alphabetical comparison based on the refname whenever the other criterion is equal.

$ git branch --sort=objectsize

*  (HEAD detached from fromtag)
    branch-two
    branch-one
    master

With Git 2.19, the sort order can be set by default.
git branch supports a config branch.sort, like git tag, which already had a config tag.sort.
See commit 560ae1c (16 Aug 2018) by Samuel Maftoul (``).
(Merged by Junio C Hamano -- gitster -- in commit d89db6f, 27 Aug 2018)

branch.sort:

This variable controls the sort ordering of branches when displayed by git-branch.
Without the "--sort=<value>" option provided, the value of this variable will be used as the default.


To list remote branches, use git branch -r --sort=objectsize. The -r flag causes it to list remote branches instead of local branches.


With Git 2.27 (Q2 2020), "git branch" and other "for-each-ref" variants accepted multiple --sort=<key> options in the increasing order of precedence, but it had a few breakages around "--ignore-case" handling, and tie-breaking with the refname, which have been fixed.

See commit 7c5045f, commit 76f9e56 (03 May 2020) by Jeff King (peff).
(Merged by Junio C Hamano -- gitster -- in commit 6de1630, 08 May 2020)

ref-filter: apply fallback refname sort only after all user sorts

Signed-off-by: Jeff King

Commit 9e468334b4 ("ref-filter: fallback on alphabetical comparison", 2015-10-30, Git v2.7.0-rc0 -- merge listed in batch #10) taught ref-filter's sort to fallback to comparing refnames.
But it did it at the wrong level, overriding the comparison result for a single "--sort" key from the user, rather than after all sort keys have been exhausted.

This worked correctly for a single "--sort" option, but not for multiple ones.
We'd break any ties in the first key with the refname and never evaluate the second key at all.

To make matters even more interesting, we only applied this fallback sometimes!
For a field like "taggeremail" which requires a string comparison, we'd truly return the result of strcmp(), even if it was 0.
But for numerical "value" fields like "taggerdate", we did apply the fallback. And that's why our multiple-sort test missed this: it uses taggeremail as the main comparison.

So let's start by adding a much more rigorous test. We'll have a set of commits expressing every combination of two tagger emails, dates, and refnames. Then we can confirm that our sort is applied with the correct precedence, and we'll be hitting both the string and value comparators.

That does show the bug, and the fix is simple: moving the fallback to the outer compare_refs() function, after all ref_sorting keys have been exhausted.

Note that in the outer function we don't have an "ignore_case" flag, as it's part of each individual ref_sorting element. It's debatable what such a fallback should do, since we didn't use the user's keys to match.
But until now we have been trying to respect that flag, so the least-invasive thing is to try to continue to do so.
Since all callers in the current code either set the flag for all keys or for none, we can just pull the flag from the first key. In a hypothetical world where the user really can flip the case-insensitivity of keys separately, we may want to extend the code to distinguish that case from a blanket "--ignore-case".


The implementation of "git branch --sort"(man) wrt the detached HEAD display has always been hacky, which has been cleaned up with Git 2.31 (Q1 2021).

See commit 4045f65, commit 2708ce6, commit 7c269a7, commit d094748, commit 75c50e5 (07 Jan 2021), and commit 08bf6a8, commit ffdd02a (06 Jan 2021) by Ævar Arnfjörð Bjarmason (avar).
(Merged by Junio C Hamano -- gitster -- in commit 9e409d7, 25 Jan 2021)

branch: show "HEAD detached" first under reverse sort

Signed-off-by: Ævar Arnfjörð Bjarmason

Change the output of the likes of "git branch -l --sort=-objectsize"(man) to show the "(HEAD detached at <hash>)" message at the start of the output.
Before the compare_detached_head() function added in a preceding commit we'd emit this output as an emergent effect.

It doesn't make any sense to consider the objectsize, type or other non-attribute of the "(HEAD detached at <hash>)" message for the purposes of sorting.
Let's always emit it at the top instead.
The only reason it was sorted in the first place is because we're injecting it into the ref-filter machinery so builtin/branch.c doesn't need to do its own "am I detached?" detection.

VonC
  • 1,042,979
  • 435
  • 3,649
  • 4,283
25

The other answers don't seem to allow passing -vv to get verbose output.

So here's a one-liner that sorts git branch -vv by commit date, preserving color etc:

git branch -vv --color=always | while read; do echo -e $(git log -1 --format=%ct $(echo "_$REPLY" | awk '{print $2}' | perl -pe 's/\e\[?.*?[\@-~]//g') 2> /dev/null || git log -1 --format=%ct)"\t$REPLY"; done | sort -r | cut -f 2

If you additionally want to print the commit date, you can use this version instead:

git branch -vv --color=always | while read; do echo -e $(git log -1 --format=%ci $(echo "_$REPLY" | awk '{print $2}' | perl -pe 's/\e\[?.*?[\@-~]//g') 2> /dev/null || git log -1 --format=%ci)" $REPLY"; done | sort -r | cut -d ' ' -f -1,4-

Sample output:

2013-09-15   master                  da39a3e [origin/master: behind 7] Some patch
2013-09-11 * (detached from 3eba4b8) 3eba4b8 Some other patch
2013-09-09   my-feature              e5e6b4b [master: ahead 2, behind 25] WIP

It's probably more readable split into multiple lines:

git branch -vv --color=always | while read; do
    # The underscore is because the active branch is preceded by a '*', and
    # for awk I need the columns to line up. The perl call is to strip out
    # ansi colors; if you don't pass --color=always above you can skip this
    local branch=$(echo "_$REPLY" | awk '{print $2}' | perl -pe 's/\e\[?.*?[\@-~]//g')
    # git log fails when you pass a detached head as a branch name.
    # Hide the error and get the date of the current head.
    local branch_modified=$(git log -1 --format=%ci "$branch" 2> /dev/null || git log -1 --format=%ci)
    echo -e "$branch_modified $REPLY"
# cut strips the time and timezone columns, leaving only the date
done | sort -r | cut -d ' ' -f -1,4-

This should also work with other arguments to git branch, e.g. -vvr to list remote-tracking branches, or -vva to list both remote-tracking and local branches.

John Mellor
  • 11,028
  • 4
  • 41
  • 32
  • `-vv` can be useful indeed, thanks. However, this solution still spawns new processes for each branch, which the OP wanted to avoid. – musiphil Jan 19 '14 at 07:28
  • Actually `git branch` doesn't specifically define the meaning of `-vv`, but only of `-v`, so `-vv` should have the same as `-v`. – musiphil Jan 19 '14 at 07:31
  • 2
    This is the best. And adding -avv makes it take into account remote branches as well. Thanks for this! – Gopherkhan Apr 21 '15 at 23:32
  • @musiphil My _git branch_ manpage, section `-v, -vv, --verbose` contains the following: `If given twice, print the name of the upstream branch, as well` – Perleone Sep 28 '15 at 12:07
  • @Perleone: I don't know how I got that information, but you are right, and I stand corrected. Thanks! – musiphil Sep 28 '15 at 17:09
  • this was the only one that worked for me as I am on an old verion of git (at work), added the **-r -vv** to make it work remotely, this gave a slightly different dated response to **-avv** or **-rvv** – MrChick May 18 '18 at 10:40
22

As of Git 2.19 you can simply:

git branch --sort=-committerdate

You can also:

git config branch.sort -committerdate

So whenever you list branches in the current repository, it will be listed sorted by committerdate.

If whenever you list branches, you want them sorted by comitterdate:

git config --global branch.sort -committerdate

Disclaimer: I'm the author of this feature in Git, and I implemented it when I saw this question.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
user801247
  • 1,713
  • 12
  • 11
  • 2
    Most up-to-date answer, far easier than using complex scripts or aliases – mtefi Sep 17 '18 at 11:38
  • **Use with caution!** Beware everyone, this is not a command to list the branches. It's a command to change the configuration of Git and will have permanent global repercussions. – Jazimov Nov 13 '18 at 17:51
  • 1
    @Jazimov you are right, I edited the answer so it's clearer – user801247 Dec 01 '18 at 21:35
19

I like using a relative date and shortening the branch name like this:

git for-each-ref --sort='-authordate:iso8601' --format=' %(authordate:relative)%09%(refname:short)' refs/heads

Which gives you output:

21 minutes ago  nathan/a_recent_branch
6 hours ago     master
27 hours ago    nathan/some_other_branch
29 hours ago    branch_c
6 days ago      branch_d

I recommend making a Bash file for adding all your favorite aliases and then sharing the script out to your team. Here's an example to add just this one:

#!/bin/sh

git config --global alias.branches "!echo ' ------------------------------------------------------------' && git for-each-ref --sort='-authordate:iso8601' --format=' %(authordate:relative)%09%(refname:short)' refs/heads && echo ' ------------------------------------------------------------'"

Then you can just do this to get a nicely formatted and sorted local branch list:

git branches

Update: Do this if you want coloring:

#!/bin/sh
#
(echo ' ------------------------------------------------------------‌​' && git for-each-ref --sort='-authordate:iso8601' --format=' %(authordate:relative)%09%(refname:short)' refs/heads && echo ' ------------------------------------------------------------‌​') | grep --color -E "$(git rev-parse --abbrev-ref HEAD)$|$"
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
n8tr
  • 4,718
  • 2
  • 30
  • 32
  • This gives me `fatal: unknown field name: '-authordate:iso8601'` – Factor Mystic Sep 30 '15 at 15:04
  • 1
    Fancy colored output is fancy, but this is simple and just what I was looking for. Replace `refs/heads` with `refs/remotes` to have a look at remote branches. – Lambart Apr 30 '17 at 18:40
  • The command itself is lovely, but the alias throws an error: `expansion of alias 'branches' failed; 'echo' is not a git command` – Philip Kahn Apr 13 '18 at 21:24
  • Works for me. What happens if you just copy paste this into terminal? ```(echo ' ------------------------------------------------------------‌​' && git for-each-ref --sort='-authordate:iso8601' --format=' %(authordate:relative)%09%(refname:short)' refs/heads && echo ' ------------------------------------------------------------‌​') | grep --color -E "$(git rev-parse --abbrev-ref HEAD)$|$"``` – n8tr Apr 15 '18 at 21:38
  • This works only for local branches – NicolasElPapu Apr 08 '21 at 12:42
11

Adds some color (since pretty-format isn't available)

[alias]
    branchdate = for-each-ref --sort=-committerdate refs/heads/ --format="%(authordate:short)%09%(objectname:short)%09%1B[0;33m%(refname:short)%1B[m%09"
epylinkn
  • 1,028
  • 11
  • 15
9

I came up with the following command (for Git 2.13 and later):

git branch -r --sort=creatordate \
    --format "%(creatordate:relative);%(committername);%(refname:lstrip=-1)" \
    | grep -v ";HEAD$" \
    | column -s ";" -t

If you don’t have column you can replace the last line with

    | sed -e "s/;/\t/g"

The output looks like

6 years ago             Tom Preston-Werner  book
4 years, 4 months ago   Parker Moore        0.12.1-release
4 years ago             Matt Rogers         1.0-branch
3 years, 11 months ago  Matt Rogers         1.2_branch
3 years, 1 month ago    Parker Moore        v1-stable
12 months ago           Ben Balter          pages-as-documents
10 months ago           Jordon Bedwell      make-jekyll-parallel
6 months ago            Pat Hawks           to_integer
5 months ago            Parker Moore        3.4-stable-backport-5920
4 months ago            Parker Moore        yajl-ruby-2-4-patch
4 weeks ago             Parker Moore        3.4-stable
3 weeks ago             Parker Moore        rouge-1-and-2
19 hours ago            jekyllbot           master

I wrote a blog post about how the various pieces work.

bdesham
  • 13,980
  • 10
  • 70
  • 116
  • Nice. +1. It does use the `git branch --sort` I mentioned in https://stackoverflow.com/a/33163401/6309. – VonC Aug 01 '17 at 04:34
  • @DanNissenbaum Make sure you’re using Git 2.13 (released in May 2017) or later. – bdesham Nov 19 '17 at 02:54
8

I had the same problem, so I wrote a Ruby gem called Twig. It lists branches in chronological order (newest first), and can also let you set a max age so that you don't list all branches (if you have a lot of them). For example:

$ twig

                              issue  status       todo            branch
                              -----  ------       ----            ------
2013-01-26 18:00:21 (7m ago)  486    In progress  Rebase          optimize-all-the-things
2013-01-26 16:49:21 (2h ago)  268    In progress  -               whitespace-all-the-things
2013-01-23 18:35:21 (3d ago)  159    Shipped      Test in prod  * refactor-all-the-things
2013-01-22 17:12:09 (4d ago)  -      -            -               development
2013-01-20 19:45:42 (6d ago)  -      -            -               master

It also lets you store custom properties for each branch, e.g., ticket id, status, todos, and filter the list of branches according to these properties. More info: http://rondevera.github.io/twig/

Ron DeVera
  • 13,578
  • 5
  • 39
  • 36
  • 5
    That name might not help as I am pretty sure there are a few pieces of software out there with the same name. – thoroc Jan 29 '16 at 09:14
8

FYI, if you'd like to get a list of recently checked out branches (as opposed to recently committed) you can use Git's reflog:

$ git reflog | egrep -io "moving from ([^[:space:]]+)" | awk '{ print $3 }' | head -n5
master
stable
master
some-cool-feature
feature/improve-everything

See also: How can I get a list of Git branches that I've recently checked out?

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Jordan Brough
  • 6,012
  • 2
  • 28
  • 29
5

Here's a little script that I use to switch between recent branches:

#!/bin/bash
# sudo bash

re='^[0-9]+$'

if [[ "$1" =~ $re ]]; then
    lines="$1"
else
    lines=10
fi
branches="$(git recent | tail -n $lines | nl)"
branches_nf="$(git recent-nf | tail -n $lines | nl)"
echo "$branches"

# Prompt which server to connect to
max="$(echo "$branches" | wc -l)"
index=
while [[ ! ( "$index" =~ ^[0-9]+$ && "$index" -gt 0 && "$index" -le "$max" ) ]]; do
    echo -n "Checkout to: "
    read index
done

branch="$( echo "$branches_nf" | sed -n "${index}p" | awk '{ print $NF }' )"
git co $branch
clear

Using those two aliases:

recent = for-each-ref --sort=committerdate refs/heads/ --format=' %(color:blue) %(authorname) %(color:yellow)%(refname:short)%(color:reset)'
recent-nf = for-each-ref --sort=committerdate refs/heads/ --format=' %(authorname) %(refname:short)'

Just call that in a Git repository, and it will show you the last N branches (10 by default) and a number aside each. Input the number of the branch, and it checks out:

Enter image description here

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Agus Arias
  • 429
  • 1
  • 7
  • 5
4

Here is another script that does what all the other scripts do. In fact, it provides a function for your shell.

Its contribution is that it pulls some colours from your Git configuration (or uses defaults).

# Git Branch by Date
# Usage: gbd [ -r ]
gbd() {
    local reset_color=`tput sgr0`
    local subject_color=`tput setaf 4 ; tput bold`
    local author_color=`tput setaf 6`

    local target=refs/heads
    local branch_color=`git config --get-color color.branch.local white`

    if [ "$1" = -r ]
    then
        target=refs/remotes/origin
        branch_color=`git config --get-color color.branch.remote red`
    fi

    git for-each-ref --sort=committerdate $target --format="${branch_color}%(refname:short)${reset_color} ${subject_color}%(subject)${reset_color} ${author_color}- %(authorname) (%(committerdate:relative))${reset_color}"
}
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
joeytwiddle
  • 24,338
  • 11
  • 107
  • 91
4

Normally we consider the remote branches recently. So try this

git fetch
git for-each-ref --sort=-committerdate refs/remotes/origin
Victor Choy
  • 3,281
  • 21
  • 30
4

Another variation:

git branch -r --sort=-committerdate --format='%(HEAD)%(color:yellow)%(refname:short)|%(color:bold green)%(committerdate:relative)|%(color:blue)%(subject)|%(color:magenta)%(authorname)%(color:reset)' --color=always | column -ts'|'

Worth noting that even though it's looking at changes in remote branches, it's worth syncing with origin before running the command (can use git fetch), as I found it can return out of date information if your local Git folder hasn't been updated in a while.

Also, this is a version that works in Windows cmd and PowerShell (didn't get output displayed in columns, would be interested to see if anyone gets this working):

git branch -r --sort=-committerdate --format="%(HEAD)%(color:yellow)%(refname:short)|%(color:bold green)%(committerdate:relative)|%(color:blue)%(subject)|%(color:magenta)%(authorname)%(color:reset)" --color=always
ZenoArrow
  • 367
  • 2
  • 15
3

This is based on saeedgnu's version, but with the current branch shown with a star and in color, and only showing anything that is not described as "months" or "years" ago:

current_branch="$(git symbolic-ref --short -q HEAD)"
git for-each-ref --sort=committerdate refs/heads \
  --format='%(refname:short)|%(committerdate:relative)' \
  | grep -v '\(year\|month\)s\? ago' \
  | while IFS='|' read branch date
    do
      start='  '
      end=''
      if [[ $branch = $current_branch ]]; then
        start='* \e[32m'
        end='\e[0m'
      fi
      printf "$start%-30s %s$end\\n" "$branch" "$date"
    done
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Mark Lodato
  • 41,133
  • 5
  • 39
  • 31
2

My best result as a script:

git for-each-ref --sort=-committerdate refs/heads/ --format='%(refname:short)|%(committerdate:iso)|%(authorname)' |
    sed 's/refs\/heads\///g' |
    grep -v BACKUP  | 
    while IFS='|' read branch date author
    do 
        printf '%-15s %-30s %s\n' "$branch" "$date" "$author"
    done
saeedgnu
  • 3,434
  • 2
  • 26
  • 41
2

The accepted command-line answer rocks, but if you want something prettier, like a GUI, and your origin === "github".

You can click "Branches" in the repository. Or hit the URL directly: https://github.com/ORGANIZATION_NAME/REPO_NAME/branches

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
jahrichie
  • 1,144
  • 2
  • 16
  • 24
2

git branch --sort=-committerdate | head -5

For any one interested in getting just the top 5 branch names sorted based on committer date.

unknownerror
  • 1,755
  • 1
  • 18
  • 21
2

Simplest one to print along with last commit date:

git branch --all  --format='%(committerdate:short) %(refname:short)'|sort
Saurav Sahu
  • 9,755
  • 5
  • 42
  • 64
2
git for-each-ref --sort=-committerdate refs/heads/

# Or using git branch (since version 2.7.0)
git branch --sort=-committerdate  # DESC
git branch --sort=committerdate  # ASC
Ikbel benab
  • 855
  • 9
  • 24
1

Here's the variation I was looking for:

git for-each-ref --sort=-committerdate --format='%(committerdate)%09%(refname:short)' refs/heads/ | tail -r

That tail -r reverses the list so the most-recent commiterdate is last.

Ben
  • 6,598
  • 1
  • 34
  • 41
1

I pipe the output from the accepted answer into dialog, to give me an interactive list:

#!/bin/bash

TMP_FILE=/tmp/selected-git-branch

eval `resize`
dialog --title "Recent Git Branches" --menu "Choose a branch" $LINES $COLUMNS $(( $LINES - 8 )) $(git for-each-ref --sort=-committerdate refs/heads/ --format='%(refname:short) %(committerdate:short)') 2> $TMP_FILE

if [ $? -eq 0 ]
then
    git checkout $(< $TMP_FILE)
fi

rm -f $TMP_FILE

clear

Save as (e.g.) ~/bin/git_recent_branches.sh and chmod +x it. Then git config --global alias.rb '!git_recent_branches.sh' to give me a new git rb command.

1

I know there are a lot of answers already, but here are my two cents for a simple alias (I like to have my most recent branch at the bottom):

[alias]
        br = !git branch --sort=committerdate --color=always | tail -n15
[color "branch"]
        current = yellow
        local = cyan
        remote = red

This will give you a nice overview of your latest 15 branches, in color, with your current branch highlighted (and it has an asterisk).

Tom
  • 2,529
  • 1
  • 22
  • 33
1

Had some trouble handling single quotes on Mac in bash_profile when trying to set an alias. This answer helped resolve it " How to escape single quotes within single quoted strings

Working solution:

alias gb='git for-each-ref --sort=committerdate refs/heads/ --format='"'"'%(HEAD) %(color:yellow)%(refname:short)%(color:reset) - %(color:red)%(objectname:short)%(color:reset) - %(contents:subject) - %(authorname) (%(color:green)%(committerdate:relative)%(color:reset))'"'"''

P.S. Could not comment because of my reputation

0

git for-each-ref --sort=committerdate refs/heads/ --format='%(HEAD) %(color:yellow)%(refname:short)%(color:reset) - %(color:red)%(objectname:short)%(color:reset) - %(contents:subject) - %(authorname) (%(color:green)%(committerdate:relative)%(color:reset))' this is that you need

ChunkCoder
  • 147
  • 1
  • 2
  • 10
0

Git v2.19 introduces branch.sort config option (see branch.sort).

So git branch will sort by committer date (desc) by default with

# gitconfig
[branch]
    sort = -committerdate     # desc

script:

$ git config --global branch.sort -committerdate

Update:

So,

$ git branch
* dev
  master
  _

and

$ git branch -v
* dev    0afecf5 Merge branch 'oc' into dev
  master 652428a Merge branch 'dev'
  _      7159cf9 Merge branch 'bashrc' into dev
hIpPy
  • 3,702
  • 5
  • 41
  • 57