代码之家  ›  专栏  ›  技术社区  ›  kevzettler

git-如何为git prune创建一个不可访问的提交?

git
  •  2
  • kevzettler  · 技术社区  · 7 年前

    我正在为git编写教育材料,我需要演示 git prune 移除“分离对象”。我想我可以使用 git reset 从分支历史中分离它。

    这将触发 git checkout 吉特梅干

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

    ~ $ 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 gc .

    2 回复  |  直到 7 年前
        1
  •  4
  •   torek    7 年前

    热释光;博士

    git reflog expire --expire-unreachable=now git prune --expire now . 即使这样,事情也可能会出错,不过对于这个特别简单的例子来说,这可能就足够了。

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

    不是这样的 git prune 不过。它能做什么 产生这种效果 在Git中不是一个定义良好的短语:Git对 分离头 我们一会儿再谈这个,但他们自己 可达成的 无法到达 . 我想你的意思是说不可达到的承诺,在这里。

    吉特梅干 处理 物体 吉特梅干 任何

    纠正误解

    git reset 从分支历史中分离它。

    commitor根据定义,任何其他Git对象都是可访问的,如果有某个外部名称直接命名commit(或object)本身,或者命名其他可以访问给定commit的对象(有关详细信息,请参阅 Think Like (a) Git )使用 ,我们可以使只能通过当前分支名称访问的提交变得不可访问。例如,如果提交 a123456... 只能通过当前的分支名称(即,不通过任何其他分支名称,也不通过任何标记名称或其他非分支名称引用)访问 git重置 调整当前分支使其排除 a123456。。。 使提交无法访问。

    这将触发 git checkout

    我想你说的是吉特所说的超然的头脑。

    .git/HEAD ,包含提交的原始哈希ID。相反的条件,我们可以称之为 ,因为这是 独立的 包含分支名称。在这两种情况下, HEAD 指当前提交;什么时候

    $ git symbolic-ref HEAD
    refs/heads/master
    

    或哈希ID:

    $ git rev-parse HEAD
    c05048d43925ab8edcb36663752c2b4541911231
    

    (对于分离的头部壳体, git symbolic-ref

    这个 git签出

    • 你给它一个分支名称,或者
    • 您可以使用它来创建并附加到新的分支名称。

    在以下情况下,它会分离头部:

    • origin/master ),或
    • 你使用 --detach

    分离头模式并不意味着您正在处理一个不可访问的提交。事实上,将头分离到一个不可访问的提交,会使该提交突然可访问 因为 现在是头犯了。换句话说,将HEAD分离到任何提交都会增加一种到达提交的方法,但就prune而言,有趣的问题不是这样的 有多少 名称到达所讨论的对象,只是数字是否为非零。一个名字,两个名字,十个名字,或者几百万个名字:所有这些对我来说都是一样的 吉特梅干 . 当我说 姓名 在这里,我指的不仅仅是参考名称加上可能的分离名称

    Git的对象模型和对对象的引用

    很好地描述了引用如何使提交可访问。不过,它没有提到,一般来说,引用可以指定 对象,而不仅仅是提交。这是因为它关注的是分支,而不仅仅是任何旧对象,以及两个分支名称( refs/heads/* )和远程跟踪名称( refs/remotes/*

    每个提交都包含单个树对象的哈希ID。树对象包含一系列三值项:mode、name和hash-ID。mode指定此树条目是用于文件、子树还是用于更奇特的项(符号链接和gitlinks)。名称给出被表示的实体的名称,例如 README.txt subdir file.ext . hash ID通常是blob对象或另一个树对象的ID:如果条目是针对类似 ,它是子树的哈希ID。

    如果我们为一次提交绘制所有这些,从最上面一行右边的分支名称开始,我们得到如下结果:

    ... <-  commit a1234...   <-- branchname
                   |
                   v
            tree 07f39...: (100644, README.txt, 531c2...); (040000, subdir, ...)
                                                   |                         |
                                                   v                         |
                                    blob 531c2...: data for README.txt       |
                                                                             |
                                                                             v
                                                                   tree ...: ...
    

    还有别的吗 refs/tags/v1.0 a1234... . 这将给这一承诺提供另一个参考。如果我们还没有创建任何标签,我们就不必担心这些问题,但是它们对于完整的图片非常重要。

    指数

    总之,在上图中,我们可以看到 branchname 作出承诺 可达成的。提交 造树 07f39... reachable,使一个blob和另一个子树可以访问,依此类推。因为这些都是可以到达的, 不会

    名称,有一个可选的 重录 作为参考, 以前的值 引用的名称。这些保存的值在一段时间内保持有效,直到过期。Git用来终止过时保存值的命令是 git reflog expire ,使用两个不同的命令行选项, --expire= when --expire-unreachable= when .

    如果你想展示 吉特梅干 完全地 未引用。这意味着您将需要删除任何直接(提交)或间接(树和blob)记住其哈希ID的reflog条目。这样做的easyalbeit而不是destructivity方法是使用:

    git reflog expire --expire-unreachable=now --all
    

    --expire=now 但是我们可以假设引用的当前值没有达到reflog值,因此 --expire-unreachable

    这就建立了一个 必要的 吉特梅干

    所有这些都解决了,让我们回到过去

    这个 吉特梅干 未引用 物体。从上面我们知道,我们必须确保commit是未引用的,在使用类似于 git branch -f git branch -D git重置 以确保没有分支名称记住它。

    但是现在我们还需要了解关于Git对象的两件事:

    • 释放 拥挤的
    • 它们有一个年龄,更像是reflog条目。

    释放 存储在文件系统中的单独文件中。这使得Git很容易对其进行操作,但意味着它的压缩程度很低。Git将根据命令(或通过 git gc ), 打包文件

    这个 prune 命令遗嘱 从未 吉特梅干 只会看 释放 物体。单独的程序 git repack

    一般来说,对象不会立即打包,因此最近创建的对象很可能是松散的。如果物体 不过,已经打包好了,现在还没有被引用,您需要运行 git重新打包 相反。

    同时,作为对竞争的Git进程的保护, 吉特梅干 吉特梅干 新的 对象,包括新的提交,它将一次一个(或仅几个)将这些对象写入存储库数据库。Git必须用blob散列来编写最深的子树,然后使用子树及其散列以及这些树中的任何blob散列来编写树的下一层。一旦Git写出了所有的树并获得了顶级树散列以进入一个新的提交,只有这样Git才能编写提交对象。在这之前,所有这些树都没有被引用。即使写下承诺, 那是 )更新为指向新创建的提交。

    这个过程需要时间。默认情况下,Git给自己14天的时间来完成这个过程。如果 git commit 需要14天以上才能完成 可能会删除一些对象,但14天应该是足够的时间。

    如果您知道自己没有运行任何其他Git命令,可以手动覆盖默认值:

    git prune --expire now
    

    意味着任何未引用的松散对象都应该被删除,无论它们是多么新。因此,您所需要做的就是确保您的提交未被引用,然后使用“now”过期时间进行修剪。

        2
  •  1
  •   jthill    7 年前

    Prune通常不会删除在最近一段时间内可以从任何ref访问的对象。。。我忘了,月它检查本地的回放。通过 --expire now 要禁用对象删除的oops保护,但如果您正在编写文档,建议您养成这样的坏习惯。