Close

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 徽标
查看解决方案

了解 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 prunegit 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/originremote/origin 引用集合。git remote prune origin 只会修剪 remote/origin 中的引用。这样可以安全地将本地工作留在 local/origin

Git Prune 摘要


git prune 命令旨在作为 git gc 的子命令调用。您几乎不可能在日常的软件工程能力中调用 git prune。需要使用其他命令来理解 git prune 的效果。本文中使用的一些命令包括 git loggit refloggit checkout


分享此文章
下一主题

推荐阅读

将这些资源加入书签,以了解 DevOps 团队的类型,或获取 Atlassian 关于 DevOps 的持续更新。

人们通过满是工具的墙进行协作

Bitbucket 博客

Devops 示意图

DevOps 学习路径

与 Atlassian 专家一起进行 Den 功能演示

Bitbucket Cloud 与 Atlassian Open DevOps 如何协同工作

注册以获取我们的 DevOps 新闻资讯

Thank you for signing up