首页 > 解决方案 > “git show ..origin/master:somefile”和“git show origin/master:somefile”有什么区别

问题描述

对于上下文,在我自己的功能分支中,我使用以下命令:

> git fetch
> git show ..origin/master:somefile > ../external_folder/somefile

以确保我拥有来自 origin/master 的文件的最新副本以供读取,而不会覆盖我自己的分支。

上面的方法有效,但如果我从 git show 命令中省略了两个点,我得到的文件与我的分支相同,即使一个较新的文件已被推送到 origin/master。

有人能解释一下有什么区别吗?此外,如果它有任何区别,则有问题的文件是一个 blob。

编辑:我错了:

> git show ..origin/master:somefile > ../external_folder/somefile

产生一个空文件,我误解了差异

标签: git

解决方案


你应该在git show origin/master:somefile这里使用,没有两个前导点。该git show命令可能应该抱怨..origin/master:somefile:向stderr打印一条错误消息,而stdout根本没有输出。

使用我方便的 Git 版本,git show ..<rev>:path根本不产生任何输出(并且成功退出!),即使给定的路径存在于两个提交中。因此,如果我要使用您的:

git show ..origin/master:somefile > ../external_folder/somefile

我总是会得到一个 ../external_folder/somefile文件。我的结论是你的 Git 版本必须早于 Git 1.7.11.3。

长的

<rev1>..<rev2>语法主要是1表示选择一个范围的提交,范围由调用确定git rev-list,或多或少就像你运行过一样:

git log ^$(git rev-parse rev1) $(git rev-parse rev2)

如果你git rev-parse自己运行,你可以更直接地看到这个效果:

$ git rev-parse master~2..master
b994622632154fc3b17fb40a38819ad954a5fb88
^41eae3eaa81c5f2b61b2610ed74de15c4291b318

master在这个特定的 Git 存储库中,名称选择了 commit b994622632154fc3b17fb40a38819ad954a5fb88。相对表达式master~2选择 commit 41eae3eaa81c5f2b61b2610ed74de15c4291b318

省略这两个名字中的一个意味着假装我HEAD是这样写的,因为HEAD目前是master,我们也得到:

git rev-parse master~2..
b994622632154fc3b17fb40a38819ad954a5fb88
^41eae3eaa81c5f2b61b2610ed74de15c4291b318

像这样的命令git log或者git cherry-pick可以接受这样的一系列提交。此范围表达式选择的提交集是:

  • 从非否定(无^前缀)提交可到达的所有提交,不包括
  • 从否定(^-prefixed)提交中可访问的所有提交。

所以如果我们有:

...--E--F--G--H   <-- master (HEAD)

then master~2..master, or - 更短但含义相同 - <code>HEAD~2.. 选择提交GH,因为master(or HEAD) 表示提交H,而master~2(or HEAD~2) 表示提交F。我们选择所有提交,包括 commit H,然后剔除所有提交,包括 commit F,只留下G这里H

然而,该git show命令通常只显示一件事:例如,一个提交或一个文件。所以给它一个范围表达式的概念是没有意义的(但见下文)。但是,该命令可以显示单个文件,并且当您提供的修订表达式命名一个 blob 对象时,它会这样做:

$ git rev-parse master:Makefile
3d3a39fc192d5544a411d4cedb3785473b6f1148
$ git cat-file -t 3d3a39fc192d5544a411d4cedb3785473b6f1148
blob

因此,当git show master:Makefile给出解析为像这样的单个 blob 对象的修订表达式时,会git show显示该 blob 对象的内容。

现在考虑:

$ git rev-parse master~2..master:Makefile
3d3a39fc192d5544a411d4cedb3785473b6f1148
^41eae3eaa81c5f2b61b2610ed74de15c4291b318

虽然哈希 ID 很大、很丑、很难记住或正确,但我们实际上可以在这里看到我们给出git show的是:

  • 我们希望看到的 blob 对象的非否定哈希 ID,加上
  • 提交 的否定哈希 ID master~2

事实证明,在 Git 1.7.11.3 中首次公开的 commit 修改了命令c5941f1aac071addc1c9b0781c323b588c542420,使其行为与给定提交范围时git show非常相似:git log

git show master~2..master

工作起来很像跑步:

git rev-list master~2..master | while read commit; do git show $commit; done

有一些区别。特别是,git log默认情况下不会显示合并提交的补丁,但git show默认情况下会显示一个补丁,就像您使用过git log --cc. (另一个区别在这里不太重要:带有while read commit; do ...; done序列的 shell 变体必须产生多个git show命令。)

请注意,以git rev-list这种方式调用不会产生任何输出:

$ git rev-list master~2..master:Makefile
$ 

这是因为第二个(非否定的)哈希 ID 是一个 blob 对象的 ID,并且 blob 对象不参与修订遍历。因此,这相当于选择不提交,同时排除所有可从master~2.

事实上,所有这些都安静地运行和退出,没有抱怨,几乎可以肯定是一个错误。..我认为,在or表达式中混合提交哈希和标记或 blob 哈希...应该只会从修订解析代码中得出一个错误。


1副词出现在这里的原因主要是少数命令有特殊处理。特别是,两者都使用两点git diffgit rebase/或三点语法玩特殊技巧:它们不只是让git rev-list工作。


推荐阅读