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

1970
我想要获取一个Git仓库中所有分支的列表,并将“最新”的分支排在前面,其中“最新”的分支是最近提交的分支(因此更可能是我想要关注的分支)。
是否有一种方法可以使用Git来按照最新提交对分支列表进行排序,或者以某种机器可读的格式获取包括每个分支的最后提交日期的分支列表?
最坏情况下,我可以始终运行“git branch”以获取所有分支的列表,解析其输出,然后为每个分支运行“git log -n 1 branchname --format=format:%ci”以获取每个分支的提交日期。但这将在Windows环境中运行,其中启动新进程相对较昂贵,因此如果有很多分支,每个分支启动一次Git可执行文件可能会变慢。是否有一种方法可以用单个命令完成所有这些操作?

3
有更好的答案。 - Spundun
18
@Spundun,你让我有些摸不着头脑。使用包括通过perl和sed的管道传输的多个命令组合,“比”使用Git已经具备的命令“更好”,这是怎么回事? - Joe White
50
关于Jakub Narębski提供的使用git for-each-ref命令的答案,您可以通过传递refs/remotes/(而不是refs/heads/)来获取远程分支(或者您可以同时传递两者,用空格隔开);对于标签,请使用refs/tags/,要获取所有三种引用,则可以使用refs/ - jakub.g
10
自从Git 2.7(2015年第四季度)开始,就不再使用for-each-ref命令了!您应该直接使用git branch --sort=-committerdate命令:请参见我的回答 - VonC
1
@JoeWhite 它仍然可用,但其语义的一部分将直接从 git 分支本身访问。 - VonC
显示剩余5条评论
32个回答

2759

使用 git for-each-ref 命令的 --sort=-committerdate 选项;

自 Git 2.7.0 起git branch 命令也可用此选项:

基本用法:

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

结果:

结果

高级用法:

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: 用于计算 aheadbehind 列的分支名称。默认为 master
  • count: 显示最近多少个分支。默认为 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:-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"

结果:

Recentb别名结果


17
太好了!我甚至可以通过添加“--format=%(refname)”来限制输出仅为引用名称。 - Joe White
40
这是更适合我的命令:git for-each-ref --sort=-committerdate refs/heads/ --format='%(refname) %(committerdate) %(authorname)' | sed 's/refs\/heads\///g'。这个命令可以按提交时间从新到旧的顺序列出所有本地分支的名称、最近的提交时间和作者名字,并使用sed命令去掉分支名前面的"refs/heads/"前缀。 - saeedgnu
38
如@BeauSmith所写:git for-each-ref --sort=-committerdate --format='%(refname:short)' refs/heads/。 git-for-each-ref(1)手册说:如果想要非歧义的引用名称,请附加:short - Jakub Narębski
93
这是一份彩色化的版本,其中包括哈希值、消息以及根据提交日期升序排序的顺序,并且每个分支上最后一次提交的相对年龄。我从以上你们所有人那里偷走了所有想法。它在我的.gitconfig文件中的[alias]部分,并且我很喜欢它。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
3
主要是这些内容和Git日志着色方面的问题,但如果你真的想知道,请参阅:https://github.com/mpercy/Dotfiles/blob/master/gitconfig :) - Michael Percy
显示剩余33条评论

161

按最近提交时间排序的 Git 分支名称列表...

继承 Jakub 的答案 Joe的提示,以下命令将剥离“refs/heads/”,以便输出仅显示分支名称:


命令:

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

结果:

最近的Git分支


9
有没有办法对远程仓库执行这个操作? - Allan Bowe
15
@aah - @jakub.g已经解释了:您可以使用refs/remotes/而不是refs/heads/来获取远程分支。完美! - Allan Bowe
我喜欢这个命令,如果你想给它起别名(就像我一样),记得要用引号把命令括起来:git config --global alias.rb "for-each-ref --count=20 --sort=-committerdate refs/heads/ --format=\'%(refname:short)\'" - Michael Discenza
7
现在,您可以使用git branch来获取本地、远程或所有分支,就像在git-branch上一样(例如-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))' - Phil Hord
为了对齐结果,您可以使用制表符(%09)而不是-;然后将其导入列中。因此,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
1
@AllanBowe 以下命令会输出存储库中前5个活跃分支:git branch -va --sort=committerdate | tail -5。也许这是你要求和发现的另一种选择。 - marckassay

