简体   繁体   English

Git - 为什么在删除的文件上运行命令时需要双短划线?

[英]Git - why are double dashes needed when running a command on a deleted file?

Consider a git repository, where a file was once deleted. 考虑一个git存储库,其中一个文件曾被删除。

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

Ok, now I want to see the git log for the file, but I receive the classic error message: 好的,现在我想看到该文件的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

The solution is simple - add -- : 解决方案很简单 - 添加--

git log -- path/to/file

But... why? 但为什么? Why is this needed? 为什么需要这个? What is the rationale here? 这里的理由是什么? Can't git do an educated guess, that this might have been a file once? 不能git做一个有根据的猜测,这可能是一个文件一次? I understand the "ambiguity" problem - but there never was a tag by that name. 我理解“模棱两可”的问题 - 但从来没有这个名称的标签。 If the file was once deleted, and no tag is present, then choosing "the file interpretation" is always the good choice. 如果文件一旦删除,并且没有标记,那么选择“文件解释”始终是一个不错的选择。

On the other hand, it's possible to have a tag named the same as a file, which git log handles pretty well: 另一方面,可以有一个名为与文件相同的标记, git log处理得非常好:

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

This behavior seems inconsistent. 这种行为似乎不一致。 Could anyone explain what the developers of git had in mind? 任何人都可以解释一下git的开发人员的想法吗?

git log could be used on files as well as on branches, tags and so on. git log可用于文件以及分支,标签等。

Assume you have a folder called a/b/c , you'll get the commits for this folder using 假设您有一个名为a/b/c的文件夹,您将获得此文件夹的提交

git log a/b/c

That's fine. 没关系。

You could also have a branch called d/e/f . 你也可以有一个名为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. 如果git log应该处理的项目无法明确确定,事情开始变得复杂。 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 ? 如果你是愚蠢的并且也给你的分支机构打电话a/b/c ,那么git就没有任何线索可以打印其日志: a/b/c 分支或你的目录日志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 : 显示分支 a/b/c的日志:
    git log a/b/c --
  • show the log of the folder a/b/c in the current branch: 显示当前分支中文件夹 a/b/c的日志:
    git log -- a/b/c
  • show the log of the folder a/b/c in the a/b/c branch: 显示a/b/c分支中文件夹 a/b/c的日志:
    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 . 使用已删除的文件,您会遇到类似的问题:工作副本中既没有名为path/to/file ,也没有名为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. 当然,混帐会知道一个叫做文件path/to/file 20.000修订前但这需要(最坏情况)来搜索项目的整个历史是否存在或没有这样的文件。

By explicitly specifying the file path after the -- , you tell git: 通过在--之后显式指定文件路径,你告诉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. 在你的情况下, --是必要的,因为否则git log将一般工作比较慢。

Why the difference when the file exists versus when it doesn't? 为什么文件存在时的差异与不存在时的区别? Let's look at the cases: 让我们来看看案例:

  1. A revision and filename both exist. 修订版和文件名都存在。 Obviously ambiguous. 显然含糊不清。
  2. A revision exists and filename doesn't. 存在修订版,文件名不存在。 Obviously not ambiguous. 显然不是暧昧。
  3. A revision doesn't exist and a filename does. 修订版不存在,文件名也不存在。 Obviously not ambiguous. 显然不是暧昧。
  4. A revision doesn't exist and a filename doesn't either. 修订版不存在,文件名也不存在。 Ambiguous? 暧昧?

Indeed it is. 的确是。

To know whether a file ever existed at some path means to walk history, opening each commit, opening each tree and walking the tree to see if this path existed then. 要知道文件是否存在于某个路径中意味着遍历历史记录,打开每个提交,打开每个树并走树,以查看此路径是否存在。 On a large repository with a lot of commits and a deep path... this could get expensive, especially on a slow disk. 在具有大量提交和深度路径的大型存储库中......这可能会变得昂贵,尤其是在慢速磁盘上。

But! 但! You say. 你说。 Isn't that exactly what git log filename does anyway? 这究竟是git log filename无论如何都不是吗? And the answer is yes, it is. 答案是肯定的,确实如此。 The difference is that when I run git log filename and the file is known to exist, then git-log knows that I want to spend the time to get this history. 不同的是,当我运行git log filename并且知道该文件存在时, git-log 知道我想花时间来获取这个历史记录。

If, instead, I run git log foo and foo is not a revision or a file that currently exists then it would need to invest the time to walk the entire graph just to tell me that foo was ambiguous. 相反,如果我运行git log foo并且foo不是当前存在的修订版或文件,那么它需要花费时间来遍历整个图表,只是为了告诉我foo是不明确的。

Ouch. 哎哟。

So you're welcome to say git log -- filename to tell git that you really want it to go walking the graph. 所以欢迎你说git log -- filename来告诉git你真的希望它走图表。 Otherwise, it will decline. 否则,它会下降。

Side note: git merely stat(2) s the argument you give on the command line to determine if the file exists. 旁注:git只是stat(2) s在命令行上给出的参数,用于确定文件是否存在。 It doesn't look in the index, nor does it open up your HEAD tree. 它不会查找索引,也不会打开您的HEAD树。 It could, of course, do those things, which would allow you to use git log filename where filename was a deletion not staged for commit. 当然,它可以做那些事情,这将允许你使用git log filename ,其中filename是一个删除而不进行提交。 This seems like a very reasonable change. 这似乎是一个非常合理的变化。

there never was a tag by that name. 那个名字从未有过这个标签。

Why do you say that? 你为什么这么说? git tag path/to/file works just fine. git tag path/to/file工作得很好。

It really is as simple as it looks: git rm takes pathnames only; 它看起来非常简单: git rm只接受路径名; git log takes ref names and path names, refnames first, and anything that could be a pathname could also be a ref name -- this isn't so much a rule for what could be a ref name as the definition. git log获取引用名称和路径名,首先重新命名,任何可能是路径名的东西也可以是引用名称 - 这不是一个规则,可以作为定义的引用名称。

On small projects it'd be easy for git log to decide that if it's valid at all it has to have been a path to a source file at some point, but at this point you have to make a judgement call balancing the likelihood and cost of all the possible screwups here. 在小型项目上,git log很容易决定,如果它有效则必须在某个时刻成为源文件的路径,但此时你必须做出判断调用来平衡可能性和成本这里所有可能的搞砸了。 Is it likelier that you're asking for the logs for a file that no longer exists, or that you fatfingered an existing path name or an existing ref? 您是否更有可能要求提供不再存在的文件的日志,或者您是否使用了现有的路径名或现有的ref? git log remote/ref is very common. git log remote/ref很常见。 I think git's just presuming a name that matches nothing current is likeliest to be a typo. 我认为git只是假设一个名称不匹配当前最有可能成为一个错字。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM