为什么for-each-ref和show-ref在裸存储库中的行为不同?

时间:2019-02-06 19:59:00

标签: git

在标准(非裸露)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

因此,通过查看比此处所示更多的存储库,前三个命令始终给出一致的答案,无论是裸露还是非裸露,但是后三个命令给出的结果并不总是与前三个相同,并且也不总是一致的彼此。有人可以解释为什么吗?

从使用非裸存储库开始,我一直假设诸如branchshow-reffor-each-ref之类的命令可以在refs / heads目录的实际内容上使用,但是在裸露的情况下这是不正确的,因为它们显示的结果多于refs / heads目录中的文件。

1 个答案:

答案 0 :(得分:3)

简短答案:

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

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

然后再次运行命令。

由于packed-refsfind不会(或很少)给您正确的答案。


详细答案:

您的命令有几个问题:

  1. 最重要的第一件事:Git有两个位置来存储引用(即标签,分支等):.git/refs目录和文件{{1} }。有关详细信息,请参见git-pack-refs

    这排除了.git/packed-refs以获得正确的答案。

  2. 接下来的两件事:这些命令与您认为的不一样:

    find ./refs/heads -type f

    假设类似Unix的环境, shell 会尝试通过匹配现有文件名来扩展git for-each-ref refs/heads/* git show-ref refs/heads/* 通配符。因此*实际上看到这样的命令:

    git

    因此,只要将引用仅 存储在git for-each-ref refs/heads/master refs/heads/topic1 文件中,shell便不会将该名称传递给packed-refs,因此没有输出。

    通配符匹配的第二个问题:shell不会递归到子目录,因此即使将引用存储在git中也不会显示分支feature/foo

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

    .git/refs/heads/feature/foo

裸仓库和非裸仓库之间的区别并不是真正的区别,而是“ shell看到至少一个匹配项”和“ shell根本看不到匹配项”之间的区别,因为在后一种情况下,shell照原样转发字符串(包括git for-each-ref "refs/heads/*" )。在非裸仓库中,是这种情况,因为参数中缺少*前缀。