如何获取按最近提交排序的Git分支列表?

我想获取Git存储库中所有分支的列表,其中“最新”分支位于顶部,其中“最新”分支是最近提交的分支(因此,更有可能是我想要关注的分支)。

有没有一种方法可以使用Git(a)按最新提交对分支列表进行排序,或者(b)以某种机器可读的格式获取分支列表以及每个分支的最后提交日期?

最坏的情况是,我总是可以运行git branch来获取所有分支的列表,解析其输出,然后为每个分支运行git log -n 1 branchname --format=format:%ci来获取每个分支的提交日期。但这将在Windows机器上运行,在那里启动一个新进程相对昂贵,因此如果有很多分支,每个分支启动一次Git可执行文件可能会很慢。有没有办法用一个命令完成所有这些?

602468 次浏览

使用#1#0选项;

也可用于#0从git 2.7.0开始

基本用法:

git for-each-ref --sort=-committerdate refs/heads/
# Or using git branch (since version 2.7.0)git branch --sort=-committerdate  # DESCgit branch --sort=committerdate  # ASC

结果:

结果

高级用法:

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))'

结果:

结果

专业用法(Unix):

您可以将以下代码段放在~/.gitconfig中。recentb别名接受两个参数:

  • refbranch:计算前面背后列的分支。默认大师
  • count:显示多少个最近的分支。默认20
[alias]# ATTENTION: All aliases prefixed with ! run in /bin/sh make sure you use sh syntax, not bash/zsh or whateverrecentb = "!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:-origin/master}..${branch}\"); behind=$(git rev-list --count \"${branch}..${refbranch:-origin/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"

结果:

最近的别名结果

以下是最佳代码,它结合了其他两个答案:

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

这是一个简单的命令,列出了所有最新提交的分支:

git branch -v

要按最近提交排序,请使用

git branch -v --sort=committerdate

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

我也遇到了同样的问题,所以我写了一个名为树枝的Ruby gem。它按时间顺序列出分支(最新的先),还可以让您设置最大年龄,这样您就不会列出所有分支(如果您有很多分支)。例如:

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

它还允许您存储每个分支的自定义属性,例如票证ID、状态、待办事项,并根据这些属性过滤分支列表。更多信息:http://rondevera.github.io/twig/

我最好的剧本:

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 authordoprintf '%-15s %-30s %s\n' "$branch" "$date" "$author"done

这是基于saeedgnu的版本,但当前分支以星形和颜色显示,并且仅显示未被描述为“月”或“年”前的任何内容:

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 datedostart='  'end=''if [[ $branch = $current_branch ]]; thenstart='* \e[32m'end='\e[0m'fiprintf "$start%-30s %s$end\\n" "$branch" "$date"done

我还需要颜色,标签和远程引用,没有任何重复:

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]++'

因为引用可能很难,这里是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'"]++'"

其他答案似乎不允许传递-vv来获得详细的输出。

所以这是一个单行代码,它根据提交日期、保留颜色等对git branch -vv进行排序:

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

如果您还想打印提交日期,您可以改用此版本:

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-

示例输出:

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

它可能更具可读性,分为多行:

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 thislocal 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 datedone | sort -r | cut -d ' ' -f -1,4-

这也应该与git branch的其他参数一起使用,例如-vvr列出远程跟踪分支,或-vva列出远程跟踪和本地分支。

添加一些颜色(因为pretty-format不可用)

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

这是另一个脚本,它做了所有其他脚本所做的事情。事实上,它为您的shell提供了一个函数。

它的贡献是它从您的Git配置中提取一些颜色(或使用默认值)。

# 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/headslocal branch_color=`git config --get-color color.branch.local white`
if [ "$1" = -r ]thentarget=refs/remotes/originbranch_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}"}

这是我正在寻找的变化:

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

tail -r反转列表,因此最近的commiterdate是最后一个。

我喜欢使用相对日期并缩短分支名称,如下所示:

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

它为您提供输出:

21 minutes ago  nathan/a_recent_branch6 hours ago     master27 hours ago    nathan/some_other_branch29 hours ago    branch_c6 days ago      branch_d

我建议制作一个Bash文件来添加所有您喜欢的别名,然后将脚本共享给您的团队。这是一个仅添加此示例的示例:

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