155

20
如果您想要查看非本地分支,可以使用 git branch -av 命令。 - Scott Stafford
8
git branch -v 命令在列出的每个提交记录后面包含日期信息容易吗? - dumbledad
9
太棒了!我喜欢使用git branch -va --sort=-committerdate命令展示非本地分支,并将最近更改的分支显示在前面。 - Clinton Blackmore
6
git branch -v --format='%(committerdate:short) %(refname:short)' 包括日期信息。 - Teepeemm
对于那些从搜索引擎过来的人,是的,committerdate 将会捕捉到您修改或变基的最后时间。(另一个可能性是 authordate,默认情况下 amendrebase 不会更改它。) - Chris Chiasson

102

这里是最优代码,结合了其他两个答案:

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

11
为了获得表格输出,可以稍微优化一下:git for-each-ref --sort=-committerdate refs/heads/ --format='%(committerdate:short)\t%(authorname)\t%(refname:short)' - schoetbi
5
由于某种原因,我必须在 Windows 上使用双引号,但除此之外,这些完全正常 :) - amenthes
1
@schoetbi,这段代码看起来和 Nikolay 的一模一样,你改了什么使它变成表格形式的? - Enrico
1
@Enrico和其他可能有同样疑问的人。Nikolay使用Schoetbi的建议修改了他的答案。通过先移动日期,因为日期长度始终相同,结果看起来更加表格化。 - johnny

97

我使用以下别名:

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"

它会产生以下结果:

Result

我们还可以自定义计数,例如:

git recent 20(默认为10)。


4
在最新版本的Git中,你可以在格式字符串的开头添加'%(HEAD) ...',以获得相同的效果,而无需通过管道传递sed命令。 - Joshua Skrzypek
6
我无法将此内容作为Git别名工作,我必须使用以下命令:[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
16
我必须添加 "--color=always" 才能获得颜色。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
5
对我而言,在大括号内放置一个分号可以帮助!r(){git for-each-ref ... ;}; r - Karl Bartel
4
我还需要在 -ts'|' 后面加上一个分号,即 "!r(){ git ... -ts'|'; }; r" - Emmanuel N K
显示剩余14条评论

83

我能够参考之前的示例创建最适合我的东西。

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

输出屏幕截图

如下评论所建议,你也可以包括远程分支和作者名称。

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

输出屏幕截图

以下是两个命令作为 shell 别名,你可以轻松地将它们添加到你的 shell 配置文件中。

# show a list of local git branches sorted by the commit date
alias 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 date
alias 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)"'

1
看起来不错,比我在 https://dev59.com/wG435IYBdhLWcg3w1juV#33163401 中建议的直接使用 git 分支更加丰富多彩。+1 - VonC
谢谢,@VonC,很高兴你喜欢它! - Andrew
1
同上 - 这个可以直接使用,不像其他一些我尝试过的需要调整。谢谢。 - Dan Nissenbaum
11
这个命令整洁明了。有时我会加上远程分支和提交者名字,如下所示: 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
1
像这样的!干净简洁,谢谢。 :) - dmitryb
请查看 *为什么在提问时不上传代码/错误的图片?(例如,"图片应该只用于说明无法以其他方式清晰表达的问题,例如提供用户界面的截图。"*),并采取适当的行动(它也涵盖了答案和屏幕输出)。 - Peter Mortensen

47

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 (KarthikNayak)完成。
(由Junio C Hamano -- gitster --提交 7f11b48中合并,2015年10月15日)

具体来说, 提交 aedcb7d

branch.c:使用 'ref-filter' API

