Git分支按最后提交日期排序:三种实用命令详解
2026/9/11 13:17:14 网站建设 项目流程

最近在维护一个持续迭代的项目时,分支数量越堆越多,很多功能分支合并完之后并没有及时清理,本地残留了大量旧分支。想快速找出来“哪些分支已经几个月没人动”,结果发现git branch默认只按字母序显示分支名,完全看不出时间信息,甚至很难判断这些分支是活跃还是已经废弃。于是我把 Git 分支按最后提交日期排序的方法系统整理了一遍,这篇文章就是这次梳理的完整记录。

本文会覆盖三种主流做法:

  • git branch --sort=-committerdate:最简单直接的排序命令。
  • git for-each-ref --sort=-committerdate --format=...:更灵活的完整解决方案。
  • git log自行拼接排序:了解原理,方便自定义。

同时会讲清楚committerdateauthordatecreatordate的区别,以及如何结合筛选条件定位长时间未更新的“僵尸分支”。新手可以跟着从准备演示仓库开始操作,有经验的开发者可以直接跳到命令示例和最佳实践部分。

1. 为什么需要按提交日期排序分支?

1.1 分支多了之后的“失控感”

在多人协作的项目中,每个需求、每个 Bug 修复都可能开一个分支。随着迭代次数增加,分支列表会越来越长。

默认的git branch输出长这样:

$ git branch bugfix/payment feature/login feature/order * master

如果项目里只有 5 个分支,这样看没有问题。但当分支数量到达 30 个、50 个甚至更多时,仅凭分支名很难判断哪些分支还在活跃开发,哪些分支已经合并完但忘了删除。

尤其到了版本发布的节点,需要确认“哪些分支还没合并”“哪些分支最近已经废弃”,这时候最直观的指标就是“这个分支最后一次提交是什么时候”。按最后提交日期排序,本质上是在回答一个问题:这个分支到底还有没有人在维护。

1.2 “最后提交日期”到底指什么

Git 里的时间并不只有一种。

git log输出中,每次提交至少有两个时间概念:

  • author date:作者创建这次提交的时间。
  • committer date:提交者把这次提交写入当前分支/仓库的时间。

平时git log默认显示的时间,通常是作者时间。而在分支排序场景下,我们更关心的是“这个分支最后被更新到哪一刻”,对应的是committer date,因为通过 rebase、cherry-pick、apply patch 等操作后,committer date 会更新,更能反映这个分支当前指向的提交实际进入仓库的时间。

还需要注意一个容易混淆的概念:分支本身并不是一个“容器”,它只是一个指向某个提交的指针。所以“按分支最后提交日期排序”,本质是查看“每个分支指针指向的那次提交的 committer date”,然后按这个时间排序。这个理解对后面排查问题很有帮助。

还有一个概念是creatordate,它表示引用(ref)本身的创建或最后更新时间。针对分支这种引用,creatordate和它指向的提交关系比较密切,在多数使用场景下,我们直接按提交时间排序即可。

2. 环境准备与版本说明

2.1 本教程的验证环境

本文的命令在 Git 2.x 环境下验证通过,具体场景如下:

  • 操作系统:Linux / macOS 均可;Windows 用户建议使用 Git Bash 执行命令。
  • Git 版本:任意较新的 2.x 版本;git branch --sortgit for-each-ref --sort都属于长期存在的功能。
  • 终端编码:建议使用 UTF-8,避免中文分支名显示异常。

如果你还不确定自己电脑的 Git 版本,可以执行:

git --version

我本机测试时使用 Git 2.39 系列,如果你的项目环境版本较老,建议先升级再继续操作。

如果你的电脑还没有安装 Git,需要先完成安装和基础配置。这里简单提醒一下:Windows 可以从 Git 官网下载安装包,安装时保持默认选项即可;macOS 可以使用 Homebrew 安装:

brew install git

安装完成后,至少配置用户名和邮箱,否则 commit 操作会失败或提示缺失身份信息:

git config --global user.name "your name" git config --global user.email "you@example.com"

2.2 准备一个便于演示的仓库

为了能够看清楚排序效果,这里先创建一个包含多个分支、且不同分支提交时间有差异的测试仓库。

git init demo-branch-sort cd demo-branch-sort git config user.name "dev" git config user.email "dev@example.com" echo "# demo" > README.md git add . git commit -m "init project"

接着创建几个分支,并在每个分支上进行独立提交:

git checkout -b feature/login echo "login feature" > login.txt git add . git commit -m "add login feature" git checkout master git checkout -b feature/order echo "order feature" > order.txt git add . git commit -m "add order feature" git checkout master git checkout -b bugfix/payment echo "fix payment" > payment.txt git add . git commit -m "fix payment bug" git checkout master echo "update readme" >> README.md git add . git commit -m "update readme"

最终仓库里会有 4 个本地分支:

  • master:最后一次提交是 “update readme”。
  • feature/login:最后一次提交是 “add login feature”。
  • feature/order:最后一次提交是 “add order feature”。
  • bugfix/payment:最后一次提交是 “fix payment bug”。

