Git 表示分支已合并,但更改显然不存在
Git says branch is merged, but changes are apparently not present
我曾将自己置于一种对我来说毫无意义的境地。我会尽力描述它。
我有一个开发分支,我已经通过 git checkout develpment && git merge master
将 master 合并到其中。我在这里没有遇到任何合并冲突。
有一个我感兴趣的特定提交,假设它是 abcd123
。当我运行git branch --contains abcd123
时,它报告development
和master
都包含abcd123
。当我执行 git log
时,它会在 development
和 master
.
的提交列表中显示 abcd123
git show abcd123
显示包含对两个文件的更改。但我似乎无法找到这些变化。当我查看文件时,在 development
和 master
上都没有看到这些更改。当我检查 git log -- path/to/file1
时,我没有看到 abcd123
,git log -- path/to/file2
也是如此。
这是怎么回事?怎么会有commit存在,而修改显然不存在?
可能 abcd123
最初是在合并到 master
的另一个分支(development
以外的分支)中引入的。我不知道这是否会有所作为。
顺便说一下,当我尝试 git checkout master && git merge development
(如上所示将 master
合并到 development
之后)时,我遇到了很多合并冲突,包括 file1 和 file2。因此,这似乎表明 master
实际上并未合并到 development
中——如果 git merge master
已经执行,git merge development
不应该成功吗?为了引起更多混淆,git branch --merged development
说 master
已合并到 development
。我想这与 git merge master
....
一致
非常感谢此时的任何建议。
编辑:在这一点上,问题似乎是由于合并失败或以某种方式搞砸了。如果有人还在阅读,我认为 torek 的回答的方向似乎是最有成果的。
这个答案很长,因为这里发生了很多事情。不过,TL;DR 摘要可能是您想要 --full-history
.
这里有多个单独的问题需要解决:
- 短语 "show changes",或者您在
git log -p
或 git show
中看到的内容,通常会导致人们在解释 Git 存储的内容时走上错误的道路。
git log
命令有时会对您撒谎(尤其是在合并时),纯粹是为了避免让您被无用的信息淹没。
git merge
的作用可能有点棘手。原则上很简单,但大多数人不会马上明白。
普通提交
让我们先看看 Git 最常见的普通提交。 Git 中的提交是 快照 (file-contents 的文件名)。您进行一次提交,然后更改一些内容和 git add
一两个更改的文件并进行第二次提交,第二次提交与第一次提交 所有相同的文件提交,除了被 git add
.
覆盖的那些
值得将这些作为 Git 的 提交图 的一部分进行绘制。请注意,每个提交都有自己唯一的哈希 ID(impossible-to-remember 字符串之一,如 93aefc
或 badf00d
或 cafedad
),加上 的 ID parent(或之前的)提交。父提交哈希让 Git 以向后的方式将这些东西串在一起:
... <-E <-F <-G ...
其中每个大写字母代表一个哈希 ID,箭头表示每个提交 "points back" 到其父节点的想法。通常我们不需要绘制内部箭头(最后它们不是很有趣)所以我将它们绘制为:
...--E--F--G <-- master
然而,namemaster
仍然值得一个箭头,因为这个箭头指向的提交会随着时间而改变。
如果我们选择像 G
这样的提交并使用 git log -p
或 git show
查看它 而没有 ,我们将看到每个文件的完整内容,与存储在提交中的完全一样。事实上,这就是我们使用 git checkout
检查时发生的情况:我们将所有文件完整提取到 work-tree 中,以便我们可以查看和处理它们。但是当我们用 git log -p
或 git show
查看它时,Git 并没有向我们展示所有内容;它只向我们展示了发生了什么变化。
为此,Git 提取提交 和 其父提交,然后 运行 在对上添加一个大的 git diff
.父 F
和子 G
之间的任何不同,都是 改变的 ,所以这就是 git log -p
或 git show
向您展示的内容.
合并提交
这对于普通的 single-parent 提交来说很好,但它不适用于 merge 提交。合并提交只是具有两个(或更多,但我们不会担心这种情况)父提交的任何提交。你通过成功的 git merge
得到这些,我们可能会像这样画出来。我们从两个分支开始(从一些 starting-point 分支出来):
H--I <-- development (HEAD)
/
...--E--F--G <-- master
然后我们 运行 git merge master
.1 Git 现在尝试合并这两个分支。如果成功,它会进行一个新的提交,该提交有 两个 个父项:
H--I--J <-- development (HEAD)
/ /
...--E--F--G <-- master
名称 development
现在指向新的合并提交 J
。这里括号(HEAD)
表示这是我们的当前分支。这告诉我们哪个 name 被移动了:我们做了一个新的提交——包括任何新的合并提交——而 development
是更改为指向新的 branch-name提交。
如果我们不担心合并提交的内容(各种提交的文件)是如何确定的,这一切都非常简单。合并提交就像任何其他提交一样:它有一个完整的快照,一堆包含内容的文件。我们检查合并提交,这些内容像往常一样进入我们的 work-tree。
但是当我们去 查看 合并提交时......好吧,Git 通常会根据其父级区分提交。合并有 两个 个父项,每个分支一个。 Git 应该比较哪一个,以向您展示变化?
在这里,git log
和 git show
采用不同的方法。当您使用 git log
查看提交时,它默认显示 什么都没有 。不会选I
-vs-J
,也不会选G
-vs-J
!对于 git log -p
.
,它什么也没显示
1在某些 Git 工作流中,不鼓励将 from master 合并到任何其他分支。不过它可以工作,既然你这样做了,让我们运行使用它。
查看合并提交
git show
命令做了一些不同且更好的事情。它运行s 两个 git diff
s,一个用于I
-vs-J
,一个用于G
-vs -J
。然后它会尝试 合并 这两个差异,只向您显示 both 中发生的变化。也就是说,J
不同于I
但不是特别 有趣 的方式,Git 抑制了差异。 J
不同于 G
但不是特别 有趣的 方式,Git 也抑制了这种差异。这可能是最有用的模式,所以它就是 git show
显示的内容。它仍然很不完美,但是您在这里所做的一切都不是完美的。
您可以通过将 --cc
添加到 git log -p
选项来让 git log
做同样的事情。或者,您可以使用 -m
(请注意 -m
的一个破折号,--cc
的两个破折号。
-m
选项告诉 Git 为了查看目的,它应该 拆分 合并。现在 Git 将 I
与 J
进行比较,以向您展示通过合并 G
带来的所有内容。然后 Git 将 G
与 J
的 split-off 额外版本进行比较,以向您展示通过合并 I
带来的所有内容。产生的差异通常非常大,但(或因为)它向您展示了 一切。
有更多方法可以尝试查找某个文件发生了什么,但我们需要稍等片刻才能找到您的:
git log -- path/to/file1
命令。正如我们看到 git log
skipping 合并一样,它可能会在这里跳过更多的东西(但有一些方法可以阻止 Git 这样做)。
实际进行合并:Git 如何构建合并的内容
让我们再看看那个 pre-merge 图:
H--I <-- development (HEAD)
/
...--E--F--G <-- master
此处,分支 development
上有两个不在分支 master
上的提交,还有两个 master
上不在 development
上的提交。提交 E
(连同 all 之前的提交)在 both 分支上。不过,提交 E
是特殊的:它是两个分支上的 最近的 2 提交。提交 E
是 Git 调用的 合并基础 。
要执行合并,Git 有效地 运行 两个 git diff
命令:
git diff E I
git diff E G
首先产生一组对各种文件的修改,即"what we did on branch development
"。实际上,如果将它们视为补丁,则它是 H
和 I
的总和。第二个产生了一组——可能不同的——对各种文件的更改,"what we did on master
",和以前一样,它实际上是 F
和 G
作为补丁的总和。
Git 然后尝试合并这两个差异。无论它们之间是完全独立的,它都需要 both 组更改,将它们应用于提交 E
的内容,并将其用作结果。每当两个 change-sets 触及 same 文件中的同一行时,Git 会尝试查看它是否可以只复制该更改的一个副本。如果两者都修复了文件 README
第 33 行的一个单词的拼写,Git 可以仅获取 一份 的拼写修复。但是只要两个 change-sets 触及同一个文件的同一行,但进行 不同的 更改, Git 声明一个 "merge conflict",抛出其隐喻举起手来,让你解决由此产生的混乱。
如果您(或进行合并的任何人)愿意,他们可以阻止 Git 提交合并结果,即使 Git 认为一切顺利:git merge --no-commit master
使 Git 合并所有内容后停止。此时,您可以在编辑器中打开 work-tree 个文件,更改 它们,写回,git add
更改的文件,以及 git commit
merge 将不是来自三个输入(基础和两个 branch-tips)中的 any 的东西放入合并中。
无论如何,理解所有这些的关键是 merge base 提交的概念。如果您坐下来绘制提交图,合并基础通常非常明显,除非图失控(实际上这种情况经常发生)。您还可以让 Git 为您找到合并基础——或者合并基础,复数,在某些情况下:
git merge-base --all master development
这会打印出一个散列 ID。在我们这里的假设情况下,这将是提交 E
的哈希 ID。一旦你有了它,你可以手动 运行 git diff
来查看每个文件发生了什么。或者你可以 运行 一个 individual-file git diff
:
git diff E development -- path/to/file1
git diff E master -- path/to/file1
请注意,如果您将名称 master
和 development
替换为 是 当前 之前的提交的哈希 ID =341=] 你做了 git merge
,这甚至在 合并后也有效。这将告诉您 Git 认为它应该为 path/to/file1
组合什么。反过来,这会告诉您 Git 是否没有看到更改,或者是否进行了合并 overrode Git,或者是否错误地处理了冲突的合并。
合并后,后续合并将找到不同的合并基础:
H--I--J----K <-- development
/ /
...--E--F--G--L--M <-- master
我们现在查看两个分支提示并通过历史(向左方向)向后工作,遵循像 J
这样的合并的两个分支,以找到我们可以从 both 分支提示中获得第一个提交。从 K
开始,我们回到 J
,然后回到 I
和 G
。从 M
开始,我们回到 L
,然后到 G
。我们发现 G
在两个分支上,所以提交 G
是新的合并基础。 Git 将 运行:
git diff G K
git diff G M
让两个 change-sets 应用于 merge-base 提交 G
。
2"Most recent"这里指的是commit graph顺序,而不是时间戳,虽然可能也是commit with两个分支上的最新时间戳。
Git 再次记录和简化谎言
我们已经看到 git log -p
直接跳过了合并提交。您根本看不到任何差异,就好像合并完全是魔术一样。但是当你 运行:
git log -- path/to/file1
还有其他更阴险的事情发生了。在 the (long) git log
documentation under the section titled History Simplification.
中对此进行了描述,尽管相当不透明
在我们上面的例子中,假设 git log
从 K
向后走。它找到 J
,这是一个合并。然后它检查 I
和 G
,将每个文件与 J
进行比较,在排除所有文件后,除了您正在查看的一个文件。 也就是说,它是只是比较三个提交中的 path/to/file1
。
如果合并的一侧 没有 显示对 path/to/file1
的任何更改,这意味着合并结果 J
与输入没有区别(I
或 G
)。 Git 称之为 "TREESAME"。如果合并 J
,在被剥离到这个文件之后,匹配 I
或 G
类似 stripped-down,那么 J
是 TREESAME 到 I
或 G
(或两者)。在这种情况下,Git 选择 TREESAME parent(s) 或其中任何一个,并在该路径上 only 查找。假设它选择 I
(沿着顶行)而不是 G
(沿着底部)。
在我们的例子中,这意味着如果有人在合并过程中失误,丢失了本应从 F
进入 J
的更改,git log
永远不会显示它。 log
命令查看K
,然后查看J
,然后查看但丢弃G
,只查看I
,然后查看H
,然后是 E
,然后是任何更早的提交。它从不查看提交 F
!所以我们没有看到从 F
.
到 path/to/file1
的变化
这里的逻辑很简单;我将直接引用 git log
文档,但添加一些重点:
[Default mode] Simplifies the history to the simplest history explaining the final state of the tree. Simplest because it prunes some side branches if the end result is the same ...
由于 F
中的更改已删除,Git 声明它们无关紧要。你不需要看到他们!我们将完全忽略合并的那一面!
你可以用--full-history
彻底打败它。这告诉 Git not p运行e 合并的任一侧:它应该查看两个历史记录。这将为您找到提交 F
。添加 -m -p
还应该找到 where 更改被删除,因为它会找到 all 涉及文件的提交:
git log -m -p --full-history -- path/to/file1
如果更改存在(在我们的示例中提交 F
)并且不再存在,则只有两种方式丢失它们:
它们在普通提交中被还原(使用 git revert
,或手动)。即使没有 -m
,您也会将其视为在历史记录中触及 path/to/file1
的提交; -p
会告诉你差异。
或者,它们在合并过程中丢失了。即使没有 -m
,您也会看到合并,但不确定进行合并的人是否在此处丢球;但是 -m -p
将显示两个父差异,包括 应该(但没有)进行更改的差异。
我曾将自己置于一种对我来说毫无意义的境地。我会尽力描述它。
我有一个开发分支,我已经通过 git checkout develpment && git merge master
将 master 合并到其中。我在这里没有遇到任何合并冲突。
有一个我感兴趣的特定提交,假设它是 abcd123
。当我运行git branch --contains abcd123
时,它报告development
和master
都包含abcd123
。当我执行 git log
时,它会在 development
和 master
.
abcd123
git show abcd123
显示包含对两个文件的更改。但我似乎无法找到这些变化。当我查看文件时,在 development
和 master
上都没有看到这些更改。当我检查 git log -- path/to/file1
时,我没有看到 abcd123
,git log -- path/to/file2
也是如此。
这是怎么回事?怎么会有commit存在,而修改显然不存在?
可能 abcd123
最初是在合并到 master
的另一个分支(development
以外的分支)中引入的。我不知道这是否会有所作为。
顺便说一下,当我尝试 git checkout master && git merge development
(如上所示将 master
合并到 development
之后)时,我遇到了很多合并冲突,包括 file1 和 file2。因此,这似乎表明 master
实际上并未合并到 development
中——如果 git merge master
已经执行,git merge development
不应该成功吗?为了引起更多混淆,git branch --merged development
说 master
已合并到 development
。我想这与 git merge master
....
非常感谢此时的任何建议。
编辑:在这一点上,问题似乎是由于合并失败或以某种方式搞砸了。如果有人还在阅读,我认为 torek 的回答的方向似乎是最有成果的。
这个答案很长,因为这里发生了很多事情。不过,TL;DR 摘要可能是您想要 --full-history
.
这里有多个单独的问题需要解决:
- 短语 "show changes",或者您在
git log -p
或git show
中看到的内容,通常会导致人们在解释 Git 存储的内容时走上错误的道路。 git log
命令有时会对您撒谎(尤其是在合并时),纯粹是为了避免让您被无用的信息淹没。git merge
的作用可能有点棘手。原则上很简单,但大多数人不会马上明白。
普通提交
让我们先看看 Git 最常见的普通提交。 Git 中的提交是 快照 (file-contents 的文件名)。您进行一次提交,然后更改一些内容和 git add
一两个更改的文件并进行第二次提交,第二次提交与第一次提交 所有相同的文件提交,除了被 git add
.
值得将这些作为 Git 的 提交图 的一部分进行绘制。请注意,每个提交都有自己唯一的哈希 ID(impossible-to-remember 字符串之一,如 93aefc
或 badf00d
或 cafedad
),加上 的 ID parent(或之前的)提交。父提交哈希让 Git 以向后的方式将这些东西串在一起:
... <-E <-F <-G ...
其中每个大写字母代表一个哈希 ID,箭头表示每个提交 "points back" 到其父节点的想法。通常我们不需要绘制内部箭头(最后它们不是很有趣)所以我将它们绘制为:
...--E--F--G <-- master
然而,namemaster
仍然值得一个箭头,因为这个箭头指向的提交会随着时间而改变。
如果我们选择像 G
这样的提交并使用 git log -p
或 git show
查看它 而没有 ,我们将看到每个文件的完整内容,与存储在提交中的完全一样。事实上,这就是我们使用 git checkout
检查时发生的情况:我们将所有文件完整提取到 work-tree 中,以便我们可以查看和处理它们。但是当我们用 git log -p
或 git show
查看它时,Git 并没有向我们展示所有内容;它只向我们展示了发生了什么变化。
为此,Git 提取提交 和 其父提交,然后 运行 在对上添加一个大的 git diff
.父 F
和子 G
之间的任何不同,都是 改变的 ,所以这就是 git log -p
或 git show
向您展示的内容.
合并提交
这对于普通的 single-parent 提交来说很好,但它不适用于 merge 提交。合并提交只是具有两个(或更多,但我们不会担心这种情况)父提交的任何提交。你通过成功的 git merge
得到这些,我们可能会像这样画出来。我们从两个分支开始(从一些 starting-point 分支出来):
H--I <-- development (HEAD)
/
...--E--F--G <-- master
然后我们 运行 git merge master
.1 Git 现在尝试合并这两个分支。如果成功,它会进行一个新的提交,该提交有 两个 个父项:
H--I--J <-- development (HEAD)
/ /
...--E--F--G <-- master
名称 development
现在指向新的合并提交 J
。这里括号(HEAD)
表示这是我们的当前分支。这告诉我们哪个 name 被移动了:我们做了一个新的提交——包括任何新的合并提交——而 development
是更改为指向新的 branch-name提交。
如果我们不担心合并提交的内容(各种提交的文件)是如何确定的,这一切都非常简单。合并提交就像任何其他提交一样:它有一个完整的快照,一堆包含内容的文件。我们检查合并提交,这些内容像往常一样进入我们的 work-tree。
但是当我们去 查看 合并提交时......好吧,Git 通常会根据其父级区分提交。合并有 两个 个父项,每个分支一个。 Git 应该比较哪一个,以向您展示变化?
在这里,git log
和 git show
采用不同的方法。当您使用 git log
查看提交时,它默认显示 什么都没有 。不会选I
-vs-J
,也不会选G
-vs-J
!对于 git log -p
.
1在某些 Git 工作流中,不鼓励将 from master 合并到任何其他分支。不过它可以工作,既然你这样做了,让我们运行使用它。
查看合并提交
git show
命令做了一些不同且更好的事情。它运行s 两个 git diff
s,一个用于I
-vs-J
,一个用于G
-vs -J
。然后它会尝试 合并 这两个差异,只向您显示 both 中发生的变化。也就是说,J
不同于I
但不是特别 有趣 的方式,Git 抑制了差异。 J
不同于 G
但不是特别 有趣的 方式,Git 也抑制了这种差异。这可能是最有用的模式,所以它就是 git show
显示的内容。它仍然很不完美,但是您在这里所做的一切都不是完美的。
您可以通过将 --cc
添加到 git log -p
选项来让 git log
做同样的事情。或者,您可以使用 -m
(请注意 -m
的一个破折号,--cc
的两个破折号。
-m
选项告诉 Git 为了查看目的,它应该 拆分 合并。现在 Git 将 I
与 J
进行比较,以向您展示通过合并 G
带来的所有内容。然后 Git 将 G
与 J
的 split-off 额外版本进行比较,以向您展示通过合并 I
带来的所有内容。产生的差异通常非常大,但(或因为)它向您展示了 一切。
有更多方法可以尝试查找某个文件发生了什么,但我们需要稍等片刻才能找到您的:
git log -- path/to/file1
命令。正如我们看到 git log
skipping 合并一样,它可能会在这里跳过更多的东西(但有一些方法可以阻止 Git 这样做)。
实际进行合并:Git 如何构建合并的内容
让我们再看看那个 pre-merge 图:
H--I <-- development (HEAD)
/
...--E--F--G <-- master
此处,分支 development
上有两个不在分支 master
上的提交,还有两个 master
上不在 development
上的提交。提交 E
(连同 all 之前的提交)在 both 分支上。不过,提交 E
是特殊的:它是两个分支上的 最近的 2 提交。提交 E
是 Git 调用的 合并基础 。
要执行合并,Git 有效地 运行 两个 git diff
命令:
git diff E I
git diff E G
首先产生一组对各种文件的修改,即"what we did on branch development
"。实际上,如果将它们视为补丁,则它是 H
和 I
的总和。第二个产生了一组——可能不同的——对各种文件的更改,"what we did on master
",和以前一样,它实际上是 F
和 G
作为补丁的总和。
Git 然后尝试合并这两个差异。无论它们之间是完全独立的,它都需要 both 组更改,将它们应用于提交 E
的内容,并将其用作结果。每当两个 change-sets 触及 same 文件中的同一行时,Git 会尝试查看它是否可以只复制该更改的一个副本。如果两者都修复了文件 README
第 33 行的一个单词的拼写,Git 可以仅获取 一份 的拼写修复。但是只要两个 change-sets 触及同一个文件的同一行,但进行 不同的 更改, Git 声明一个 "merge conflict",抛出其隐喻举起手来,让你解决由此产生的混乱。
如果您(或进行合并的任何人)愿意,他们可以阻止 Git 提交合并结果,即使 Git 认为一切顺利:git merge --no-commit master
使 Git 合并所有内容后停止。此时,您可以在编辑器中打开 work-tree 个文件,更改 它们,写回,git add
更改的文件,以及 git commit
merge 将不是来自三个输入(基础和两个 branch-tips)中的 any 的东西放入合并中。
无论如何,理解所有这些的关键是 merge base 提交的概念。如果您坐下来绘制提交图,合并基础通常非常明显,除非图失控(实际上这种情况经常发生)。您还可以让 Git 为您找到合并基础——或者合并基础,复数,在某些情况下:
git merge-base --all master development
这会打印出一个散列 ID。在我们这里的假设情况下,这将是提交 E
的哈希 ID。一旦你有了它,你可以手动 运行 git diff
来查看每个文件发生了什么。或者你可以 运行 一个 individual-file git diff
:
git diff E development -- path/to/file1
git diff E master -- path/to/file1
请注意,如果您将名称 master
和 development
替换为 是 当前 之前的提交的哈希 ID =341=] 你做了 git merge
,这甚至在 合并后也有效。这将告诉您 Git 认为它应该为 path/to/file1
组合什么。反过来,这会告诉您 Git 是否没有看到更改,或者是否进行了合并 overrode Git,或者是否错误地处理了冲突的合并。
合并后,后续合并将找到不同的合并基础:
H--I--J----K <-- development
/ /
...--E--F--G--L--M <-- master
我们现在查看两个分支提示并通过历史(向左方向)向后工作,遵循像 J
这样的合并的两个分支,以找到我们可以从 both 分支提示中获得第一个提交。从 K
开始,我们回到 J
,然后回到 I
和 G
。从 M
开始,我们回到 L
,然后到 G
。我们发现 G
在两个分支上,所以提交 G
是新的合并基础。 Git 将 运行:
git diff G K
git diff G M
让两个 change-sets 应用于 merge-base 提交 G
。
2"Most recent"这里指的是commit graph顺序,而不是时间戳,虽然可能也是commit with两个分支上的最新时间戳。
Git 再次记录和简化谎言
我们已经看到 git log -p
直接跳过了合并提交。您根本看不到任何差异,就好像合并完全是魔术一样。但是当你 运行:
git log -- path/to/file1
还有其他更阴险的事情发生了。在 the (long) git log
documentation under the section titled History Simplification.
在我们上面的例子中,假设 git log
从 K
向后走。它找到 J
,这是一个合并。然后它检查 I
和 G
,将每个文件与 J
进行比较,在排除所有文件后,除了您正在查看的一个文件。 也就是说,它是只是比较三个提交中的 path/to/file1
。
如果合并的一侧 没有 显示对 path/to/file1
的任何更改,这意味着合并结果 J
与输入没有区别(I
或 G
)。 Git 称之为 "TREESAME"。如果合并 J
,在被剥离到这个文件之后,匹配 I
或 G
类似 stripped-down,那么 J
是 TREESAME 到 I
或 G
(或两者)。在这种情况下,Git 选择 TREESAME parent(s) 或其中任何一个,并在该路径上 only 查找。假设它选择 I
(沿着顶行)而不是 G
(沿着底部)。
在我们的例子中,这意味着如果有人在合并过程中失误,丢失了本应从 F
进入 J
的更改,git log
永远不会显示它。 log
命令查看K
,然后查看J
,然后查看但丢弃G
,只查看I
,然后查看H
,然后是 E
,然后是任何更早的提交。它从不查看提交 F
!所以我们没有看到从 F
.
path/to/file1
的变化
这里的逻辑很简单;我将直接引用 git log
文档,但添加一些重点:
[Default mode] Simplifies the history to the simplest history explaining the final state of the tree. Simplest because it prunes some side branches if the end result is the same ...
由于 F
中的更改已删除,Git 声明它们无关紧要。你不需要看到他们!我们将完全忽略合并的那一面!
你可以用--full-history
彻底打败它。这告诉 Git not p运行e 合并的任一侧:它应该查看两个历史记录。这将为您找到提交 F
。添加 -m -p
还应该找到 where 更改被删除,因为它会找到 all 涉及文件的提交:
git log -m -p --full-history -- path/to/file1
如果更改存在(在我们的示例中提交 F
)并且不再存在,则只有两种方式丢失它们:
它们在普通提交中被还原(使用
git revert
,或手动)。即使没有-m
,您也会将其视为在历史记录中触及path/to/file1
的提交;-p
会告诉你差异。或者,它们在合并过程中丢失了。即使没有
-m
,您也会看到合并,但不确定进行合并的人是否在此处丢球;但是-m -p
将显示两个父差异,包括 应该(但没有)进行更改的差异。