使用 git 在所有本地分支中查找对文件的最新提交 - 在本地分支之间进行比较
Find latest commits to a file across all local branches with git - compare across local branches
所以我正在处理一堆分支。我记得,在其中一个分支上,我对文件做了一些超级智能的更改。但是我不记得这是在哪个分支发生的。
是否有一个 git 命令可以显示我在本地所有分支上对存储库的文件的所有最新更改?
例子
/---D
/
/ /---E
/ /
A - B - C
\
\
\--F
我坐在 C 上,我知道我已经在 D、E 或 F 中对特定文件进行了超级聪明的提交。
我可以一个一个地浏览它们,以查看文件的内容。但我希望有这样的命令:
$ git magic-command-1 "path/to/target/file"
Commit 123456 on branch "F" at 2022-05-19 15:10
Commit 234567 on branch "E" at 2022-05-19 14:33
Commit 345678 on branch "D" at 2022-05-19 11:12
也许还有一些显示差异的东西。
我试过这个:
git log -p -- cypress.development.json
但我不确定它是否显示在所有分支机构中。或者给定的更改显示哪个分支。
我还阅读了 here 关于 --all
标志的内容,但输出没有显示在哪个分支上进行了更改:
我也查看了 --source
-flag,但结果对我来说没有任何意义。
无论我做什么,我都觉得我缺少一个命令来适当地比较所有本地分支中的同一文件。
TL;DR
将 git branch --contains
与您找到的哈希 ID 一起使用。但是:你为什么关心?哈希 ID 就是您真正需要的。
长
你的图有一个基本问题:它没有分支名称。放上一些分支名称,然后问一个关键问题:
/---D <-- br1
/
/ /---E <-- br2
/ /
A - B - C <-- br3
\
\
\--F <-- br4
哪个 分支 是提交 A
的?
警告:这是一个骗人的问题!答案在下面,(我希望)中间有足够的文字,这样你就不能只是作弊和阅读它,而是不得不考虑这个问题。 显而易见的 答案是“在 br3
上”,但这是不对的。 (不是错,只是不对。)
您想做什么
I also read here about something about an --all
-flag ...
使用此标志,然后使用 git describe
或 git branch --contains
与找到的提交哈希 ID,或:
I also looked at the --source
-flag, but the results doesn't really make any sense to me.
--source
标志的作用与 the git log
documentation 的作用相同:
--source
Print out the ref name given on the command line by which each commit was reached.
但是,正如常见的那样,参考手册在这里简洁且充满行话。该标志为您提供 一些 您需要的信息,有时 它将是您需要的一切,但是 git branch --contains
或 git describe
可能仍然 更多 有用。
技巧问题的答案
提交 A
在 每个 分支上。
这里的技巧是在 Git 中,许多提交同时在许多分支上。一些提交可能在 no 分支上。这使我们进入一个单独的 Git 问题,即: What exactly do we mean by "branch"? Git 中的 branch 这个词实际上是模棱两可的,并且被过度使用,有时对几乎失去所有意义的地方。但是,一旦您习惯了疯狂的多重含义,就会发现人类 通常 会自动分配 正确的 含义:分支是 分支名称,但它也是一个remote-tracking名称,一个特定的提交Git更正式地称为 tip 提交,以及 一组以 tip commit 结尾的提交。 Git 分支是所有这些东西,然而,当一个人说“分支”时,他们通常只指这些东西中的 一个 。
要理解这一点,我们需要 可达性 的概念。可达性实际上是 graph-theory 的东西。您绘制的图表是 提交图 ,字母 A
到 F
代表实际提交。每个实际的提交都有一些独特的、大的和丑陋的和 random-looking 哈希 ID,但这些对人类来说太难了,所以我们大多尽可能地忽略它们,或者使用像这样的替代品这些字母 A
到 F
在这里。
每个提交 links 向后 到先前或 parent 提交。在这里,提交 C
links 向后提交 B
,links 向后提交 A
。将 D
links 也提交到 A
,F
也是如此; E
links 倒退到 B
,我们已经注意到 links 倒退到 A
.
通过跟随 backwards-pointing links,Git 找到 提交。 Git 找到 end 提交——分支提示 提交——使用分支名称,这是人类倾向于关心和使用的。但是 Git 从那里向后工作。
当我们从 br1
开始时,Git 将找到提交 D
,然后向后工作并找到提交 A
。这意味着提交 A
在分支 br1
上,或“包含在其中”。但是我们也可以从br2
开始,找到A
,我们可以从br3
开始,找到A
,等等。事实上,由于 A
是我们的第一个提交,all roads lead to Rome A
:提交 A
在 每个 分支上。它也会出现在未来的分支上。1
在 Git 中几乎不可能知道提交是在哪个分支上 创建的 除非您将其记录为提交消息中的文本。那是因为我们可以随意创建和销毁分支名称:每个分支 name 只是选择(或“指向”)一些提交 in 提交图.我们在创建分支名称时选择此提交。
然后,当我们签出(切换到)分支并进行新提交时,Git使新提交,使其向后指向我们已签出的提交,并且 将新提交的哈希 ID 存储到分支名称 中,以便新提交现在是 tip 提交。因此,根据您的图表,如果我们 git switch br3
并进行新的提交,名称 br3
将指向我们之后的新提交 G
; G
将向后指向 C
;并且提交 A
保留在每个分支上。
如果我们 完全删除 分支名称 br1
,提交 D
将变为 un-findable,因为我们发现提交使用分支名称并向后工作.现在只有一种方法可以找到 D
,那就是使用 br1
。因此,通过删除 name br1
,我们“丢失”了提交 D
。变成不可达.2
所以 可达性 的意思是“我们如何到达那里”。我们从分支名称开始提交。有关此概念的更多信息,请参阅 Think Like (a) Git.
1它是可能的,在Git中创建多个根提交,因此设置新的不 的分支导致返回提交 A
。但这不是很典型,我们不会在这里介绍。
2Git 最终会 discard 一个无法访问的提交。但是,您确实可以获得宽限期来取回提交,通常至少为 30 天。问题是你必须找到提交的唯一哈希 ID,你可以使用分支名称来完成,但是现在分支名称已经消失了......好吧,这就是两难选择。
可达性,git branch --contains
,git log --source
既然您了解了可达性,git branch --contains
就有意义了。您给 git branch --contains
一些哈希 ID,例如提交 B
或 E
或 A
的哈希 ID。 git branch --contains
所做的是:
- 从每个分支名称开始,向后计算;
- 如果到达提交,打印分支名称
所以当与提交哈希 ID B
一起使用时,这将打印 br2
和 br3
,因为这是两个分支名称可以达到 B
.
git log
的 --source
选项只是打印 git log
在发现某个提交 时正在使用的任何名称 。这其实更解释起来比较复杂,因为git log
本身就很复杂!
git log
所做的是走图,打印它在运行过程中遇到的一些提交。也就是说,我们给 git log
一些起点,例如一个或多个分支名称或提交哈希 ID。 git log
命令获取这些名称并将它们解析为哈希 ID,或者获取哈希 ID(已经是哈希 ID),并找到命名的提交。它将每个提交放入 priority queue.
如果我们 运行 git log
没有 个参数,git log
使用特殊名称 HEAD
。此名称通常 附加到 一个分支名称。使用git switch
或git checkout
,我们控制哪个分支名称 HEAD
是attached-to;这是我们进行新提交时得到 extended 的分支,所以它非常重要!该分支名称是 当前分支 ,这就是 git log
默认显示的内容:即 运行ning git log
和 no 参数意味着 git log
将 HEAD
解析为 当前 提交的提交哈希 ID,并将该(单个)哈希 ID 放入队列中。
现在队列中有一些提交或提交,git log
从队列中取出 front 条目。由于队列是优先级队列,所以有一个排序顺序,如果里面有多个条目。但是队列只有一个条目是非常常见的!例如,如果我们 运行 git log
没有参数,那么 当前提交 就是我们开始时其中的一个条目。如果我们 运行 git log br1
,Git 将 F
的哈希 ID 放入其中,同样只有一个条目。
无论如何,在队列的 front 入口 out 之后,git log
现在决定,基于你的任何参数给了 --no-merges
之类的东西,是否 show 这个提交。如果它应该显示提交,它就会那样做。我们称此为访问提交,就好像我们正在度假并去某些景点或城市或其他地方一样。
接下来,显示或未显示提交后,git log
找到提交的 parent 或 parents。在您的示例图中,每个提交都有 one parent,除了提交 A
有 no parent. (一个合并提交,如果有的话,会有两个 parents。)默认情况下,git log
将 所有 parents 放入队列,除非那些 parent 已经被访问过。
有了它的 parent,如果我们刚刚访问了 F
,git log
就会把 F
的 parent A
进入队列。队列 是 空的——F
是所有这一切开始时队列中唯一的东西——所以现在队列中又只有一个条目。 git log
命令现在取出并访问 队列中的一个提交 ,即提交 A
。它显示提交 A
,如果它应该这样做,然后将 A
的 parent 放入队列。没有 parents,所以这不会在队列中放入任何内容,队列仍然是空的。
一旦队列像这样为空,git log
退出。因此,通过名称 br4
从 F
开始,我们访问提交 F
和 A
并停止,就是这样git log
会显示。
另一方面,如果我们 运行 git log --all
,代码将放入 D
、E
、C
和 F
全部进入队列。现在有 四个条目 所以优先级真的很重要。此优先级导致 git log
对其输出进行 排序 。默认排序基于每次提交中存储的提交者日期,较晚的提交具有更高的优先级。因此,如果提交 F
是 最新的 提交,那么它就是第一个出现的提交。
我们将访问F
,将其打印出来并将其parent A
放入队列:队列现在包含A
、D, E
和 C
(按日期顺序)。假设 E
有 next-highest-priority 日期:git log
将从队列中弹出 E
,访问它,然后将 B
插入队列。然后 git log
将从队列中取出最高优先级的提交——让我们继续主题并说这是 D
——然后访问那个。这会将 A
放入队列,但它已经在那里了;它不会进入两次。我们现在访问C
,它想把B
放入队列,但是它已经在了;然后我们访问 B
,它想将 A
放入队列,但它已经在那里了;然后我们访问 A
,这是队列中的最后一个东西,没有将任何东西 放入 队列,因此 git log
最终停止。
--source
标志简单地注释每个 输出 ,对于任何给定的提交,name 首先导致 Git 到这个提交。所以对于 C
,就是 br3
.3 对于 B
,就是 br2
或者 br3
,取决于 git log
是先访问 C
还是 E
。
访问顺序取决于优先顺序。至少在某种程度上,您可以使用 --topo-order
或 --author-date-order
等选项来控制它。但是在一个大图中,尤其是其中有很多 branch-and-merge 动作的图中,很难知道许多名字中的哪一个可能首先到达某个提交。只有在像您这里这样的小而简单的图表中,您才能得到可预测的结果。
3使用 git log --all
你会看到 refs/heads/br3
而不仅仅是 br3
。这只是分支机构的全名。所有分支都有像 br3
这样的短名称,以及像 refs/heads/br3
这样的完整名称。我喜欢把全名想象成他们的妈妈(或配偶)生他们的气时说的话,有点像 Stella Mudd in these ST:TOS clips。
分支名称无关紧要
在顶部,我问你为什么关心一些提交是“on”的。有时您实际上会关心,然后问 哪些分支包含此提交 的问题就可以了。但是,如果您只想 查看 文件,或将其视为更改,只需告诉 Git 显示文件或显示更改即可:
git show a123456:path/to/file
或:
git show a123456 -- path/to/file
前者显示存储在命名提交中的命名文件的内容。后者采用命名提交(使用缩写的提交哈希 a123456
),找到其 parent(单数4) , 和 运行s git diff
两次提交。然后,由于最后的 -- path/to/file
pathspec,它只显示该文件的差异。所以你会看到在那个文件中,在那个提交中,关于它的 parent.
发生了什么变化
您甚至可以从提交的 中提取整个文件,覆盖当前的工作树副本,git restore
:
git restore --source=a123456 --worktree -- path/to/file
当然,你应该首先确保你在path/to/file
中没有任何有价值的东西,因为你的工作树中的副本是not in Git 和 Git 在你告诉 Git 到 overwrite 之后无法取回它。只有 提交的 个文件实际存储在 Git.
这——保存的文件副本,或来自 parent 的更改——通常是您关心的全部内容。一旦您拥有提交的 哈希 ID,就很容易获得这些。该哈希 ID 是提交的“真实名称”:它 始终有效 来识别 那个特定的提交 .
分支名称在Git中的意义只是为了帮助您找到提交。哈希 ID 是它们的 真实 名称。它们实在太难对付了:我们必须使用鼠标 cut-and-paste 或其他方式,一旦我们找到它们。但是,如果您有 运行 打印您关心的提交的哈希 ID 的命令,只需用鼠标抓住它并开始工作!
4A merge commit,其中有两个或更多 parents,这里会导致问题。每个提交都包含每个文件 的完整快照 。因此,要查看某些提交中 更改了 的内容,我们 Git 使用其 backwards-pointing link 从提交到 parent。 parent 也有一个完整的快照,所以 parent 提交包含相同的文件,除非文件本身是 all-new。 Git 然后可以从每个提交中提取文件并比较这两个文件并告诉您发生了什么变化。
但是 merge 提交有 两个或更多 parents。这就是首先将其定义为合并提交的原因。由于它至少有两个 parent,我们不再知道 哪个 parent 承诺使用 来获取文件的“较早”版本。有两个或更多的早期版本! git log
命令,当用作 git log -p
将提交显示为补丁时,默认情况下 作弊 :它只是 不显示任何内容全部。默认情况下,git show
命令会更努力地工作,做一些 Git 调用 组合差异 。不过我们不会在这里详细介绍。
所以我正在处理一堆分支。我记得,在其中一个分支上,我对文件做了一些超级智能的更改。但是我不记得这是在哪个分支发生的。
是否有一个 git 命令可以显示我在本地所有分支上对存储库的文件的所有最新更改?
例子
/---D
/
/ /---E
/ /
A - B - C
\
\
\--F
我坐在 C 上,我知道我已经在 D、E 或 F 中对特定文件进行了超级聪明的提交。
我可以一个一个地浏览它们,以查看文件的内容。但我希望有这样的命令:
$ git magic-command-1 "path/to/target/file"
Commit 123456 on branch "F" at 2022-05-19 15:10
Commit 234567 on branch "E" at 2022-05-19 14:33
Commit 345678 on branch "D" at 2022-05-19 11:12
也许还有一些显示差异的东西。
我试过这个:
git log -p -- cypress.development.json
但我不确定它是否显示在所有分支机构中。或者给定的更改显示哪个分支。
我还阅读了 here 关于 --all
标志的内容,但输出没有显示在哪个分支上进行了更改:
我也查看了 --source
-flag,但结果对我来说没有任何意义。
无论我做什么,我都觉得我缺少一个命令来适当地比较所有本地分支中的同一文件。
TL;DR
将 git branch --contains
与您找到的哈希 ID 一起使用。但是:你为什么关心?哈希 ID 就是您真正需要的。
长
你的图有一个基本问题:它没有分支名称。放上一些分支名称,然后问一个关键问题:
/---D <-- br1
/
/ /---E <-- br2
/ /
A - B - C <-- br3
\
\
\--F <-- br4
哪个 分支 是提交 A
的?
警告:这是一个骗人的问题!答案在下面,(我希望)中间有足够的文字,这样你就不能只是作弊和阅读它,而是不得不考虑这个问题。 显而易见的 答案是“在 br3
上”,但这是不对的。 (不是错,只是不对。)
您想做什么
I also read here about something about an
--all
-flag ...
使用此标志,然后使用 git describe
或 git branch --contains
与找到的提交哈希 ID,或:
I also looked at the
--source
-flag, but the results doesn't really make any sense to me.
--source
标志的作用与 the git log
documentation 的作用相同:
--source
Print out the ref name given on the command line by which each commit was reached.
但是,正如常见的那样,参考手册在这里简洁且充满行话。该标志为您提供 一些 您需要的信息,有时 它将是您需要的一切,但是 git branch --contains
或 git describe
可能仍然 更多 有用。
技巧问题的答案
提交 A
在 每个 分支上。
这里的技巧是在 Git 中,许多提交同时在许多分支上。一些提交可能在 no 分支上。这使我们进入一个单独的 Git 问题,即: What exactly do we mean by "branch"? Git 中的 branch 这个词实际上是模棱两可的,并且被过度使用,有时对几乎失去所有意义的地方。但是,一旦您习惯了疯狂的多重含义,就会发现人类 通常 会自动分配 正确的 含义:分支是 分支名称,但它也是一个remote-tracking名称,一个特定的提交Git更正式地称为 tip 提交,以及 一组以 tip commit 结尾的提交。 Git 分支是所有这些东西,然而,当一个人说“分支”时,他们通常只指这些东西中的 一个 。
要理解这一点,我们需要 可达性 的概念。可达性实际上是 graph-theory 的东西。您绘制的图表是 提交图 ,字母 A
到 F
代表实际提交。每个实际的提交都有一些独特的、大的和丑陋的和 random-looking 哈希 ID,但这些对人类来说太难了,所以我们大多尽可能地忽略它们,或者使用像这样的替代品这些字母 A
到 F
在这里。
每个提交 links 向后 到先前或 parent 提交。在这里,提交 C
links 向后提交 B
,links 向后提交 A
。将 D
links 也提交到 A
,F
也是如此; E
links 倒退到 B
,我们已经注意到 links 倒退到 A
.
通过跟随 backwards-pointing links,Git 找到 提交。 Git 找到 end 提交——分支提示 提交——使用分支名称,这是人类倾向于关心和使用的。但是 Git 从那里向后工作。
当我们从 br1
开始时,Git 将找到提交 D
,然后向后工作并找到提交 A
。这意味着提交 A
在分支 br1
上,或“包含在其中”。但是我们也可以从br2
开始,找到A
,我们可以从br3
开始,找到A
,等等。事实上,由于 A
是我们的第一个提交,all roads lead to Rome A
:提交 A
在 每个 分支上。它也会出现在未来的分支上。1
在 Git 中几乎不可能知道提交是在哪个分支上 创建的 除非您将其记录为提交消息中的文本。那是因为我们可以随意创建和销毁分支名称:每个分支 name 只是选择(或“指向”)一些提交 in 提交图.我们在创建分支名称时选择此提交。
然后,当我们签出(切换到)分支并进行新提交时,Git使新提交,使其向后指向我们已签出的提交,并且 将新提交的哈希 ID 存储到分支名称 中,以便新提交现在是 tip 提交。因此,根据您的图表,如果我们 git switch br3
并进行新的提交,名称 br3
将指向我们之后的新提交 G
; G
将向后指向 C
;并且提交 A
保留在每个分支上。
如果我们 完全删除 分支名称 br1
,提交 D
将变为 un-findable,因为我们发现提交使用分支名称并向后工作.现在只有一种方法可以找到 D
,那就是使用 br1
。因此,通过删除 name br1
,我们“丢失”了提交 D
。变成不可达.2
所以 可达性 的意思是“我们如何到达那里”。我们从分支名称开始提交。有关此概念的更多信息,请参阅 Think Like (a) Git.
1它是可能的,在Git中创建多个根提交,因此设置新的不 的分支导致返回提交 A
。但这不是很典型,我们不会在这里介绍。
2Git 最终会 discard 一个无法访问的提交。但是,您确实可以获得宽限期来取回提交,通常至少为 30 天。问题是你必须找到提交的唯一哈希 ID,你可以使用分支名称来完成,但是现在分支名称已经消失了......好吧,这就是两难选择。
可达性,git branch --contains
,git log --source
既然您了解了可达性,git branch --contains
就有意义了。您给 git branch --contains
一些哈希 ID,例如提交 B
或 E
或 A
的哈希 ID。 git branch --contains
所做的是:
- 从每个分支名称开始,向后计算;
- 如果到达提交,打印分支名称
所以当与提交哈希 ID B
一起使用时,这将打印 br2
和 br3
,因为这是两个分支名称可以达到 B
.
git log
的 --source
选项只是打印 git log
在发现某个提交 时正在使用的任何名称 。这其实更解释起来比较复杂,因为git log
本身就很复杂!
git log
所做的是走图,打印它在运行过程中遇到的一些提交。也就是说,我们给 git log
一些起点,例如一个或多个分支名称或提交哈希 ID。 git log
命令获取这些名称并将它们解析为哈希 ID,或者获取哈希 ID(已经是哈希 ID),并找到命名的提交。它将每个提交放入 priority queue.
如果我们 运行 git log
没有 个参数,git log
使用特殊名称 HEAD
。此名称通常 附加到 一个分支名称。使用git switch
或git checkout
,我们控制哪个分支名称 HEAD
是attached-to;这是我们进行新提交时得到 extended 的分支,所以它非常重要!该分支名称是 当前分支 ,这就是 git log
默认显示的内容:即 运行ning git log
和 no 参数意味着 git log
将 HEAD
解析为 当前 提交的提交哈希 ID,并将该(单个)哈希 ID 放入队列中。
现在队列中有一些提交或提交,git log
从队列中取出 front 条目。由于队列是优先级队列,所以有一个排序顺序,如果里面有多个条目。但是队列只有一个条目是非常常见的!例如,如果我们 运行 git log
没有参数,那么 当前提交 就是我们开始时其中的一个条目。如果我们 运行 git log br1
,Git 将 F
的哈希 ID 放入其中,同样只有一个条目。
无论如何,在队列的 front 入口 out 之后,git log
现在决定,基于你的任何参数给了 --no-merges
之类的东西,是否 show 这个提交。如果它应该显示提交,它就会那样做。我们称此为访问提交,就好像我们正在度假并去某些景点或城市或其他地方一样。
接下来,显示或未显示提交后,git log
找到提交的 parent 或 parents。在您的示例图中,每个提交都有 one parent,除了提交 A
有 no parent. (一个合并提交,如果有的话,会有两个 parents。)默认情况下,git log
将 所有 parents 放入队列,除非那些 parent 已经被访问过。
有了它的 parent,如果我们刚刚访问了 F
,git log
就会把 F
的 parent A
进入队列。队列 是 空的——F
是所有这一切开始时队列中唯一的东西——所以现在队列中又只有一个条目。 git log
命令现在取出并访问 队列中的一个提交 ,即提交 A
。它显示提交 A
,如果它应该这样做,然后将 A
的 parent 放入队列。没有 parents,所以这不会在队列中放入任何内容,队列仍然是空的。
一旦队列像这样为空,git log
退出。因此,通过名称 br4
从 F
开始,我们访问提交 F
和 A
并停止,就是这样git log
会显示。
另一方面,如果我们 运行 git log --all
,代码将放入 D
、E
、C
和 F
全部进入队列。现在有 四个条目 所以优先级真的很重要。此优先级导致 git log
对其输出进行 排序 。默认排序基于每次提交中存储的提交者日期,较晚的提交具有更高的优先级。因此,如果提交 F
是 最新的 提交,那么它就是第一个出现的提交。
我们将访问F
,将其打印出来并将其parent A
放入队列:队列现在包含A
、D, E
和 C
(按日期顺序)。假设 E
有 next-highest-priority 日期:git log
将从队列中弹出 E
,访问它,然后将 B
插入队列。然后 git log
将从队列中取出最高优先级的提交——让我们继续主题并说这是 D
——然后访问那个。这会将 A
放入队列,但它已经在那里了;它不会进入两次。我们现在访问C
,它想把B
放入队列,但是它已经在了;然后我们访问 B
,它想将 A
放入队列,但它已经在那里了;然后我们访问 A
,这是队列中的最后一个东西,没有将任何东西 放入 队列,因此 git log
最终停止。
--source
标志简单地注释每个 输出 ,对于任何给定的提交,name 首先导致 Git 到这个提交。所以对于 C
,就是 br3
.3 对于 B
,就是 br2
或者 br3
,取决于 git log
是先访问 C
还是 E
。
访问顺序取决于优先顺序。至少在某种程度上,您可以使用 --topo-order
或 --author-date-order
等选项来控制它。但是在一个大图中,尤其是其中有很多 branch-and-merge 动作的图中,很难知道许多名字中的哪一个可能首先到达某个提交。只有在像您这里这样的小而简单的图表中,您才能得到可预测的结果。
3使用 git log --all
你会看到 refs/heads/br3
而不仅仅是 br3
。这只是分支机构的全名。所有分支都有像 br3
这样的短名称,以及像 refs/heads/br3
这样的完整名称。我喜欢把全名想象成他们的妈妈(或配偶)生他们的气时说的话,有点像 Stella Mudd in these ST:TOS clips。
分支名称无关紧要
在顶部,我问你为什么关心一些提交是“on”的。有时您实际上会关心,然后问 哪些分支包含此提交 的问题就可以了。但是,如果您只想 查看 文件,或将其视为更改,只需告诉 Git 显示文件或显示更改即可:
git show a123456:path/to/file
或:
git show a123456 -- path/to/file
前者显示存储在命名提交中的命名文件的内容。后者采用命名提交(使用缩写的提交哈希 a123456
),找到其 parent(单数4) , 和 运行s git diff
两次提交。然后,由于最后的 -- path/to/file
pathspec,它只显示该文件的差异。所以你会看到在那个文件中,在那个提交中,关于它的 parent.
您甚至可以从提交的 中提取整个文件,覆盖当前的工作树副本,git restore
:
git restore --source=a123456 --worktree -- path/to/file
当然,你应该首先确保你在path/to/file
中没有任何有价值的东西,因为你的工作树中的副本是not in Git 和 Git 在你告诉 Git 到 overwrite 之后无法取回它。只有 提交的 个文件实际存储在 Git.
这——保存的文件副本,或来自 parent 的更改——通常是您关心的全部内容。一旦您拥有提交的 哈希 ID,就很容易获得这些。该哈希 ID 是提交的“真实名称”:它 始终有效 来识别 那个特定的提交 .
分支名称在Git中的意义只是为了帮助您找到提交。哈希 ID 是它们的 真实 名称。它们实在太难对付了:我们必须使用鼠标 cut-and-paste 或其他方式,一旦我们找到它们。但是,如果您有 运行 打印您关心的提交的哈希 ID 的命令,只需用鼠标抓住它并开始工作!
4A merge commit,其中有两个或更多 parents,这里会导致问题。每个提交都包含每个文件 的完整快照 。因此,要查看某些提交中 更改了 的内容,我们 Git 使用其 backwards-pointing link 从提交到 parent。 parent 也有一个完整的快照,所以 parent 提交包含相同的文件,除非文件本身是 all-new。 Git 然后可以从每个提交中提取文件并比较这两个文件并告诉您发生了什么变化。
但是 merge 提交有 两个或更多 parents。这就是首先将其定义为合并提交的原因。由于它至少有两个 parent,我们不再知道 哪个 parent 承诺使用 来获取文件的“较早”版本。有两个或更多的早期版本! git log
命令,当用作 git log -p
将提交显示为补丁时,默认情况下 作弊 :它只是 不显示任何内容全部。默认情况下,git show
命令会更努力地工作,做一些 Git 调用 组合差异 。不过我们不会在这里详细介绍。