如何获取按最近提交排序的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个回答

26
其他答案似乎不支持传递-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 patch
2013-09-11 * (detached from 3eba4b8) 3eba4b8 Some other patch
2013-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 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-

这应该也适用于其他 git branch 命令的参数,例如 -vvr 以列出远程跟踪分支,或 -vva 以列出本地和远程跟踪分支。


-vv确实很有用,谢谢。然而,这个解决方案仍然为每个分支生成新的进程,而原帖中的作者想要避免这种情况。 - musiphil
实际上,git branch并没有明确定义-vv的含义,只有-v有定义,因此-vv应该与-v相同。 - musiphil
3
这是最好的。添加 -avv 命令可以考虑远程分支。谢谢! - Gopherkhan
@musiphil 我的_git分支_手册,章节-v,-vv,--verbose包含以下内容: 如果给定两次,则打印上游分支的名称。 - Perleone
@Perleone:我不知道我是怎么得到那个信息的,但你是对的,我改正我的错误。谢谢! - musiphil
这是我唯一可用的方法,因为我使用的是一个旧版本的 Git(在工作中)。我添加了 -r -vv 以使其能够远程工作,这产生了与 -avv-rvv 稍有不同的日期响应。 - MrChick

24

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

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

这将列出最新的10个分支。它很简短,也可以不使用别名。


git config --global alias.br "! git branch --sort=-committerdate | head -n 10" - mfink

22
获取根据提交者日期排序的前五个分支名称:
```git branch --sort=-committerdate | head -5```

21

我喜欢使用相对日期并缩短分支名称,就像这样:

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

这会给你输出:

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

我建议创建一个 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)$|$"

这给了我 fatal: unknown field name: '-authordate:iso8601' - Factor Mystic
2
花哨的彩色输出很漂亮,但这个简单的输出正是我想要的。将 refs/heads 替换为 refs/remotes 可以查看远程分支。 - Lambart
该命令本身很好用,但是别名出现错误:“扩展别名 'branches' 失败;'echo'不是 git 命令。” - Philip Kahn
对我来说可以。如果你只是将此内容复制粘贴到终端中会发生什么?(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

12

添加了一些颜色(因为 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"

12
我想到了以下命令(适用于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  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

我写了一篇关于各种组件如何工作的博客文章。你可以在这里查看。


不错。+1。它确实使用了我在 https://dev59.com/wG435IYBdhLWcg3w1juV#33163401 中提到的 git branch --sort - VonC
@DanNissenbaum 请确保您正在使用Git 2.13(于2017年5月发布)或更高版本。 - bdesham

10

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

因此,git branch 默认按提交者日期(降序)排序。

# gitconfig
[branch]
    sort = -committerdate     # Descending

脚本:

git config --global branch.sort -committerdate

所以,
git branch

输出:

* dev
  master
  _

并且

git branch -v

输出:

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

9

如果你想获取最近检出的分支列表(而不是最近提交的分支列表),可以使用Git的reflog功能:

提示:reflog是Git用于记录本地仓库中HEAD引用历史记录的命令,它记录了本地仓库的所有提交、检出和重置等操作。

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

另请参阅:如何获取我最近检出的Git分支列表?


(注:该链接为英文内容)

9

我曾经也遇到同样的问题,所以我写了一个叫做Twig的Ruby宝石。它按时间顺序列出分支(最新的在前面),还可以让您设置最大年龄,这样您就不会列出所有分支(如果您有很多分支)。例如:

$ 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

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

5
这个名字可能不太有帮助,因为我相当确定市场上已经有几款软件使用了同样的名称。 - thoroc

7

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

#!/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

使用这两个别名:

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个),并在旁边标识一个编号。输入分支号码,即可切换到该分支:

Enter image description here


请查看 *为什么在提问时不上传代码/错误的图片?(例如,"只有无法用其他方式清晰表达问题时才应使用图片,例如提供用户界面的截图。"*),并采取适当的行动(它也涵盖了回答)。 - Peter Mortensen

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