为什么这不起作用:
git log someBranch:path/to/myfile.txt
echo $? # shows 0/success but no output from git log
(这确实有效:)
git rev-parse someBranch:path/to/myfile.txt # this works and returns the SHA
还有另一种方法来获取与特定分支上的特定文件相关的日志/提交(无需检出该分支)吗?
答案 0 :(得分:1)
git log --branches=<regex> -- <filename>
:将所有修改过filename
的提交记录在名称与regex
匹配的分支中。
答案 1 :(得分:0)
之所以无法正常工作,是因为git log
是关于 commits 的,而someBranch:path/to/myfile.txt
是一个 blob 的名字。 Git会用“ blob”一词来表示“提交中存储的文件”。
要完全理解这一点,请通读网站Think Like (a) Git上的说明。但是,为了大致了解它,请阅读以下内容:
Git主要与 commits 有关。毕竟,这与支行无关。这意味着您需要确切地知道什么是提交 ,以及提交和分支之间的区别。这有点粘性,因为Git和使用Git的人们将“ branch”一词的几种不同含义混合在一起。要弄清分支的这两种含义,有助于非常具体地讨论每个分支名称。但是,让我们从提交开始。
任何提交的真实名称都是一个丑陋的哈希ID。您将在git log
输出中看到这些哈希ID:
$ git log
commit c05048d43925ab8edcb36663752c2b4541911231
Author: Junio C Hamano <gitster@pobox.com>
Date: Tue Sep 4 14:33:27 2018 -0700
Git 2.19-rc2
Signed-off-by: Junio C Hamano <gitster@pobox.com>
c0504...1231
是提交的实际名称,正如您所看到的,提交会记住其作者和时间戳。 (还有更多,但我们会在这里停留以保持此空头。)
提交的主要功能有两个:提交使Git永久保留,或者只要提交继续存在(可能也是永久的)就可以保留其中的所有内容的完整快照。存储库。好吧,更准确地说,提交保留了提交中所有内容的快照,但这似乎有点多余:提交具有提交所具有的内容。尽管如此,这是最准确的表达方式。之所以说它具有所有内容的完整快照,是因为其他版本控制系统通常将提交存储为更改,但是Git将它们存储为整个快照。
提交的另一个主要功能是记住其 parent 或先前的提交。您在上方看不到的是c05048d43925ab8edcb36663752c2b4541911231
的父级是e9983f8965c0875cc6727e9644c84ff1dfc99372
。要直接查看,可以使用git cat-file -p c05048d43925ab8edcb36663752c2b4541911231
。但是git log
会看到的,这对我们来说很重要:
向我们展示了一次提交后,git log
继续向我们展示了先前的/父提交。它使用父母的真实姓名(其丑陋的哈希ID大)找到了先前的/父提交。 —存储在提交中。只要我们掌握了提交的丑陋ID,就可以使用它查找实际的提交。我们通常说这个ID 指向提交:它可以让我们找到它。
因此,每个提交都指向其父级。这使得链条向后看。如果我们使用单个大写字母来表示较大的丑陋哈希ID,那么我们会得到更人性化的内容,尽管在仅仅提交26次左右(取决于字母)之后,我们的字母就用光了:
A <-B <-C ... <-H
使用这个单字母系统,很容易找到 last 提交:我们只找到最后一个字母。但是这些代表了真正的,显然是随机的(根本不是随机的,但也不是可预测的)哈希。因此,我们需要以某种方式知道H
是 last 哈希,这就是分支 names 进入的地方。
分支名称,例如master
将 last 提交的哈希ID存储在分支中。 Git将此称为 tip 分支的提交。 名称总是指向尖端提交,所以我们应该这样写:
A <-B <-C ... <-H <--master
如果我们向分支添加一个 new 提交,则Git这样做的方法是使所有现有的提交保持不变,而完全不触及它们。它会产生一些新的丑陋的哈希ID I
,并将I
的父级设置为H
,然后更改名称 master
,因此master
存储I
的哈希ID而不是H
的哈希ID:
A <-B <-C ... <-H <-I <--master
现在,从结尾开始-使用名称master
查找I
-我们可以使用提交I
。提交I
会记住H
的哈希值,因此我们可以使用它来获取H
。 H
记住G
的哈希值,因此我们可以使用 that 到达G
,这使我们到达F
,依此类推,向后。最终,这导致B
和A
,并且由于A
是有史以来的第一个提交,因此它没有父级,我们可以停止。 >
git log
的工作方式 git log
的主要任务是显示一些从某个起点开始的提交(或者我们可以将其称为终点因为Git总是向后工作)。我们可以从 any 提交开始,只要我们具有其哈希ID。但是我们拥有的哈希ID是存储在分支名称中的ID。
上面的图显示了只有一个分支名称时该图的外观。如果分支名称更多,则每个名称都将存储一些 tip (在我们的图形中最右边)提交的哈希ID。每次提交都照常指向其父级。如果我们开始绘制内部箭头只是为了使其更容易连接,这将为我们提供例如
...--F--G--H--I <-- master
\
J--K <-- develop
名称master
表示从I
开始并向后。名称develop
表示从K
开始并向后工作。
(请注意,无论我们是从G
还是从I
开始,随着向后工作,我们最终都会到达提交K
。此问题供您将来探索:哪个分支包含提交G
?我们暂时不在这里解决。)
git log
的输出在任何情况下,git log
都是从结尾开始,然后沿着提交链向后移动,一次向您展示每个提交。在一个大项目中,这可能是很多提交。
每个提交都具有文件 all 的完整快照。如果您在存储库中已经有path/to/myfile.txt
很长时间了,那么path/to/myfile.txt
的副本中会有很多。它们中的许多可能完全相同,如果是这样,Git会 share ,对具有该特定版本的所有提交仅使用一个副本。 Git之所以可以这样做是因为已提交的版本已冻结:没有任何东西可以更改它们。
但是,如果它们与先前的每个提交相同,那么从您的角度来看,这会使每个提交都变得很无聊!如果所有这些提交都具有相同的符号,为什么要从提交Z
开始,然后显示Y
和X
和W
,依此类推? 1}}中?因此,path/to/myfile.txt
可以不显示提交。
您可以要求git log
显示您的提交,从某个起点(结束点)开始并向后进行,但是跳过以显示其中的大部分。您可以说:仅当在比较提交及其父项之后,文件git log
在这两个提交中不同时,才显示每个提交。
也就是说,path/to/myfile.txt
将从结尾开始-提交git log
-并查找Z
的父Z
。如果Y
和path/to/myfile.txt
中的Z
相同,则Y
不会显示git log
。如果不同,则Z
将显示git log
。然后,无论如何,Git将移回Z
。现在,它正在Y
上运行,Git将查找Y
的父Y
。如果X
和path/to/myfile.txt
中的Y
是相同的,则X
将继续前进到git log
。这一直持续到您对X
的输出感到厌倦,或者git log
一直回到最初的提交为止。
要使此工作有效,您必须给git log
正确的开始(结束?)提交。这就是git log
的用处。{{1 }}是从您的当前提交开始的,但是您要从其他特定的提交开始:一些分支名称的提示。 然后,您还必须提供git log branchname
个限制文件。这就是git log
的来源。路径名位于git log
之后,以将其与分支名称分开。如果您有一个名为-- path
的文件,--
将向您显示从master
开始的提交,但是git log master
将向您显示从当前提交开始的提交,但仅限于那些更改了文件master
。
请注意,git log -- master
之后的文件名是否存在并不重要:master
只是检查在回溯历史时提交之间的文件名是否存在差异。如果该文件不在两个提交中,那么它将随时进行比较,这意味着“对该文件没有更改”。如果文件恰好在两个提交中的一个 中,则意味着文件 did 发生了更改(已添加或删除)。如果文件同时在两个快照中,则文件当然也只有在文件更改的情况下才更改。
--
失败的原因现在应该清除使用git log
使git log someBranch:path/to/myfile.txt
查找原始Blob哈希ID。那不是一次提交,因此someBranch:path/to/myfile.txt
无法显示,也不会显示。然后git log
没有 commit 开头,因此也不能向后工作。没有提交显示,它什么也不做,然后退出。 git log
至少应警告您,您的起点(终点?)根本不是一个提交,但实际上不是。