由于每个分支都只提交了一次且时间点不同,方便后续观察排序结果。

3. 核心命令拆解:三种排序方式

下面我们一层一层把按最后提交日期排序的方案讲透。先看最省事的,再看最灵活的,最后讲一个“理解原理”的做法。

3.1 最简单的git branch --sort

这是日常使用中最直接的排序方式。

写法:

git branch --sort=-committerdate

在这个输出中,分支会按照“最后一次提交时间”倒序排列,最新提交的分支排在最上面:

$ git branch --sort=-committerdate * master bugfix/payment feature/order feature/login

如果去掉前面的减号,就变成正序排列:

git branch --sort=committerdate

在实际使用中,我们绝大部分场景都希望“越新的分支排越前面”,所以-committerdate是更常用的写法。

配合-v参数,可以同时看到每个分支的最新提交哈希和提交信息:

git branch -v --sort=-committerdate

输出示例:

* master a1b2c3d update readme bugfix/payment b2c3d4e fix payment bug feature/order c3d4e5f add order feature feature/login d4e5f6a add login feature

这里的哈希和提交信息只是演示,真实执行时以你仓库中的结果为准。git branch -v --sort特别适合日常快速浏览,因为它一行就能看出分支最后改了什么。

3.2 更灵活的git for-each-ref

git branch --sort虽然简单,但输出字段固定,无法自由控制显示内容、时间格式和排序键。如果需要把分支和时间信息输出为表格,或者方便脚本处理,推荐使用git for-each-ref

基础用法:

git for-each-ref --sort=-committerdate \ --format='%(committerdate:iso8601) | %(refname:short) | %(subject)' \ refs/heads

其中:

  • refs/heads表示只遍历本地分支引用。
  • %(committerdate:iso8601)是提交时间的 ISO8601 格式。
  • %(refname:short)是去掉了refs/heads前缀的短分支名。
  • %(subject)是该分支最新一次提交的第一行说明。

输出示例:

2025-01-06 10:23:45 +0800 | master | update readme 2025-01-06 10:12:30 +0800 | bugfix/payment | fix payment bug 2025-01-06 10:02:11 +0800 | feature/order | add order feature 2025-01-05 18:20:09 +0800 | feature/login | add login feature

注意:上面示例里显示的时间是我为了演示补充的说明文字,实际执行时看到的时间取决于你仓库里的真实提交时间。

如果你想让人一眼看出分支多久没更新,可以把时间格式改成相对时间:

git for-each-ref --sort=-committerdate \ --format='%(committerdate:relative) | %(refname:short) | %(subject)' \ refs/heads

输出示例:

2 hours ago | master | update readme 4 hours ago | bugfix/payment | fix payment bug 5 hours ago | feature/order | add order feature 2 days ago | feature/login | add login feature

这种格式阅读起来非常直观,特别适合分支清理前的“体检”环节。

3.3 用git log自己拼接排序

如果不想记忆for-each-ref的格式化字段,也可以用git log配合 shell 循环手动拼接分支列表:

git branch | while read branch; do branch=$(echo "$branch" | sed 's/\* //') last_commit=$(git log -1 --format='%ci %s' "$branch" 2>/dev/null) echo "$branch $last_commit" done | sort -k2,2r

这段脚本的大致逻辑是:

  • git branch列出所有本地分支,带*的是当前分支。
  • sed去掉行首的*
  • git log -1 --format='%ci %s'取该分支最后一次提交的提交时间和提交说明。
  • 最后用sort -k2,2r按时间列倒序排序。

这个方案比较绕,而且每执行一个分支都要调用一次git log,分支很多时速度会慢。推荐只是在理解“排序本质”时参考,生产环境直接用git for-each-ref

3.4 排序字段的选择

-committerdate并不是唯一可用的排序字段,Git 还支持按多个时间维度排序:

  • committerdate:提交者时间,最常见,适合判断分支最后的活跃时间。
  • authordate:作者时间,适合追溯原作者是谁、原始提交时间是什么。
  • creatordate:引用创建时间,适合查看分支创建的时间。

在绝大多数分支清理场景里,我们只需要关注committerdate。因为 rebase、cherry-pick、fast-forward 合并等操作都会更新提交者时间,用它判断分支“最后被更新”最准确。

如果你还想看一下当前 HEAD 指向哪个分支,可以用:

git for-each-ref --sort=-committerdate \ --format='%(HEAD) %(refname:short) | %(committerdate:relative)' \ refs/heads

%(HEAD)如果以*开头,说明那个分支就是当前所在分支。

4. 完整实战:按最后提交日期管理本地分支

这一节把上面的命令串起来,做一次完整的实战演示,覆盖查看、筛选、清理准备整个流程。

4.1 查看默认分支列表

先回到前面创建的演示仓库:

cd demo-branch-sort

不添加任何参数时,分支按名称排序列出:

$ git branch bugfix/payment feature/login feature/order * master

这个列表在分支数量少的时候还可以接受,但信息量仅限于名字。

