Git prune
git prune
命令是一个内部管理实用程序,用于清理无法访问或“孤立的”Git 对象。无法访问的对象是指任何引用都无法访问的对象。任何无法通过分支或标记访问的提交都被视为无法访问。git prune
通常不直接执行。prune 被视为垃圾回收命令,是 git gc 命令的子命令。
Git Prune 概述
为了理解 git prune
的效果,我们需要模拟无法提交的场景。以下是模拟这种体验的一系列命令行执行。
~ $ cd git-prune-demo/
~/git-prune-demo $ git init .
Initialized empty Git repository in /Users/kev/Dropbox/git-prune-demo/.git/
~/git-prune-demo $ echo "hello git prune" > hello.txt
~/git-prune-demo $ git add hello.txt
~/git-prune-demo $ git commit -am "added hello.txt"
前面的命令序列将在名为 git-prune-demo
的目录中创建一个新的存储库。一个包含新文件 hello.text
的提交被添加到代码存储库中,其基本内容为 "hello git prune"。接下来,我们将修改 hello.txt
,然后根据这些修改创建新的提交。
~/git-prune-demo $ echo "this is second line txt" >> hello.txt
~/git-prune-demo $ cat hello.txt
hello git prune
this is second line txt
~/git-prune-demo $ git commit -am "added another line to hello.txt"
[main 5178bec] added another line to hello.txt
1 file changed, 1 insertion(+)
相关资料
如何移动完整的 Git 存储库
查看解决方案
了解 Bitbucket Cloud 的 Git
现在,我们在这个演示代码存储库中有 2 次提交历史记录。我们可以使用 git log
进行验证:
~/git-prune-demo $ git log
commit 5178becc2ca965e1728554ce1cb8de2f2c2370b1
Author: kevzettler <kevzettler@gmail.com>
Date: Sun Sep 30 14:49:59 2018 -0700
added another line to hello.txt
commit 994b122045cf4bf0b97139231b4dd52ea2643c7e
Author: kevzettler <kevzettler@gmail.com>
Date: Sun Sep 30 09:43:41 2018 -0700
added hello.txt
git log 输出显示了 2 次提交以及有关对 hello.txt
所做的编辑的相应提交消息。下一步是让其中一个提交变得不可访问。我们将使用 git reset 命令来实现此目的。我们将代码存储库的状态重置为第一次提交。“added hello.txt”提交。
~/git-prune-demo $ git reset --hard 994b122045cf4bf0b97139231b4dd52ea2643c7e
HEAD is now at 994b122 added hello.txt
如果我们现在使用 git log
来检查存储库的状态,我们可以看到我们只有一次提交。
~/git-prune-demo $ git log
commit 994b122045cf4bf0b97139231b4dd52ea2643c7e
Author: kevzettler <kevzettler@gmail.com>
Date: Sun Sep 30 09:43:41 2018 -0700
added hello.txt
演示存储库现在处于包含分离提交的状态。我们在 "added another line to hello.txt" 消息时所做的第二次提交不再显示在 git log
输出中,现在已分离。看起来好像我们丢失或删除了提交,但是 Git 对不删除历史记录非常严格。我们可以使用 git checkout
直接访问它来确认它仍然可用,但已分离:
~/git-prune-demo $ git checkout 5178becc2ca965e1728554ce1cb8de2f2c2370b1
Note: checking out '5178becc2ca965e1728554ce1cb8de2f2c2370b1'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:
git checkout -b <new-branch-name>
HEAD is now at 5178bec... added another line to hello.txt
~/git-prune-demo $ git log
commit 5178becc2ca965e1728554ce1cb8de2f2c2370b1
Author: kevzettler <kevzettler@gmail.com>
Date: Sun Sep 30 14:49:59 2018 -0700
added another line to hello.txt
commit 994b122045cf4bf0b97139231b4dd52ea2643c7e
Author: kevzettler <kevzettler@gmail.com>
Date: Sun Sep 30 09:43:41 2018 -0700
added hello.txt
当我们签出分离提交时,Git 会贴心地给我们发一条详细消息,说明我们处于分离状态。如果我们在这里查看日志,可以看到在 "added another line to hello.txt" 提交现在又回到了日志输出中!现在我们知道存储库处于良好的模拟状态,有分离提交,我们可以使用 git prune
进行练习。但首先,我们使用 git checkout
返回 main
分支
~/git-prune-demo $ git checkout main
Warning: you are leaving 1 commit behind, not connected to
any of your branches:
5178bec added another line to hello.txt
If you want to keep it by creating a new branch, this may be a good time
to do so with:
git branch <new-branch-name> 5178bec
Switched to branch 'main'
通过 git checkout
返回 main 分支时,Git 再次贴心地让我们知道我们留下了一个分离提交。现在是时候修剪分离提交了!接下来,我们将执行 git prune
,但我们必须确保向其传递一些选项。--dry-run
和 --verbose
将显示输出,指示设置为修剪的内容,但实际上并未对其进行修剪。
~/git-prune-demo $ git prune --dry-run --verbose
此命令很可能会返回空输出。空输出意味着修剪实际上不会删除任何内容。为什么会发生这种情况?好吧,提交很可能没有完全分离。在某个地方,Git 仍在保留对它的引用。这是一个很好的例子,说明了为什么 git prune
不能在 git gc
之外单独使用。这也是一个很好的例子,说明使用 Git 很难完全丢失数据。
Git 很可能在引用日志中存储了对我们分离提交的引用。我们可以通过运行 git reflog 来调查。您应该会看到一些描述我们为到达这里而采取的操作顺序的输出。有关 git reflog
的更多信息,请访问 git reflog 页面。除了在 reflog 中保留历史记录外,Git 还有内部过期日期,说明何时会删除分离提交。同样,这些都是 git gc
处理的实现细节,git prune
不应单独使用。
要结束我们的 git prune
模拟演示,我们必须清除引用日志
~/git-prune-demo $ git reflog expire --expire=now --expire-unreachable=now --all
上面的命令将强制引用日志中所有比现在更早的条目过期。这是一个残酷而危险的命令,作为普通的 Git 用户,您最好不要使用。我们执行这个命令是为了演示成功的 git prune
。完全擦除引用日志后,我们现在可以执行 git prune
了。
~/git-prune-demo $ git prune --dry-run --verbose --expire=now
1782293bdfac16b5408420c5cb0c9a22ddbdd985 blob
5178becc2ca965e1728554ce1cb8de2f2c2370b1 commit
a1b3b83440d2aa956ad6482535cbd121510a3280 commit
f91c3433eae245767b9cd5bdb46cd127ed38df26 tree
此命令应输出与上面类似的 Git SHA 对象引用列表。
使用
git prune
有一个简短的选项列表,我们在概述部分介绍了这些选项。
-n --dry-run
不要执行修剪操作,只需显示它将做什么的输出即可
-v --verbose
显示所有对象的输出以及修剪执行的操作
--progress
显示指示修剪进度的输出
--expire <time>
强制超过以下时间的对象过期
<head>…
指定 将保留该标头引用中的所有选项
讨论
Git Prune、Git Fetch --prune 和 Git Remote Prune 有什么区别?
git remote prune
和 git fetch-- prune
的操作一样:删除对远程存储库上不存在的分支的引用。在团队工作流程中工作时,在合并到 main
分支后删除远程分支时,这是非常可取的。第二条命令 git fetch --prune
将连接到远程存储库并在修剪之前获取最新的远程存储库状态。它本质上是命令的组合:
git fetch --all && git remote prune
通用的 git prune
命令完全不同。如概述部分所述,git prune 将删除本地分离的提交。
如何清理过时的分支?
git fetch --prune
是清理过时分支的最佳工具。它将远程连接到共享的远程存储库并获取所有远程分支引用。然后,它将删除远程存储库中不再使用的远程引用。
Git Remote Prune Origin 会删除本地分支吗?
没有 git remote prune origin
只会删除对已不存在的远程分支的引用。Git 同时存储本地和远程引用。存储库将包含 local/origin
和 remote/origin
引用集合。git remote prune origin
只会修剪 remote/origin
中的引用。这样可以安全地将本地工作留在 local/origin
。
Git Prune 摘要
git prune
命令旨在作为 git gc
的子命令调用。您几乎不可能在日常的软件工程能力中调用 git prune
。需要使用其他命令来理解 git prune
的效果。本文中使用的一些命令包括 git log
、git reflog
和 git checkout
。
分享此文章
下一主题
推荐阅读
将这些资源加入书签,以了解 DevOps 团队的类型,或获取 Atlassian 关于 DevOps 的持续更新。