从master合并后如何找出分支上的变化?
How to find out what changes on a branch after merges from master?
我分叉了 master
一个分支。有时我将 master
合并到我的分支以进行更新。
/--B--D--G--H--J--L--M--> dev (HEAD)
/ / /
-----A--C--E--F--I--K---> master
如何只显示我的分支上的更改,不包括合并中的更改?
IE。仅在提交时显示差异 B
、D
、H
、L
、M
.
git diff A
不起作用,因为它包含来自 master
.
的合并更改
顺便说一句,如果有人知道无需继续向下滚动日志即可快速找到 A
的方法,我将不胜感激。
我不清楚你在找什么。但请注意:
提交存储快照。这意味着提交 K
有一个完整的源代码树,它独立于提交 A
、B
、C
等中的任何内容。同样,提交 J
有一个完整的快照,独立于 A
或 K
或任何其他提交中的任何内容。
(此处“独立”一词的意思是,如果您要求 Git 检索提交 J
,那么您是否以某种方式设法更改提交 K
之后就没有关系了J
。实际上 不可能 更改任何提交;git commit --amend
似乎 更改提交,但实际上没有。)
在两个特定的提交上使用 git diff
,Git 提取两个快照中的每一个,并进行比较。
简单的差异
因此,git diff K M
将向您展示 master
当前提示(提交 K
)和 dev
当前提示(提交 M
).
你也可以只拼这个git diff master dev
。
这可能是您想看到的(同样,我也不是很清楚)。所以 答案 1:git diff master dev
.
多个独立差异
另一方面,也许您想要的是为提交 B
显示一个差异,为提交 D
显示一个差异,为提交 H
显示一个差异,为 H
显示一个差异提交 L
,以及提交 M
的一个差异。也就是说,您希望一次看到每个 non-merge 提交,与其(单个)parent.
相比
您可以 git diff A B
和 git diff B D
,等等。但您也可以只使用 git show B
和 git show D
,等等。这将提交显示为更改,而不是快照。
您可能想知道如果提交存储快照而不是更改,这怎么可能。 (这让很多人感到困惑,因为大多数 other 版本控制系统实际上会进行存储更改。)这个 apparent 矛盾的答案是 git show
查找和你画的一样。
再次查看提交 B
。它之前有什么提交?也就是说,哪个提交在它的左边,向左跟随行?提交 B
只有一个可能的祖先,那就是它的单个 parent,提交 A
。所以 git show B
:
- 提取提交
A
的快照,然后
- 提取提交
B
的快照,然后
- 比较这两个快照。
同样,提交 M
只有一个直接祖先 (parent),那就是提交 L
。所以 git show M
:
- 提取
L
的快照,然后
- 提取
M
的快照,然后
- 比较这两个快照。
如果这是您想要的,那么有趣的问题就变成了:您如何在 B
、D
、H
中找到每个提交的 ID , L
, 和 M
序列 ?这个问题的答案有点复杂,但关键命令是git rev-list
,这与git log
本质上是相同的命令。这些命令(git log
和 git rev-list
两者)所做的是 遍历提交图 。也就是说,您选择一些起点——在本例中,提交 M
,dev
的尖端——并告诉 Git 向后遍历提交,查看每个提交的 parents.
问题是,当您点击合并提交时,例如提交 J
,Git 返回到其 [=346= 的 all ]s。您希望将 Git 限制为仅查找 parent,即您进行合并提交时分支 dev
的顶端。 Git 有一个标志,拼写为 --first-parent
。这告诉 git rev-list
仅遵循每个合并提交的 first parent。
我们也想跳过合并,所以我们可以添加--no-merges
(这不会影响walking-back过程,它只是限制打印的修订ID以排除合并)。
这导致 答案 2a:git rev-list --first-parent --no-merges ^A dev
(我们稍后会谈到“非 A”部分)。
现在,实际上将它与 git rev-list
一起使用有点痛苦,因为现在我们必须获取每个提交 ID,然后在其上添加 运行 git show
。不过,还有一种更简单的方法,因为 git rev-list
和 git log
本质上是相同的命令 ,而 git log -p
将每个提交显示为 补丁,和git show
.
做的事情差不多
这导致 答案 2b:git log -p --first-parent --no-merges ^A dev
。我们也不一定需要这里的 --no-merges
;见下文。
合并提交和合并差异
git show
做的一件特别的事情,git diff
没有,就是处理显示 merge 提交的情况,例如提交 J
。提交 J
有 两个 parent,即提交 H
和 K
(顺便说一下,这意味着您提交了 K
在提交 J
:-) 之前。如果您 运行 git diff H J
,Git 将提取 H
和 J
的快照和 comp重新他们。如果您 运行 git diff K J
,Git 将提取 K
和 J
的快照并进行比较。但是如果你 运行 git show J
,Git 将:
- 提取
H
的快照,然后
- 提取
K
的快照,然后
- 提取
J
的快照(合并),最后
- 产生Git所谓的组合差异。
第 4 步的组合差异试图以紧凑的方式显示从 H
和 K
到 J
的变化.在压缩更改时,Git 会丢弃 版本在 H
或 K
中的任何文件匹配 J
.
中的版本
也就是说,假设文件 README.txt
从 H
到 J
有一些变化。但假设 README.txt
与 K
和 J
中的 相同 。换句话说,当您执行 git merge
时,您正在从 K
中获取更改以进行 J
,并且没有从另一侧对 README.txt
进行更改的合并。这意味着 README.txt
完全匹配一个“传入方”,因此组合差异 完全忽略文件 .
这意味着合并的差异通常什么也没有显示,即使合并在新快照中发现了一些变化。要查看这些更改,您必须进行 两次 比较,而不仅仅是一次。你必须从 H
到 J
做一个差异,从 K
到 J
做另一个差异,而不是依赖组合的差异。
当使用 git log -p
时,您还可以通过在选项中添加 -c
或 --cc
来查看合并的组合差异。但是如果你不要求这个,Git所做的实际上简单得可笑:它根本不费心去显示差异.
所以这导致 答案 2c:git log -p --first-parent ^A dev
。我们所做的只是删除 --no-merges
:我们现在将看到每个合并的 日志消息 ,但没有差异。
这是什么^A
东西?
这也与您的另一个问题有关:
BTW, I will appreciate if anyone knows a quick way to find A without keep scrolling down the log.
答案是为提交 A
创建一个 符号名称 。找到它的 ID 一次,然后选择一个名称,例如 dev
或 master
(但不要使用它们,因为它们正在使用中!)。
这就是全部 dev
和 master
是 :它们只是提交的符号名称,加上额外的 属性,作为分支名称,您可以 git checkout
符号名称并在分支“上”结束。你也可以给 A
一个 branch-name。您将需要确保您没有 git checkout
这个分支并对其进行提交,因为如果您这样做,您将增长一个新分支,而不是仅仅让 branch-name 指向提交 A
.
或者,您可以创建一个 tag-name 指向提交 A
。这几乎与分支名称完全相同。这两个区别是:
- 这是一个标签名称:您不能将其作为分支签出,因此不能意外更改它。
- 这是一个标签名称:如果你
git push --tags
你会把它作为标签发送到上游,然后其他人也会有它。
在这种情况下,第 1 点对您有利,而第 2 点可能不利,因此由您决定优势(不能意外更改)是否值得冒险(可能会意外发布)。
如果您有A
的ID,那么,您可以:
$ git tag A <id-of-commit-A>
现在您有了 名称 A
。 (您可以稍后 git tag -d A
删除它,但如果您不小心发布了它,您可能会继续从上游取回它。)
回到 git log
命令中 ^A
字符串的问题,^A
所做的只是告诉 git rev-list
(因此 git log
)到 停止 在到达提交 A
时遍历提交图。提交也未显示(对于 git rev-list
,未打印;对于 git log
,未显示在日志输出中)。前缀 ^
符号是“not”的缩写,即“让我从 dev
到达所有提交,但 not 从 A
到达” .添加 --first-parent
使得 Git 仅遍历每个合并的 first parent,这样我们就不会进入从 master
合并的提交.
(^A dev
语法也可以拼写为 A..dev
。请注意,这适用于 git log
和 git rev-list
,但对于 git diff
.)
我分叉了 master
一个分支。有时我将 master
合并到我的分支以进行更新。
/--B--D--G--H--J--L--M--> dev (HEAD)
/ / /
-----A--C--E--F--I--K---> master
如何只显示我的分支上的更改,不包括合并中的更改?
IE。仅在提交时显示差异 B
、D
、H
、L
、M
.
git diff A
不起作用,因为它包含来自 master
.
顺便说一句,如果有人知道无需继续向下滚动日志即可快速找到 A
的方法,我将不胜感激。
我不清楚你在找什么。但请注意:
提交存储快照。这意味着提交
K
有一个完整的源代码树,它独立于提交A
、B
、C
等中的任何内容。同样,提交J
有一个完整的快照,独立于A
或K
或任何其他提交中的任何内容。(此处“独立”一词的意思是,如果您要求 Git 检索提交
J
,那么您是否以某种方式设法更改提交K
之后就没有关系了J
。实际上 不可能 更改任何提交;git commit --amend
似乎 更改提交,但实际上没有。)在两个特定的提交上使用
git diff
,Git 提取两个快照中的每一个,并进行比较。
简单的差异
因此,git diff K M
将向您展示 master
当前提示(提交 K
)和 dev
当前提示(提交 M
).
你也可以只拼这个git diff master dev
。
这可能是您想看到的(同样,我也不是很清楚)。所以 答案 1:git diff master dev
.
多个独立差异
另一方面,也许您想要的是为提交 B
显示一个差异,为提交 D
显示一个差异,为提交 H
显示一个差异,为 H
显示一个差异提交 L
,以及提交 M
的一个差异。也就是说,您希望一次看到每个 non-merge 提交,与其(单个)parent.
您可以 git diff A B
和 git diff B D
,等等。但您也可以只使用 git show B
和 git show D
,等等。这将提交显示为更改,而不是快照。
您可能想知道如果提交存储快照而不是更改,这怎么可能。 (这让很多人感到困惑,因为大多数 other 版本控制系统实际上会进行存储更改。)这个 apparent 矛盾的答案是 git show
查找和你画的一样。
再次查看提交 B
。它之前有什么提交?也就是说,哪个提交在它的左边,向左跟随行?提交 B
只有一个可能的祖先,那就是它的单个 parent,提交 A
。所以 git show B
:
- 提取提交
A
的快照,然后 - 提取提交
B
的快照,然后 - 比较这两个快照。
同样,提交 M
只有一个直接祖先 (parent),那就是提交 L
。所以 git show M
:
- 提取
L
的快照,然后 - 提取
M
的快照,然后 - 比较这两个快照。
如果这是您想要的,那么有趣的问题就变成了:您如何在 B
、D
、H
中找到每个提交的 ID , L
, 和 M
序列 ?这个问题的答案有点复杂,但关键命令是git rev-list
,这与git log
本质上是相同的命令。这些命令(git log
和 git rev-list
两者)所做的是 遍历提交图 。也就是说,您选择一些起点——在本例中,提交 M
,dev
的尖端——并告诉 Git 向后遍历提交,查看每个提交的 parents.
问题是,当您点击合并提交时,例如提交 J
,Git 返回到其 [=346= 的 all ]s。您希望将 Git 限制为仅查找 parent,即您进行合并提交时分支 dev
的顶端。 Git 有一个标志,拼写为 --first-parent
。这告诉 git rev-list
仅遵循每个合并提交的 first parent。
我们也想跳过合并,所以我们可以添加--no-merges
(这不会影响walking-back过程,它只是限制打印的修订ID以排除合并)。
这导致 答案 2a:git rev-list --first-parent --no-merges ^A dev
(我们稍后会谈到“非 A”部分)。
现在,实际上将它与 git rev-list
一起使用有点痛苦,因为现在我们必须获取每个提交 ID,然后在其上添加 运行 git show
。不过,还有一种更简单的方法,因为 git rev-list
和 git log
本质上是相同的命令 ,而 git log -p
将每个提交显示为 补丁,和git show
.
这导致 答案 2b:git log -p --first-parent --no-merges ^A dev
。我们也不一定需要这里的 --no-merges
;见下文。
合并提交和合并差异
git show
做的一件特别的事情,git diff
没有,就是处理显示 merge 提交的情况,例如提交 J
。提交 J
有 两个 parent,即提交 H
和 K
(顺便说一下,这意味着您提交了 K
在提交 J
:-) 之前。如果您 运行 git diff H J
,Git 将提取 H
和 J
的快照和 comp重新他们。如果您 运行 git diff K J
,Git 将提取 K
和 J
的快照并进行比较。但是如果你 运行 git show J
,Git 将:
- 提取
H
的快照,然后 - 提取
K
的快照,然后 - 提取
J
的快照(合并),最后 - 产生Git所谓的组合差异。
第 4 步的组合差异试图以紧凑的方式显示从 H
和 K
到 J
的变化.在压缩更改时,Git 会丢弃 版本在 H
或 K
中的任何文件匹配 J
.
也就是说,假设文件 README.txt
从 H
到 J
有一些变化。但假设 README.txt
与 K
和 J
中的 相同 。换句话说,当您执行 git merge
时,您正在从 K
中获取更改以进行 J
,并且没有从另一侧对 README.txt
进行更改的合并。这意味着 README.txt
完全匹配一个“传入方”,因此组合差异 完全忽略文件 .
这意味着合并的差异通常什么也没有显示,即使合并在新快照中发现了一些变化。要查看这些更改,您必须进行 两次 比较,而不仅仅是一次。你必须从 H
到 J
做一个差异,从 K
到 J
做另一个差异,而不是依赖组合的差异。
当使用 git log -p
时,您还可以通过在选项中添加 -c
或 --cc
来查看合并的组合差异。但是如果你不要求这个,Git所做的实际上简单得可笑:它根本不费心去显示差异.
所以这导致 答案 2c:git log -p --first-parent ^A dev
。我们所做的只是删除 --no-merges
:我们现在将看到每个合并的 日志消息 ,但没有差异。
这是什么^A
东西?
这也与您的另一个问题有关:
BTW, I will appreciate if anyone knows a quick way to find A without keep scrolling down the log.
答案是为提交 A
创建一个 符号名称 。找到它的 ID 一次,然后选择一个名称,例如 dev
或 master
(但不要使用它们,因为它们正在使用中!)。
这就是全部 dev
和 master
是 :它们只是提交的符号名称,加上额外的 属性,作为分支名称,您可以 git checkout
符号名称并在分支“上”结束。你也可以给 A
一个 branch-name。您将需要确保您没有 git checkout
这个分支并对其进行提交,因为如果您这样做,您将增长一个新分支,而不是仅仅让 branch-name 指向提交 A
.
或者,您可以创建一个 tag-name 指向提交 A
。这几乎与分支名称完全相同。这两个区别是:
- 这是一个标签名称:您不能将其作为分支签出,因此不能意外更改它。
- 这是一个标签名称:如果你
git push --tags
你会把它作为标签发送到上游,然后其他人也会有它。
在这种情况下,第 1 点对您有利,而第 2 点可能不利,因此由您决定优势(不能意外更改)是否值得冒险(可能会意外发布)。
如果您有A
的ID,那么,您可以:
$ git tag A <id-of-commit-A>
现在您有了 名称 A
。 (您可以稍后 git tag -d A
删除它,但如果您不小心发布了它,您可能会继续从上游取回它。)
回到 git log
命令中 ^A
字符串的问题,^A
所做的只是告诉 git rev-list
(因此 git log
)到 停止 在到达提交 A
时遍历提交图。提交也未显示(对于 git rev-list
,未打印;对于 git log
,未显示在日志输出中)。前缀 ^
符号是“not”的缩写,即“让我从 dev
到达所有提交,但 not 从 A
到达” .添加 --first-parent
使得 Git 仅遍历每个合并的 first parent,这样我们就不会进入从 master
合并的提交.
(^A dev
语法也可以拼写为 A..dev
。请注意,这适用于 git log
和 git rev-list
,但对于 git diff
.)