4.2 按提交日期倒序查看

执行:

git branch -v --sort=-committerdate

输出大致为:

* master a1b2c3d update readme bugfix/payment b2c3d4e fix payment bug feature/order c3d4e5f add order feature feature/login d4e5f6a add login feature

排序结果从最新提交到最旧提交排列。在真实项目中,这种视图能立刻发现哪些分支最近还在活跃,哪些已经停了很久。

4.3 用for-each-ref输出更完整的信息

如果觉得-v的信息还不够,可以用下面的命令,把时间精确到秒,并且显示提交人和提交说明:

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

在团队协作中,这种格式非常适合直接导出给同事确认:“这个分支是你负责的吗?最后提交时间是 X,还要继续保留吗?”

4.4 只看远程仓库分支

本地分支往往和远程分支对应。如果只想看远程分支,把refs/heads换成refs/remotes

git for-each-ref --sort=-committerdate \ --format='%(committerdate:iso8601) | %(refname:short) | %(subject)' \ refs/remotes

也可以直接使用简短写法:

git branch -r --sort=-committerdate

这里有一点要注意:远程分支refname默认显示为origin/feature/login这样的形式。如果想去掉origin/前缀,可以用%(refname:lstrip=2)代替%(refname:short)

git for-each-ref --sort=-committerdate \ --format='%(committerdate:iso8601) | %(refname:lstrip=2) | %(subject)' \ refs/remotes

lstrip=2的意思是去掉引用路径的前两段,也就是去掉refs/remotesorigin

4.5 结合相对时间定位不活跃分支

分支清理前,最常问的问题是:“哪些分支超过 30 天没有更新了?”

先把所有分支按相对时间展示出来:

git for-each-ref --sort=-committerdate \ --format='%(committerdate:relative) | %(refname:short) | %(subject)' \ refs/heads

输出中你会看到类似2 days ago6 weeks ago3 months ago这样的相对时间。相对时间是动态计算的,适合人工阅读,但它不是固定字段,拿去做精确的日期过滤时不方便。

如果需要精确过滤超过 30 天的分支,可以借助 unix 时间戳写一段小脚本:

git for-each-ref --sort=-committerdate \ --format='%(committerdate:unix) %(refname:short)' refs/heads | while read ts branch; do now=$(date +%s) diff=$(( (now - ts) / 86400 )) if [ "$diff" -gt 30 ]; then echo "$branch : $diff days" fi done

这段脚本的思路:

  • %(committerdate:unix)输出 Unix 时间戳。
  • date +%s获取当前时间戳。
  • 两者相减得到秒数,再除以 86400 换算成天数。
  • diff -gt 30表示超过 30 天未更新的分支会被打印出来。

注意:这段脚本需要 bash 或 Git Bash 环境,Windows 的 CMD/PowerShell 直接执行可能不兼容。

5. 常用组合:筛选、统计与脚本化

5.1 找出已经合并到主分支的旧分支

除了按时间排序,还可以结合--merged参数,只显示已经合并到指定分支的旧分支:

git branch --merged master --sort=-committerdate

这种命令非常适合清理场景:已经合并到 master 的分支,如果没有特殊原因,通常就是可以删除的候选对象。再配合最后提交时间,就能把“已合并 + 长时间未更新”的分支一次性列出来。如果要列出未合并分支,把--merged改成--no-merged

git branch --no-merged master --sort=-committerdate

未合并分支即使旧,也可能包含尚未合入的功能或专属环境的修复,删除前必须二次确认。

5.2 统计每个分支的最后提交人和提交邮箱

团队维护时,如果想知道“某个分支最近是谁在提交”,用committeremailauthorname字段:

git for-each-ref --sort=-committerdate \ --format='%(committerdate:iso8601) | %(refname:short) | %(committeremail) | %(subject)' \ refs/heads

输出后可以按提交人过滤,例如查看某个开发者的最近分支提交情况:

git for-each-ref --sort=-committerdate \ --format='%(committerdate:iso8601) | %(refname:short) | %(committeremail)' \ refs/heads | grep "zhangsan@example.com"

这里grep只是简单的字符串过滤,实际上这种方式比在浏览器里翻 GitLab/GitHub 分支列表要快得多。

5.3 把命令固化成 Git 别名

每次输入一大段for-each-ref命令比较麻烦,可以把它配置成 Git 别名。

在终端执行:

git config --global alias.recent "for-each-ref --sort=-committerdate --format='%(committerdate:relative) | %(refname:short) | %(authorname) | %(subject)' refs/heads"

配置好之后,直接执行:

git recent

就能看到所有本地分支的最后提交时间和提交信息。

也可以配置查看远程分支的别名:

git config --global alias.remote-recent "for-each-ref --sort=-committerdate --format='%(committerdate:relative) | %(refname:lstrip=2) | %(authorname) | %(subject)' refs/remotes"

日常使用git remote-recent即可。

在 Windows 环境如果使用 Git Bash,别名里的单引号不会出问题;如果你在 PowerShell

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询