【问题标题】:Why do for-each-ref and show-ref behave differently in a bare repository?为什么 for-each-ref 和 show-ref 在裸存储库中的行为不同?
【发布时间】:2019-02-06 19:59:00
【问题描述】:

在标准(非裸)Git 存储库中,以下命令都给出了基本相同的结果,因为它们列出了所有分支(每个命令后面的数字是通过管道传输到 wc -l 的命令的输出,只是为了保持事情简介):

R1) bare: false
    pwd                           .../R1/.git
    git branch                    8
    git for-each-ref refs/heads   8
    git show-ref --heads          8
    git for-each-ref refs/heads/* 8
    git show-ref refs/heads/*     8
    find ./refs/heads -type f     8

但在裸存储库中,显然并非总是如此:

R2) bare: true
    pwd                           .../R2.git
    git branch                    24
    git for-each-ref refs/heads   24
    git show-ref --heads          24
    git for-each-ref refs/heads/* 17
    git show-ref refs/heads/*     13
    find ./refs/heads -type f     14
R3) bare: true
    pwd                           .../R3.git
    git branch                    15
    git for-each-ref refs/heads   15
    git show-ref --heads          15
    git for-each-ref refs/heads/* 6
    git show-ref refs/heads/*     6
    find ./refs/heads -type f     6
R4) bare: true
    pwd                           .../R4.git
    git branch                    36
    git for-each-ref refs/heads   36
    git show-ref --heads          36
    git for-each-ref refs/heads/* 36
    git show-ref refs/heads/*     0
    find ./refs/heads -type f     0

因此,通过查看比此处显示的更多的存储库,前 3 个命令总是给出一致的答案,无论是裸的还是非裸的,但后 3 个给出的结果并不总是与前三个相同,而且并不总是一致彼此。谁能解释一下原因?

在使用非裸存储库时,我一直假设像 branchshow-reffor-each-ref 这样的命令可以处理 refs/heads 目录的实际内容,但在裸存储库中,这不可能是真的,因为它们显示的结果比 refs/heads 目录中的文件多。

【问题讨论】:

    标签: git


    【解决方案1】:

    简短回答:

    通过引用参数来抑制 shell 的通配符处理:

    git for-each-ref "refs/heads/*"
    

    然后再次运行您的命令。

    因为packed-refsfind 不会(或很少)给你正确的答案。


    详细解答:

    你的命令有几个问题:

    1. 最重要的第一点:Git 有 两个 位置来存储引用(即标签、分支等):.git/refs 目录和文件 .git/packed-refs。详情请见git-pack-refs

      这排除了find ./refs/heads -type f 获得正确答案。

    2. 接下来的两件事:这些命令并不像你认为的那样:

      git for-each-ref refs/heads/*
      git show-ref refs/heads/*
      

      假设是一个类 Unix 环境,shell 会尝试通过匹配现有文件名来扩展 * 通配符。所以git 看到的实际上是这样的命令:

      git for-each-ref refs/heads/master refs/heads/topic1
      

      因此,每当引用 存储在 packed-refs 文件中时,shell 将不会将该名称传递给 git,因此没有输出。

      通配符匹配的第二个问题:shell 确实递归到子目录中,因此即使引用存储在 .git/refs/heads/feature/foo 中,分支 feature/foo 也不会出现。

      您可以通过引用参数来抑制 shell 的通配符处理。有几种方法可以做到这一点,一个简单的方法是:

      git for-each-ref "refs/heads/*"
      

    真正的区别不是裸存储库和非裸存储库之间的区别,而是“shell 看到至少一个匹配”和“shell 根本没有匹配”之间的区别,因为在后一种情况下,shell 按原样转发字符串(包括*) 到命令。在非裸仓库中是这种情况,因为您的参数中缺少 .git/ 前缀。

    【讨论】:

      猜你喜欢
      • 2011-01-02
      • 2021-08-02
      • 2010-11-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-15
      相关资源
      最近更新 更多