使 'branch.c' 使用 'ref-filter' API 迭代引用排序。这将删除 'branch.c' 中使用的大部分代码,并将其替换为调用 'ref-filter' 库。

添加选项 --sort=<key>

基于给定的关键字进行排序。
在关键字前加上前缀-,可以按值的降序排序。
您可以多次使用--sort=<key>选项,最后一个关键字将成为主关键字。
支持的关键字与git for-each-ref中的相同(链接)
默认情况下,排序顺序基于完整的引用名称(包括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 -committerdate
git branch

另请参见提交9e46833(2015年10月30日)由Karthik Nayak (KarthikNayak)完成。
协助者:Junio C Hamano (gitster)
(由Junio C Hamano -- gitster --合并于提交415095f,2015年11月03日)

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

从Git 2.19开始,可以默认设置排序顺序。
git branch支持一个配置branch.sort,就像git tag一样,它已经有了一个配置tag.sort
请参见commit 560ae1c (2018年8月16日)由Samuel Maftoul (``)提交的更改。
(由Junio C Hamano -- gitster --commit d89db6f中合并)

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" 和与 refname 并列时出现了一些问题,这些问题已经得到了解决。

查看提交 7c5045f提交 76f9e56(2020年5月3日)由Jeff King (peff)完成。
(由Junio C Hamano -- gitster --提交 6de1630中合并,2020年5月8日)

ref-filter:仅在所有用户排序后应用回退引用名称排序

签名作者:Jeff King

Commit 9e468334b4 ("ref-filter:回退到字母比较", 2015-10-30, Git v2.7.0-rc0 - 合并批次#10中列出) 教授了ref-filter的排序,使其回退到比较refnames。但是它在错误的级别上执行,覆盖了用户单个"--sort"键的比较结果,而不是在所有排序键用完后执行。这对于单个"--sort"选项有效,但对于多个选项无效。我们会在第一个键中使用refname打破任何平局,并且根本不评估第二个键。更有趣的是,我们只有在某些情况下应用此回退! 对于像"taggeremail"这样需要字符串比较的字段,我们确实会返回strcmp()的结果,即使它为0。但是对于类似于"taggerdate"的数字"value"字段,我们会应用回退。这就是为什么我们的多重排序测试错过了它的原因:它使用taggeremail作为主要比较。因此,让我们首先添加一个更加严格的测试。我们将拥有一组提交,表达两个tagger电子邮件、日期和refnames的每个组合。然后,我们可以确认我们的排序应用了正确的优先级,并且我们将同时使用字符串和值比较器。这确实显示了错误,修复很简单:将回退移动到外部compare_refs()函数,在所有ref_sorting键用完后执行。请注意,在外部函数中,我们没有一个"ignore_case"标志,因为它是每个单独的ref_sorting元素的一部分。这样的回退应该做什么是有争议的,因为我们没有使用用户的键进行匹配。但是直到现在,我们一直在尝试尊重该标志,因此最不侵入性的事情是继续这样做。由于当前代码中的所有调用者都将标志设置为所有键或没有键,因此我们只需从第一个键中提取标志即可。在假设的世界中,用户确实可以分别翻转键的大小写敏感性,我们可能需要扩展代码以区分该情况和毯式"--ignore-case"。

"git branch --sort"(man) 命令的实现与分离 HEAD 显示一直很不完美,但在 Git 2.31 (2021年第一季度) 中已经得到了改进。

请查看 提交记录 4045f65, 提交记录 2708ce6, 提交记录 7c269a7, 提交记录 d094748, 提交记录 75c50e5(2021年1月7日),以及提交记录 08bf6a8, 提交记录 ffdd02a(2021年1月6日),作者为Ævar Arnfjörð Bjarmason (avar)
(于2021年1月25日由Junio C Hamano -- gitster合并至提交记录 9e409d7

分支:在反向排序下首先显示“HEAD detached”

签名:Ævar Arnfjörð Bjarmason

将类似 "git branch -l --sort=-objectsize"(man) 的输出更改为在输出开头显示 "(HEAD detached at <hash>)" 消息。
在之前的提交中添加了 compare_detached_head() 函数之前,我们会将此输出作为紧急效果发出。
考虑到排序目的,"(HEAD detached at <hash>)" 消息的对象大小、类型或其他非属性都没有任何意义。
让我们始终在顶部发出它。
首先进行排序的唯一原因是因为我们将其注入到 ref-filter 机制中,因此 builtin/branch.c 不需要执行自己的"我是否分离?"检测。
使用Git 2.35(2022年第一季度),像 "git -c branch.sort=bogus branch new HEAD"(man) 这样的东西,即 "git branch"(man) 命令的操作模式不需要排序键信息,不再因为看到无效的排序键而出错。请注意保留HTML标签。

请查看 提交 98e7ab6, 提交 1a89796 (2021年10月20日) 由Junio C Hamano (gitster)提交。
(于2021年11月29日由Junio C Hamano -- gitster --合并到提交 5126145)

for-each-ref: 延迟解析--sort=<atom>选项

该命令会延迟解析--sort=<atom>选项。

for-each-ref 命令族在看到每个 --sort=<atom> 选项时立即调用解析器,如果 <atom> 无法识别,则甚至在看到命令行中的其他选项之前就会终止。

相反,将它们累积到一个字符串列表中,在命令行解析完成后将其解析为 ref_sorting 结构。
因此, "git branch --sort=bogus -h"(man) 以前无法提供简短帮助,这可能是一种特性,现在可以做到,这更符合其他选项的工作方式。


要使用此选项列出远程,请添加“-r”。 - Troy Daniels

44

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

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

awk:第1行附近语法错误 awk:第1行附近退出 - Jamie Mason
@GotNoSugarBaby,你是像例子一样使用单引号吗?你在使用哪个shell?否则Bash会赋予该字符特殊含义。 - estani
嘿,我在/bin/bash(GNU bash,版本4.0.28(1)-release(i386-pc-solaris2.11))上直接复制并粘贴您的示例运行了它 - 但自那以后,我已经在/bin/bash(GNU bash,版本3.2.48(1)-release(x86_64-apple-darwin12))上运行它,并且它可以工作,所以我会取消踩踏。非常感谢,estani。 - Jamie Mason
@GotNoSugarBaby 我使用的是 4.2.25(1)-release (x86_64-pc-linux-gnu) 版本,并在 3.x 上尝试过并且可以工作。我不确定问题是什么...但可能是与 Git 版本有关,而不是 bash 的问题。无论如何,我很高兴它能为你工作! - estani
1
@MichaelDiscenza 只需将所有内容导向 head。这意味着在末尾添加 | head -n20。如果您正在使用别名,请确保此命令在引号内部。 - estani
显示剩余3条评论

32

另一种变化:

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

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

此外,这是在Windows cmdPowerShell中工作的版本:

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

1
感谢您对Windows Cmd/Powershell的回答。我可以确认它在Cmder中也适用。 - Francis
如果你想要本地分支而不仅仅是已经被推送/同步到远程仓库的分支,就去掉 -r - Zach Young
1
谢谢,你也检查了远程分支,这正是我想要的! - Ninja

32

从Git 2.19开始,你可以简单地执行以下操作:

git branch --sort=-committerdate

你还可以:

git config branch.sort -committerdate

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

git config --global branch.sort -committerdate

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


3
最新的答案,远比使用复杂的脚本或别名更容易。 - mtefi
使用时要小心!大家要注意,这不是一个列出分支的命令。这是一个更改Git配置的命令,将会产生永久的全局影响。 - Jazimov
1
@Jazimov 你说得对,我编辑了答案以使其更清晰。 - smaftoul
谢谢您添加这个很棒的功能,@smaftoul,我经常使用它。; ) - theartofrain
1
@theartofrain 不客气,我也经常使用它 ;) - smaftoul

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接