11

考虑一个 git 存储库,其中一个文件曾经被删除。

git rm path/to/file
git commit -a -m"testing"

好的,现在我想查看git log文件,但我收到了经典的错误消息:

git log path/to/file
fatal: ambiguous argument 'path/to/file': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions

解决方案很简单 - 添加--

git log -- path/to/file

但为什么?为什么需要这个?这里的理由是什么?git 不能做一个有根据的猜测,这可能曾经是一个文件吗?我理解“歧义”问题 - 但从来没有那个名字的标签。如果文件曾经被删除,并且没有标签存在,那么选择“文件解释”总是不错的选择。

另一方面,可以有一个与文件同名的标签,它git log处理得很好:

fatal: ambiguous argument 'path/to/file': both revision and filename
Use '--' to separate filenames from revisions

这种行为似乎不一致。谁能解释一下 git 的开发者的想法?

4

3 回答 3

11

git log could be used on files as well as on branches, tags and so on.

Assume you have a folder called a/b/c, you'll get the commits for this folder using

git log a/b/c

That's fine.

You could also have a branch called d/e/f. You'll get the commits for this branch using

git log d/e/f

That's fine too.

Things start to get complicated if the item where git log should work on could not be clearly determined. If you're stupid and call your branch a/b/c too, git has no clue whose log shall be printed: that of the branch a/b/c or the log of your directory a/b/c? Therefore, you have to tell a bit more about the information you want to receive:

  • show the log of the branch a/b/c:
    git log a/b/c --
  • show the log of the folder a/b/c in the current branch:
    git log -- a/b/c
  • show the log of the folder a/b/c in the a/b/c branch:
    git log a/b/c -- a/b/c

With the deleted file, you have a similar problem: there's neither a file called path/to/file present in the working copy, nor is there a branch called path/to/file. This is the reason why you have to specify what you want.

Of course, git could know that there was a file called path/to/file 20.000 revisions ago but this would require (worst case) to search the entire history of your project whether such a file existed or not.

By explicitly specifying the file path after the --, you tell git:

search harder for that file, even if it takes hours


Conclusion (answering your question):
in your case, the -- is needed because otherwise git log would work slower in general.

于 2013-04-12T15:12:49.947 回答
3

为什么文件存在与不存在时的差异?我们来看看案例:

  1. 修订和文件名都存在。显然模棱两可。
  2. 存在修订并且文件名不存在。显然不是模棱两可。
  3. 修订版不存在,文件名存在。显然不是模棱两可。
  4. 修订版不存在,文件名也不存在。模糊的?

它的确是。

要知道某个文件是否曾经存在于某个路径意味着遍历历史、打开每个提交、打开每个树并遍历树以查看该路径当时是否存在。在具有大量提交和深度路径的大型存储库中......这可能会变得昂贵,尤其是在慢速磁盘上。

但!你说。这不正是这样git log filename做的吗?答案是肯定的,是的。不同的是,当我运行git log filename并且知道该文件存在时,便git-log 知道我要花时间来获取此历史记录。

相反,如果我运行git log foo并且 foo 不是当前存在的修订版或文件,那么它将需要花费时间来遍历整个图表,只是为了告诉我这foo是模棱两可的。

哎哟。

所以欢迎你git log -- filename告诉 git 你真的希望它在图表中行走。否则,它将下降。

旁注: git 只是stat(2)您在命令行上提供的参数以确定文件是否存在。它不会查看索引,也不会打开您的 HEAD 树。当然,它可以做这些事情,这将允许您使用git log filename删除filename未上演提交的位置。这似乎是一个非常合理的变化。

于 2013-04-12T14:49:14.440 回答
2

从来没有那个名字的标签。

你为什么这么说? git tag path/to/file工作得很好。

它真的很简单:git rm只接受路径名;git log接受引用名称和路径名称,首先是引用名称,并且任何可能是路径名的东西也可能是引用名称——这对于可能是引用名称的定义来说并不是一个规则。

在小型项目中, git log 很容易确定它是否有效,它必须是某个源文件的路径,但此时您必须做出判断,平衡可能性和成本这里所有可能的错误。您是否更有可能要求不再存在的文件的日志,或者您对现有路径名或现有引用进行了粗略处理? git log remote/ref很常见。我认为 git 只是假设一个与当前不匹配的名称很可能是一个错字。

于 2013-04-12T14:36:24.240 回答