然后,您可以这样做以获得格式良好且排序良好的本地分支列表:

git branches

更新:如果您想要着色,请执行此操作:

#!/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)$|$"

接受的命令行答案很棒,但是如果你想要更漂亮的东西,比如GUI,你的起源==="github"。

您可以单击存储库中的“分支”。或者直接点击URL:https://github.com/ORGANIZATION_NAME/REPO_NAME/branches

仅供参考,如果您想获取最近退房分支的列表(而不是最近提交的),您可以使用Git的reflg:

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

另见:如何获取我最近签出的Git分支列表?

我使用以下别名:

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"

它产生:

结果

我们也可以给出一个自定义计数,例如,

git recent 20(默认值为10)。

git 2.7(2015年第四季度)将直接使用git branch引入分支排序:
提交aa3bc55提交aedcb7d提交1511b22提交f65f139,…(2015年9月23日),提交aedcb7d提交1511b22提交ca41799(2015年9月24日),和提交f65f139,…(2015年9月23日)通过Karthik Nayak(#0)(由Junio C Hamano----#0----合并于提交7f11b48,2015年10月15日)

特别是提交aedcb7d

branch.c:使用“ref-filter”API

让'branch.c'使用'ref-filter'API来迭代引用排序。这删除了'branch.c'中使用的大部分代码来替换它

添加选项#0

根据给定的键进行排序。
前缀-按值的降序排序。

您可以多次使用--sort=<key>选项,在这种情况下,最后一个键将成为主键。

支持的键是与#0相同
排序顺序默认为基于完整的引用名(包括refs/...前缀)进行排序。这首先列出分离的HEAD(如果存在),然后列出本地分支,最后列出远程跟踪分支。

这里:

git branch --sort=-committerdate

或者(见下面的Git 2.19)

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

另见提交9e46833(2015年10月30日)byKarthik Nayak(#0)
帮助方式:Junio C Hamano(#0).
(由Junio C Hamano----#0----合并于提交415095f,03 Nov 2015)

当按数值排序时(例如--sort=objectsize),当两个引用都持有相同的值时,没有回退比较。这可能会导致意想不到的结果(即无法预先确定列出具有相同值的引用的顺序),正如Johannes Symt($gmane/280117)所指出的。

因此,回退到基于引用名的字母顺序比较当其他条件相等时

$ git branch --sort=objectsize
*  (HEAD detached from fromtag)branch-twobranch-onemaster

在Git 2.19中,可以默认设置排序顺序。
git branch支持配置branch.sort,比如git tag,它已经有了配置tag.sort
提交560ae1c(2018年8月16日)by塞缪尔·马夫图尔(").
(由Junio C Hamano----#0----合并于提交d89db6f,27 Aug 2018)

branch.sort:

此变量控制git-branch显示时分支的排序顺序。
如果没有提供“--sort=<value>”选项,则此变量的值将被用作默认值。


要列出远程分支,请使用git branch -r --sort=objectsize-r标志使其列出远程分支而不是本地分支。


在Git 2.27(2020年第二季度)中,“git branch”和其他“for-each-ref”变体以递增的优先级接受了多个--sort=<key>选项,但它在“--ignore-case”处理方面有一些破坏,并且与引用名打破平局,这些已经修复。

提交7c5045f提交76f9e56(2020年5月3日)by杰夫·金(#0)
(由提交6de1630中的Junio C Hamano----#0----合并,2020年5月8日)

#0:仅在所有用户排序后应用回退引用名排序

签名人:Jeff King

提交9e468334b4(“ref-filter:按字母顺序比较的回退”,2015-10-30,Git v2.7.0-rc0-批次#10中列出的合并)教授了ref-filter的排序回退到比较引用名。
但是它在错误的级别上做了,覆盖了用户单个“--sort”键的比较结果,而不是在所有排序键都用完之后。

这对于单个“--sort”选项正确工作,但对于多个选项无效。
我们将使用refname断开第一个键中的任何联系,并且根本不会评估第二个键。

为了让事情更有趣,我们有时只应用这个后备!
对于像“taggeremail”这样需要字符串比较的字段,我们会真正返回strcmp()的结果,即使它是0。
但是对于像“taggerdate”这样的数字“value”字段,我们确实应用了回退。这就是为什么我们的多重排序测试错过了这一点:它使用taggeremail作为主要比较。

所以让我们从添加一个更严格的测试开始。我们将有一组提交来表达两个标记器电子邮件、日期和重命名的每个组合。然后我们可以确认我们的排序以正确的优先级应用,我们将击中字符串和值比较器。

这确实显示了bug,修复很简单:在所有ref_sorting键都用完后,将回退移动到外部compare_refs()函数。

请注意,在外部函数中,我们没有"ignore_case"标志,因为它是每个ref_sorting元素的一部分。由于我们没有使用用户的键来匹配,因此这样的后备应该做什么是有争议的。
但到目前为止,我们一直在努力尊重这面旗帜,所以侵入性最小的事情就是继续这样做。由于当前代码中的所有调用者要么为所有键设置标志,要么为所有键设置标志,我们可以从第一个键中提取标志。在一个假设的世界中,用户真的可以单独翻转键的大小写不敏感,我们可能希望扩展代码以将大小写与一揽子“--ignore-case”区分开来。


分离的HEAD显示的“#0man)的实现一直很老套,Git 2.31(2021年第一季度)已经清理了这一点。

提交4045f65提交2708ce6提交7c269a7提交d094748提交75c50e5(2021年1月7日),和提交08bf6a8提交ffdd02a(2021年1月6日)by阿尔法约尔比亚尔马森(#0)(2021年1月25日,被提交9e409d7中的Junio C Hamano----#0----合并)

#0:在逆向排序下首先显示“HEAD devted”

签字人:埃瓦尔·阿恩菲约尔·比亚尔马森

更改“#0man)之类的输出以在输出开始时显示“(HEAD detached at <hash>)”消息。
在前面的提交中添加compare_detached_head()函数之前,我们会将此输出作为紧急效果发出。

为了排序的目的,考虑“(HEAD detached at <hash>)”消息的对象大小、类型或其他非属性是没有任何意义的。
让我们总是在顶部发射它。
它首先被排序的唯一原因是因为我们将它注入了ref-filter机器,所以#0不需要自己做“我分离了吗?”检测。


在Git 2.35(2022年第一季度)中,像“#0man)这样的东西,即
#0man)命令的操作模式不需要排序键信息,不再因看到伪排序键而出错。

提交98e7ab6提交1a89796(2021年10月20日)byJunio C Hamano(#0)
(2021年11月29日提交5126145合并Junio C Hamano----#0----

#0:延迟解析--sort=<atom>选项

for-each-ref系列命令在看到每个--sort=<atom>选项时立即调用解析器,当<atom>无法识别时,甚至在看到命令行上的其他选项之前死亡。

相反,将它们累积在字符串列表中,并在命令行解析完成后将它们解析为ref_sorting结构。
因此,“#0man)过去无法提供简短的帮助,这可能是一个功能,现在这样做了,这与其他选项的工作方式更一致。

我将接受的答案的输出输送到dialog,给我一个交互式列表:

#!/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 ]thengit checkout $(< $TMP_FILE)fi
rm -f $TMP_FILE
clear

保存为(例如)~/bin/git_recent_branches.shchmod +x它。然后git config --global alias.rb '!git_recent_branches.sh'给我一个新的git rb命令。

这是我用来在最近的分支之间切换的一个小脚本:

#!/bin/bash# sudo bash
re='^[0-9]+$'
if [[ "$1" =~ $re ]]; thenlines="$1"elselines=10fibranches="$(git recent | tail -n $lines | nl)"branches_nf="$(git recent-nf | tail -n $lines | nl)"echo "$branches"
# Prompt which server to connect tomax="$(echo "$branches" | wc -l)"index=while [[ ! ( "$index" =~ ^[0-9]+$ && "$index" -gt 0 && "$index" -le "$max" ) ]]; doecho -n "Checkout to: "read indexdone
branch="$( echo "$branches_nf" | sed -n "${index}p" | awk '{ print $NF }' )"git co $branchclear

使用这两个别名:

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)'

只需在Git存储库中调用它,它将向您显示最后N个分支(默认为10个)和每个分支的数字。输入分支的编号,它就会检查出来:

在此输入图片描述

我能够参考前面的例子来创建最适合我的东西。

git for-each-ref--sort=-提交日期引用/头(%(颜色:绿色)%(提交日期:相对)%(颜色:重置))'

输出截图

正如下面的注释所建议的,您还可以包含远程分支和作者姓名。

git for-each-ref--sort=-提交日期引用/头引用/远程引用(%(颜色:绿色)%(提交日期:相对)%(颜色:重置))%(作者名)'

输出截图

以下两个命令都是shell别名,您可以轻松地将其添加到shell配置文件中。

# show a list of local git branches sorted by the commit datealias git.branches='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))"'
# show a list of local and remote git branches sorted by the commit datealias git.branches.remote='git for-each-ref --sort=-committerdate refs/heads refs/remotes --format="%(authordate:short) %(color:red)%(objectname:short) %(color:yellow)%(refname:short)%(color:reset) (%(color:green)%(committerdate:relative)%(color:reset)) %(authorname)"'

我想出了以下命令(适用于Git 2.13及更高版本):

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

如果您没有column,您可以将最后一行替换为

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

输出看起来像

6 years ago             Tom Preston-Werner  book4 years, 4 months ago   Parker Moore        0.12.1-release4 years ago             Matt Rogers         1.0-branch3 years, 11 months ago  Matt Rogers         1.2_branch3 years, 1 month ago    Parker Moore        v1-stable12 months ago           Ben Balter          pages-as-documents10 months ago           Jordon Bedwell      make-jekyll-parallel6 months ago            Pat Hawks           to_integer5 months ago            Parker Moore        3.4-stable-backport-59204 months ago            Parker Moore        yajl-ruby-2-4-patch4 weeks ago             Parker Moore        3.4-stable3 weeks ago             Parker Moore        rouge-1-and-219 hours ago            jekyllbot           master

我写了一篇博客文章关于各个部分是如何工作的。

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))'这是你需要的

从Git 2.19开始,您可以简单地:

git branch --sort=-committerdate

您还可以:

git config branch.sort -committerdate

因此,每当您在当前存储库中列出分支时,它将按提交日期排序。

如果每当您列出分支时,您希望它们按comitterdate排序:

git config --global branch.sort -committerdate

免责声明:我是Git中此功能的作者,当我看到这个问题时,我实现了它。

git v2.19引入了branch.sort配置选项(参见branch.sort)。

所以git branch将默认按提交者日期(降序)排序

# gitconfig[branch]sort = -committerdate     # Descending

脚本:

git config --global branch.sort -committerdate

所以,

git branch

输出:

* devmaster_

git branch -v

输出:

* dev    0afecf5 Merge branch 'oc' into devmaster 652428a Merge branch 'dev'_      7159cf9 Merge branch 'bashrc' into dev

仅根据提交者日期对前五个分支名称进行排序:

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

我知道已经有很多答案了,但这是我对一个简单别名的两分钱(我喜欢在底部有我最近的分支):

[alias]br = !git branch --sort=committerdate --color=always | tail -n15[color "branch"]current = yellowlocal = cyanremote = red

这将给你一个很好的概述你最新的15个分支,以颜色显示,突出显示你当前的分支(它有一个星号)。

通常我们最近会考虑偏远的分支。所以试试这个

git fetchgit for-each-ref --sort=-committerdate refs/remotes/origin

与最后提交日期一起打印的最简单的一个:

git branch --all  --format='%(committerdate:short) %(refname:short)'|sort

另一个变化:

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'|'

值得注意的是,即使它正在查看远程分支中的更改,在运行命令之前也值得与起源同步(您可以使用Git get ch),因为我发现如果您的本地Git文件夹有一段时间没有更新,它可能会返回过时的信息。

此外,这是一个适用于WindowscmdPowerShell的版本:

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
git for-each-ref --sort=-committerdate refs/heads/
# Or using Git branch (since version 2.7.0)git branch --sort=-committerdate  # Descendinggit branch --sort=committerdate  # Ascending

我发现以下命令对我的目的很有帮助。

git branch --sort=-committerdate | head -n 10

这将列出最新10个分支。它很短,也可以在没有别名的情况下使用。