git cherry-pick 实际上与 git show + git apply 一样吗?
Is git cherry-pick actually the same as git show + git apply?
难道是
git cherry-pick <rev>
实际上与
完全一样
git show <rev> | git apply -3 -
???
因为 运行 中的任何一个都会给我带来完全相同的结果,如果我知道它们确实是等价的,我就能更好地理解 GIT 的挑选实际上是如何工作的,因为它并不总能给我预期的结果,但这可能是因为无法应用唯一的更改并且樱桃采摘退回到三向合并(这就是 -3
在第二个上所做的命令),这将解释意外的结果。
从技术上讲,git cherry-pick 的工作方式类似于 git 合并,而不是寻找 "best revision that is present on both branches" 来检查差异和 merge 他们,合并逻辑的 "common revision" 被迫成为您正在挑选的修订的父级。
除了 , which is right and I've upvoted it, there are a bunch of other niggling details, including 关于二进制文件(git show
需要 --binary
来生成二进制补丁)并且你可能还需要 --full-index
,在一些罕见的情况下缩写的 Index:
行是不够的。1
当然,git apply
(带或不带 -3
)不介意脏索引和工作树,而 git cherry-pick
需要干净的索引和工作树,除非您添加 -n
。而且,如果您 省略 -n
,git cherry-pick
继续进行提交,而 git apply
永远不会。
综上所述,是的,这两个在正常情况下在功能上应该是等价的。
1要实现这一点,blob 哈希在缩写时必须是非唯一的。这在 Git 版本 1.7.2 中已自动更正,但如果您使用 core.abbrev
或命令行标志强制使用特定的缩写长度,您仍然可以获得非唯一的哈希缩写。添加 --full-index
可确保您获得唯一的。
(如果你要长期保存一个差异,添加一堆 new 对象到存储库,然后尝试 git apply -3
差异,以前 明确的缩写 Index:
行现在可能变得不明确。)
注意:对于二进制文件,git apply
无论如何都不起作用,在 Git 2.34(2021 年第 4 季度)之前不会:“git apply
"(man) 错误地计算了字节和未能读到二进制 hunks 的末尾。
参见 commit 46d723c (09 Aug 2021) by Jeff King (peff
)。
(由 Junio C Hamano -- gitster
-- in commit 7e3b9d1 合并,2021 年 8 月 30 日)
apply
: keep buffer/size pair in sync when parsing binary hunks
Reported-by: Xingman Chen
Signed-off-by: Jeff King
We parse through binary hunks by looping through the buffer with code like:
llen = linelen(buffer, size);
...do something with the line...
buffer += llen;
size -= llen;
However, before we enter the loop, there is one call that increments "buffer" but forgets to decrement "size
".
As a result, our "size
" is off by the length of that line, and subsequent calls to linelen()
may look past the end of the buffer for a newline.
The fix is easy: we just need to decrement size as we do elsewhere.
This bug goes all the way back to 0660626 ("binary diff: further updates.", 2006-05-05, Git v1.4.1-rc1 -- merge).
Presumably nobody noticed because it only triggers if the patch is corrupted, and even then we are often "saved" by luck.
We use a strbuf
to store the incoming patch, so we overallocate there, plus we add a 16-byte run of NULs as slop for memory comparisons.
So if this happened accidentally, the common case is that we'd just read a few uninitialized bytes from the end of the strbuf before producing the expected "this patch is corrupted" error complaint.
However, it is possible to carefully construct a case which reads off the end of the buffer.
The included test does so.
It will pass both before and after this patch when run normally, but using a tool like ASan shows that we get an out-of-bounds read before this patch, but not after.
难道是
git cherry-pick <rev>
实际上与
完全一样git show <rev> | git apply -3 -
???
因为 运行 中的任何一个都会给我带来完全相同的结果,如果我知道它们确实是等价的,我就能更好地理解 GIT 的挑选实际上是如何工作的,因为它并不总能给我预期的结果,但这可能是因为无法应用唯一的更改并且樱桃采摘退回到三向合并(这就是 -3
在第二个上所做的命令),这将解释意外的结果。
从技术上讲,git cherry-pick 的工作方式类似于 git 合并,而不是寻找 "best revision that is present on both branches" 来检查差异和 merge 他们,合并逻辑的 "common revision" 被迫成为您正在挑选的修订的父级。
除了 git show
需要 --binary
来生成二进制补丁)并且你可能还需要 --full-index
,在一些罕见的情况下缩写的 Index:
行是不够的。1
当然,git apply
(带或不带 -3
)不介意脏索引和工作树,而 git cherry-pick
需要干净的索引和工作树,除非您添加 -n
。而且,如果您 省略 -n
,git cherry-pick
继续进行提交,而 git apply
永远不会。
综上所述,是的,这两个在正常情况下在功能上应该是等价的。
1要实现这一点,blob 哈希在缩写时必须是非唯一的。这在 Git 版本 1.7.2 中已自动更正,但如果您使用 core.abbrev
或命令行标志强制使用特定的缩写长度,您仍然可以获得非唯一的哈希缩写。添加 --full-index
可确保您获得唯一的。
(如果你要长期保存一个差异,添加一堆 new 对象到存储库,然后尝试 git apply -3
差异,以前 明确的缩写 Index:
行现在可能变得不明确。)
注意:对于二进制文件,git apply
无论如何都不起作用,在 Git 2.34(2021 年第 4 季度)之前不会:“git apply
"(man) 错误地计算了字节和未能读到二进制 hunks 的末尾。
参见 commit 46d723c (09 Aug 2021) by Jeff King (peff
)。
(由 Junio C Hamano -- gitster
-- in commit 7e3b9d1 合并,2021 年 8 月 30 日)
apply
: keep buffer/size pair in sync when parsing binary hunksReported-by: Xingman Chen
Signed-off-by: Jeff King
We parse through binary hunks by looping through the buffer with code like:
llen = linelen(buffer, size); ...do something with the line... buffer += llen; size -= llen;
However, before we enter the loop, there is one call that increments "buffer" but forgets to decrement "
size
".
As a result, our "size
" is off by the length of that line, and subsequent calls tolinelen()
may look past the end of the buffer for a newline.The fix is easy: we just need to decrement size as we do elsewhere.
This bug goes all the way back to 0660626 ("binary diff: further updates.", 2006-05-05, Git v1.4.1-rc1 -- merge).
Presumably nobody noticed because it only triggers if the patch is corrupted, and even then we are often "saved" by luck.
We use astrbuf
to store the incoming patch, so we overallocate there, plus we add a 16-byte run of NULs as slop for memory comparisons.
So if this happened accidentally, the common case is that we'd just read a few uninitialized bytes from the end of the strbuf before producing the expected "this patch is corrupted" error complaint.However, it is possible to carefully construct a case which reads off the end of the buffer.
The included test does so.
It will pass both before and after this patch when run normally, but using a tool like ASan shows that we get an out-of-bounds read before this patch, but not after.