在git

时间:2017-02-08 19:18:32

标签: git

我们团队中的某个人将一系列提交推送到孤立的远程存储库。也就是说,第一次提交没有父级。随后的是第一个的后代。分支上也没有名字。从图形上看,它看起来像这样

master
o Commit #4
|               (no branch)
o commit #3     o commit #7
|               |
o commit #2     o commit #6
|               |
o commit #1     o commit #5

我想删除提交5-7。我尝试在commit 5创建一个分支。然后,提交6和7被列为在该分支上。然后,我尝试修剪分支,但无济于事。

我该怎么做?

更新:我认为问题与不匹配的分支名称有关。开发人员以某种方式将远程控制器上的新分支命名为master。最初已经有一位大师,仍然存在于我当地。因此,(我使用GitExt)在本地查看存储库时,我认为它混淆了GitExt并显示本地分支没有任何名称。当我将master分支重置回远程的原始分支时,新分支不再有任何引用并消失。问题解决了,我想。

2 个答案:

答案 0 :(得分:3)

Sukima's question-comment是了解所有这一切的关键。

在Git存储库中,提交图(DAG)表示为提交对象的集合。像往常一样,每个对象通过其哈希ID进行标识,并且每个提交在其中都有一些父对象ID(零或更多,但通常为1)。 Git使用父链接来构造图形,但为了开始这个图形构建过程,它必须有一些方法来识别"起点"。 (其他版本控制系统,包括Mercurial,使用其他技术,不需要这个起点列表。)

这些起点是Git的参考。两个最常见的参考文献是分支和标签名称,但还有其他"常规"引用,所有引号都在以refs/开头的名称下,以及一些特殊的引用,如HEAD(当HEAD分离时)和FETCH_HEAD(在一个已运行git fetch的存储库中{{ 1}})。还有一些额外的特殊引用:索引(也称为暂存区域,也就是缓存)可以直接引用" blob" (存储在存储库数据库中的文件对象 - 这些文件对象不参与提交图,但它们都是相同整体存储方案的一部分。)

创建一个对象然后放弃它是很正常的。提交和blob是最典型的,但四种对象类型中的任何一种都可以通过此过程。例如,当我们将它们复制到git commit --amendgit rebase的新提交时,我们放弃旧提交。 1 当我们git add文件时,我们放弃blob对象,然后意识到它还没有完成,再进行编辑,然后git add 再次再提交。每个git add将文件本身作为blob对象复制到存储库中,但在我们git commit结果之前,它仅通过索引引用,并重新add新版本会覆盖旧索引条目。

Git可以(有时会)完全扫描每个存储库对象,它会找到没有可能导致它们的起始点的对象。这些有时被称为无法访问的对象。 2 执行此操作的两个面向用户的命令 - 这些仍然非常维护 - 对大多数用户通常不是必需的 - 是存储库一致性检查器git fsck垃圾收集器 git gc。因为他们做了这种全扫描,所以它们相对较慢。 3

因为它很慢,所以在后台完成自动垃圾收集":各种命令根据需要自动关闭git gc,以丢弃未引用/不可达的提交和文件。这意味着后台清理可以与正常的Git活动竞争,这可以创建尚未引用的 new 对象,但是一旦命令完成,它就会立即生成。例如,GC可能与git commit命令同时运行。如果GC在添加到分支之前发现了新创建的提交,并且删除了提交,那将是不好的。因此,为了安全起见,自动GC可以避免删除在过去14天内创建的任何内容:默认情况下,这会花费git commit 336小时来完成,这通常应该是足够的时间。 : - )

您始终可以通过其原始哈希ID找到任何现有的Git对象:Git如何访问每个对象,无论是在慢速全扫描操作中,还是枚举存储库中的每个ID,还是在以起点开始的更快操作,例如分支或标记引用。因此,如果提交确实无法访问,但 仍在存储库中,则可以通过其哈希ID查看它们。但最终,垃圾收集器将运行它们将至少14天。此时,GC将删除它们将永远消失。 4

通常,您不需要关心其中的任何内容,但如果您不小心将敏感内容(例如明文密码或密钥或证书)放入存储库,则可能需要更快地删除它。这很难(见脚注),当你注意到谷仓门打开时,无论如何都可能克隆了马匹, 5 因此明智的做法是使证书无效,即使你设法找到并删除有问题的Git对象。

1 这些放弃的提交通常通过 reflogs 保留。每个普通refs/名称空间参考有一个reflog,加上特殊HEAD引用的一个大的。默认情况下,reflog中的项目至少可以使用30天,有时最长可达90天。 (两个时间值都是可配置的:请参阅gc.reflogExpiregc.reflogExpireUnreachable。)但最终这些值也会过期,之后它们指向的对象可能会变为真正未引用的,因此也是GC的候选对象。

2 单词 unreferenced 可用于专门讨论没有直接引用的提交或其他对象,单词 unreachable 用于例如另一个提交引用的提交,但其他提交没有引用 it 。也就是说,在视觉上,我们可能会:

A--B--C--D   <-- master
    \
     E--F    <-- branch
      \
       G--H

最后两次提交G--H根本没有名称,但我们可能只调用H 未引用,而两者都无法访问。但是Git对此不一致:git fsck使用悬空这个词来描述提交H

3 这个GC过程让人想起一些编程语言&#39; &#34;标记和扫描&#34; GC。例如,看看很多Lisp实现,一直追溯到1959年。另见Wikipedia page on GC in programming languages。 Git的GC不使用(也不希望)引用计数,也不使用任何类型的实时动态实时GC系统,因为GC主要可以在后台运行,只需短时间锁定包文件。当然,Git的对象形成一个DAG,根据定义,它不包含循环,与Lisp数据结构不同。尽管如此,标记和扫描简单而有效,并且在这里运行良好。

4 这掩盖了压缩的对象。对象可以松散,在这种情况下,它们以压缩形式存储,但存储在单个文件中,或者压缩。打包的对象一起存储在一个文件中,其名称以.pack结尾。 (这些.pack文件可以有多个实例,每个文件都是自包含的。)如果需要,打包的对象仍然可以进行GC编辑,但这并不容易:包必须<使用git repack重新打包。新包不会保留未引用的对象(git repack称它们为“无法访问”#34;它的含义略有不同)。如果删除了旧的包文件,那么最终会丢弃该对象。但是,通过添加<name>.keep文件,您可以将某些包标记为珍贵; 永远不会自动删除。

请注意,打包对象的主要目的是让它们更快更慢地访问(以复杂的方式,尝试更快地保留更新的对象),同时 delta压缩它们彼此相对在包内缩小磁盘空间使用量。垃圾收集器git gc通常会自动为您处理所有这些。

5 正常的普通git clone克隆引用/可达对象。但即使秘密或敏感文件总是无法访问,对于知道其中一个提交ID的攻击者来说,使用Git传输来访问该对象或有关该对象的信息也是可能的。请参阅the description of known transfer data leaks in the Git documentation

答案 1 :(得分:1)

任何分支都不会引用的提交将被git垃圾收集器删除。无需做任何事情。