git-如何为git prune创建无法访问的提交?

git-如何为git prune创建无法访问的提交?,git,Git,我正在为git编写教育材料,我需要演示如何删除“分离的对象”。我想我可以通过使用git reset将提交从分支历史中分离出来,从而将其置于分离状态 这将触发git checkout将提交视为已分离,但是git prune将不关心它 我当前分离的提交模拟的设置如下所示: ~ $ mkdir git-prune-demo ~ $ cd git-prune-demo/ ~/git-prune-demo $ git init . Initialized empty Git repository in /

我正在为git编写教育材料,我需要演示如何删除“分离的对象”。我想我可以通过使用
git reset
将提交从分支历史中分离出来,从而将其置于分离状态

这将触发
git checkout
将提交视为已分离,但是
git prune
将不关心它

我当前分离的提交模拟的设置如下所示:

~ $ mkdir git-prune-demo
~ $ 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"
[master (root-commit) 994b122] added hello.txt
 1 file changed, 1 insertion(+)
 create mode 100644 hello.txt
~/git-prune-demo $ echo "this is second line txt" >> hello.txt
~/git-prune-demo $ git commit -am "added another line to hello.txt"
[master 5178bec] added another line to hello.txt
 1 file changed, 1 insertion(+)
~/git-prune-demo $ git reset --hard 994b122045cf4bf0b97139231b4dd52ea2643c7e
HEAD is now at 994b122 added hello.txt
~/git-prune-demo $ git prune -n
~/git-prune-demo $ nothing

是的,我知道
git prune
通常不作为独立命令使用,本质上是
git gc
的子命令

Prune通常不会删除在上一个。。。我忘了,月它会检查本地的回流。Pass
--立即过期
以禁用对象删除时的oops保护,但如果您正在编写文档,则建议您养成这样的坏习惯。

TL;博士 您需要首先运行
git reflog expire--expire unreachable=now
,然后运行
git prune--expire now
。即使这样,事情也可能会出问题,不过对于这个特别简单的例子,这可能就足够了

长的 我正在为git编写教育材料,我需要演示git prune如何删除分离的提交

但这不是git prune所做的。它所做的可以产生这种效果,但只有在特定条件下。重要的是,分离提交在Git中并不是一个定义良好的短语:Git对分离头有一个定义,稍后我们将回到这里,但提交本身要么是可到达的,要么是不可到达的。我想你的意思是在这里谈论无法实现的提交

重要的是,
gitprune
处理对象,这些对象比提交更通用。Git有四种类型的对象:提交、树、blob和带注释的标记。Git的
Git prune
可以删除任何无法访问的对象,只要满足其他几个条件。不过,在我们到达之前,让我们再看几个项目

纠正误解 我想我可以通过使用
git reset
将提交从分支历史中分离出来,从而将其置于分离状态

根据定义,如果有某个外部名称直接命名提交(或对象)本身,或者命名我们可以访问给定提交的其他对象,那么提交或任何其他Git对象都是可访问的。(有关这方面的更多信息,请参阅。)使用
git reset
,我们可以使只能通过当前分支名称访问的提交变得不可访问。例如,如果只能通过当前分支名称访问提交
a123456…
,即,不能通过任何其他分支名称,也不能通过任何标记名称或其他非分支名称引用,则使用
git reset
调整当前分支,使其排除
a123456…
使该提交无法访问

这将触发git签出,以将提交视为已分离

我想你说的是Git称之为分离的头

分离的头仅仅意味着Git的特殊头引用(存储为名为
.Git/HEAD
的文件)包含提交的原始散列ID。相反的情况,我们可以称之为附加头,因为当
.git/HEAD
包含分支名称时,这是分离的明显反义词。在这两种情况下,
HEAD
表示当前提交;当
HEAD
包含分支名称时,
HEAD
也指当前分支名称。Git在内部处理这一问题的方式是,它有不同的函数和程序来解析
头部
,或者象征性地:

$ git symbolic-ref HEAD
refs/heads/master
或哈希ID:

$ git rev-parse HEAD
c05048d43925ab8edcb36663752c2b4541911231
(对于分离的机头箱,
git symbolic ref
产生错误,因为没有分支名称。)

在以下情况下,
git checkout
命令将头(附加到某些指定的分支名称):

  • 您给它一个分支名称,或者
  • 您可以使用它创建并附加到新的分支名称
在以下情况下,它会分离头部:

  • 您为它提供了解析为散列ID而不是分支名称的内容(例如,原始散列ID或远程跟踪名称,如
    origin/master
    ),或者
  • 您可以使用
    --detach
    标志强制分离磁头,即使它通常会连接磁头
分离头模式并不意味着您正在处理无法访问的提交。事实上,将HEAD分离到一个不可访问的提交,会使该提交突然可访问,因为它现在是HEAD提交。换句话说,将HEAD分离到任何commit都会增加一种到达commit的方法,但就prune而言,有趣的问题不是有多少名称到达了所讨论的对象,而是这个数字是否为非零。一个名称、两个名称、十个名称或数百万个名称:所有这些都与git prune相同。当我在这里说名称时,我的意思不仅仅是参考名称加上可能分离的
,但在添加下一个复杂度之前,我们将从这些名称开始

Git的对象模型和对对象的引用 很好地描述了引用如何使提交可访问。不过,它没有提到,一般来说,引用可以指定任何对象的哈希ID,而不仅仅是提交。这是因为它关注的是分支,而不仅仅是任何旧对象,而且分支名称(
refs/heads/*
)和远程跟踪名称(
refs/remotes/*
)都被限制为仅指向提交。它也没有详细介绍提交中的内容,即Git如何存储文件和文件名。这就是树和blob对象的作用

每个提交都包含单个树对象的哈希ID。树对象包含一系列三值项:mode、name和hash-ID
... <-  commit a1234...   <-- branchname
               |
               v
        tree 07f39...: (100644, README.txt, 531c2...); (040000, subdir, ...)
                                               |                         |
                                               v                         |
                                blob 531c2...: data for README.txt       |
                                                                         |
                                                                         v
                                                               tree ...: ...
git reflog expire --expire-unreachable=now --all
git prune --expire now