为什么git-bisect必须从工作树的顶层目录运行?

73

如果在代码库的根目录之外的任何位置尝试运行git-bisect命令,会收到以下提示:

您需要从工作树的顶层运行此命令。

为什么会这样呢?我不知道其他任何一个git命令有这种要求,也没有明显的原因表明bisect应该特殊对待。手册中也没有提及这个限制。

这其实并不是什么大问题。我只是好奇。


我认为这是为了明确表示在二分期间整个工作副本将被修改。 - CharlesB
2
为了避免在目录被删除时出现的边缘情况。再说一遍,git不跟踪目录... - Arafangion
1
@CharlesB,Arafangion,这些观点对git-checkout和git-bisect都同样适用,不是吗? - Parker Coates
@Arafangion,任何命令都会改变wc - pull、merge、rebase、checkout等。 bisect没有什么特别之处。我认为这只是又一个误解。 - kan
3个回答

69

在查看项目的一些提交时,我发现有一条由Marcel M. Cary(marcel@oak.homeunix.org)提交的记录。

他在提交中提到(它碰巧是关于git-pull的,但我认为它是相关的)

"git pull" 失败了,因为 POSIX shell 有一个与 getcwd() 不同的当前工作目录概念。shell 在 PWD 中存储此路径。因此,“cd ../”在 shell 脚本中可能被解释为不同于在C程序中的 chdir("../")。shell会通过基本上从 PWD 中删除最后一个文本路径组件来解释 "../",而 C 的 chdir() 则按照文件系统上当前目录中的 ".." 链接进行跟随。当 PWD 是符号链接时,这些是不同的目标。结果,Git 的 C 命令找到了正确的顶级工作树,而 shell 脚本则没有。

https://github.com/git/git/commit/08fc0608657ee91bc85276667804c36a93138c7d

所以我想说的是,部分原因是因为 git-bisect 是一个 shell 脚本,不能自行找到顶级目录(当涉及到符号链接时)。


7
我本希望有个更好的理由,但这并不怪你。非常感谢你做了一些研究。 - Parker Coates
1
有点令人失望。继续深入代码吧;它非常(有时还很幽默)地注释良好,提交信息也很出色。 - willoller

12

二分过程需要检查您项目的不同版本。如果特定版本不包含当前文件夹,则当前文件夹将被删除。

在这种情况下,你的Shell可能会停留在一个已经不存在于文件系统中的文件夹! Git将无法找到根目录的.git文件夹,所以必须进行干预才能继续二分过程。

一个示例:

$ git rev-parse --show-toplevel
/path/to/project
$ mkdir tmp
$ cd tmp
$ rmdir ../tmp
$ git rev-parse --show-toplevel
fatal: Unable to read current working directory: No such file or directory

当执行git checkout时,当然也可能出现同样的问题,但可以很容易地在事后进行修复,例如使用cd ..(willoller解释了为什么这在shell中有效但在git中无效)。

但是由于二分查找是一个过程,因此在开始之前避免这种情况是有意义的,特别是如果我们想使用自动化工具例如git bisect run


8
因此,Git的C命令可以找到正确的顶层工作树,而Shell脚本则不行。
好的,随着Git 2.21(2019年2月)的发布,git bisect正在从Shell脚本向C语言过渡。

请查看 提交 06f5608, 提交 450ebb7, 提交 129a6cf, 提交 4fbdbd5, 提交 e3b1e3b, 提交 0f30233, 提交 5e82c3d (2019年1月2日) 由 Pranit Bauva (pranitbauva1997) 提交。
协助者: Ramsay Jones (jeffhostetler), 和 Stephan Beyer (sbeyer)
(由Junio C Hamano -- gitster --提交 09a9c1f中合并,2019年2月7日)

bisect-helper: bisect_start shell函数部分使用C重新实现

bisect_start shell函数部分使用C重新实现,并向git bisect--helper添加bisect-start子命令,以便从git-bisect.sh中调用它。

这还没有完成,但此迁移的一个副作用将是能够从子文件夹执行git bisect


Git 2.23进一步改进了C语言转换。
请参见提交7877ac3(2019年5月21日),作者为Johannes Schindelin (dscho)
(由Junio C Hamano -- gitster --提交5b476dc中合并,2019年6月17日)


从 Git 2.25 (2020年第一季度) 开始,bisect_reset 得到了修复的好处。

请参见 提交 51a0a4e (由 Tanushree Tumane (tanushree27) 于 2019年12月09日提交)
(由 Junio C Hamano -- gitster -- 合并于 提交 4bfc9cc,2019年12月25日)

bisect--helper: 避免使用后释放

导师:Johannes Schindelin
导师:Christian Couder
签名:Tanushree Tumane
签名:Miriam Rubio

5e82c3dd22a("C语言中的bisect_reset shell函数",2019-01-02,Git v2.21.0-rc0 -- 合并)中,git bisect reset子命令被移植到了C中。
当调用git checkout失败时,向用户报告了一个错误消息(could not check out original HEAD)。

但是,该错误消息已经使用了刚发布的strbuf,因此需要对它进行修改:先使用它,然后再释放它。


在 Git 2.26 (2020年第一季度) 中,"git bisect--helper" 的基础机制正在重构为更易于重用的部分。

请查看由Pranit Bauva (pranitbauva1997)于2020年2月17日提交的提交6c69f22, 提交9ec598e, 提交45b6370, 提交cdd4dc2, 提交e8e3ce6, 提交ce58b5d, 提交7613ec5
请查看由Miriam Rubio (``)于2020年2月17日提交的提交680e8a0, 提交b8e3b2f, 提交16538bf
请查看由Tanushree Tumane (tanushree27)于2020年2月17日提交的提交bfacfce, 提交292731c
(合并自Junio C Hamano -- gitster --提交25063e2,2020年3月5日)

例如:

bisect--helper: 引入新的decide_next()函数

Mentored-by: Christian Couder
Signed-off-by: Tanushree Tumane
Signed-off-by: Miriam Rubio

让我们将bisect_next_check()代码重构为一个新的decide_next()辅助函数。

这将移除一些goto语句,并使代码更简单、更清晰、更容易理解。


在 Git 2.28(2020 年第三季度)之前,解析 "git bisect start " 命令行的代码在验证参数方面比较宽松。

请参见 commit 4d9005f(2020 年 5 月 20 日),作者为 Carlo Marcelo Arenas Belón (carenas)
(由 Junio C Hamano -- gitster -- 合并至 commit 63e50b8,于 2020 年 6 月 9 日)

bisect--helper:避免在 start --term-* 中出现语法错误导致段错误

签名作者:Carlo Marcelo Arenas Belón
经过确认:Christian Couder

06f5608c14 ("bisect--helper: bisect_start shell function partially in C", 2019-01-02, Git v2.21.0-rc0 -- merge) 添加了一个松散的解析器,用于[git bisect start](https://git-scm.com/docs/git-bisect),如果使用自定义术语调用start时会导致段错误。

检测命令行中是否有足够的参数可用于--term-{old,good,new,bad},如果没有,则终止并显示与原始实现相同的语法错误。


在 Git 2.29(2020年第四季度)之前,“git bisect start X Y(man)”中,当X和Y不是有效的提交对象名称时,应该将X和Y作为路径规范处理,但实际未能这样做。

请查看由Christian Couder (chriscool)于2020年9月25日提交的提交73c6de0
(在2020年10月4日被Junio C Hamano -- gitster --合并到提交03a0182中)

bisect: 开始时不要使用无效的 oid 作为 rev

签名作者: Christian Couder
签名作者: Johannes Schindelin

In 06f5608c14 ("bisect--helper: bisect_start shell function partially in C", 2019-01-02, Git v2.21.0-rc0 -- merge), we changed the following shell code:

-      rev=$(git rev-parse -q --verify "$arg^{commit}") || {
-              test $has_double_dash -eq 1 &&
-              die "$(eval_gettext "'\$arg' does not appear to be a valid revision")"
-              break
-      }
-      revs="$revs $rev"

into:

+      char *commit_id = xstrfmt("%s^{commit}", arg);
+      if (get_oid(commit_id, &oid) && has_double_dash)
+              die(_("'%s' does not appear to be a valid "
+                    "revision"), arg);
+
+      string_list_append(&revs, oid_to_hex(&oid));
+      free(commit_id);

In case of an invalid "arg" when "has_double_dash" is false, the old code would "break" out of the argument loop.

In the new C code though, oid_to_hex(&oid) is unconditonally appended to "revs". This is wrong first because "oid" is junk as get_oid(commit_id, &oid) failed, and second because it doesn't break out of the argument loop.

Not breaking out of the argument loop means that "arg" is then not treated as a path restriction (which is wrong).


在Git 2.29(2020年第四季度)中,用C重写“git bisect(man)脚本的工作正在继续。

查看 提交 517ecb3提交 09535f0(2020年9月24日)由Pranit Bauva (pranitbauva1997)
查看 提交 c7a7f48(2020年9月24日),以及提交 7b4de74, 提交 3027676, 提交 ef5aef5 (2020年8月28日)由Miriam Rubio (mirucam)
(由Junio C Hamano -- gitster --合并于提交 f4cc68c,2020年10月4日)

bisect--helper:在C语言中重新实现bisect_nextbisect_auto_next shell函数

指导者:Lars Schneider
指导者:Christian Couder
指导者:Johannes Schindelin
签署者:Pranit Bauva
签署者:Tanushree Tumane
签署者:Miriam Rubio

在C中重新实现bisect_next()bisect_auto_next() shell函数,并将子命令添加到[git](https://github.com/git/git/blob/517ecb3161daa4503f7638489fd44177b3659913/Documentation/git-.txt)<sup>([man](https://git-scm.com/docs/git-))</sup> bisect--helper中,以便从git-bisect.sh中调用它们。 bisect_auto_next()函数返回一个枚举类型的bisect_error作为整体结果,因为[git bisect](https://github.com/git/git/blob/517ecb3161daa4503f7638489fd44177b3659913/Documentation/git-bisect.txt)<sup>([man](https://git-scm.com/docs/git-bisect))</sup>bisect_next()失败时可以退出并返回错误代码。 当bisect_next()失败时返回一个错误,这样可以修复shell脚本版本的一个bug。 使用--bisect-next--bisect-auto-next子命令是将shell函数移植到C的临时措施,以便使用现有的测试套件。随着更多的函数被移植,--bisect-auto-next子命令将被淘汰,并将由其他方法调用。
使用Git 2.30(2021年第一季度),在C中重写了 "git bisect"(man)

请参阅 提交 b0f6494, 提交 5c517fe, 提交 9b437b0, 提交 27257bc, 提交 04774b4, 提交 e439607, 提交 88ad372 (2020年10月15日) ,作者为 Pranit Bauva (pranitbauva1997)
(由Junio C Hamano -- gitster --合并于提交 cfdc70b,2020年11月9日)

bisect--helper:在C中重新实现bisect_statebisect_head shell函数

导师:Lars Schneider
导师:Christian Couder
导师:Johannes Schindelin
签名:Pranit Bauva
签名:Tanushree Tumane
签名:Miriam Rubio
审核:Johannes Schindelin

在C中重新实现bisect_state() shell函数,并在git-bisect--helper中添加一个子命令--bisect-state,以从git-bisect.sh调用它们。


随着Git 2.31 (2021年第一季度)的到来:对C语言中"git bisect"(man)的重写进行了逐步处理。

请查看由Pranit Bauva (pranitbauva1997)于2021年2月3日提交的提交97b8294, 提交e4c7b33, 提交9feea34, 提交b7a6f16, 提交68efed8, 提交2b1fd94, 提交97d5ba6
(由Junio C Hamano -- gitster --合并于2021年2月17日的提交0871fb9)

bisect--helper: 废除 --bisect-write 子命令

指导者: Lars Schneider
指导者: Christian Couder
指导者: Johannes Schindelin
签署者: Pranit Bauva
签署者: Tanushree Tumane
签署者: Miriam Rubio

--bisect-write 子命令不再从 git-bisect.sh shell 脚本中使用。
而是直接从 C 实现中调用函数 bisect_write()


"git bisect"(man) 在 2.30 时间框架内的重新实现更多地使用了 C 语言,但不能很好地接受带有注释的标签作为好/坏的终点。
这个回归错误已在 Git 2.31.1 (Q1 2021) 中得到修正。

请看 提交 7730f85 (2021年3月16日) ,作者是Jeff King (peff)
(由Junio C Hamano -- gitster --提交 35381b1中合并,2021年3月19日)

bisect: 将带注释的标签转换为提交

署名:Jeff King

This patch fixes a bug where 'git-bisect'(man) doesnt handle receiving annotated tags as "git bisect" good <tag>, etc.
It's a regression in 27257bc ("bisect--helper: reimplement bisect_state & bisect_head shell functions in C", 2020-10-15, Git v2.30.0-rc0 -- merge listed in batch #4).

The original shell code called:

sha=$(git rev-parse --verify "$rev^{commit}") ||
        die "$(eval_gettext "Bad rev input: \$rev")"

which will peel the input to a commit (or complain if that's not possible).
But the C code just calls get_oid(), which will yield the oid of the tag.

The fix is to peel to a commit.
The error message here is a little non-idiomatic for Git (since it starts with a capital).

新错误信息:
Bad rev input (not a commit): xxxx

警告:在使用自定义单词来代替new/old时, "git bisect skip"(man) 在Git 2.31中无法正常工作,但已在Git 2.32(2021年第二季度)中得到修复。

请参见 提交记录4cd66e7 (2021年4月29日),作者为Ramsay Jones(ramsay-jones
该提交已被Junio C Hamano(gitster合并至提交记录8ca4771,时间为2021年5月11日。

bisect--helper:在“bisect skip”命令中使用BISECT_TERMS

报告者:Trygve Aaberge
签署者:Bagas Sanjaya
签署者:Ramsay Jones

作为 shell-to-C 转换的一部分,提交 e4c7b33 ("bisect--helper: 在 C 中重新实现 bisect_skip shell 函数",2021-02-03,Git v2.31.0-rc0 -- 合并 列在 批次 #9 中) 时,忘记读取新的 'bisect skip' 命令实现期间的 'terms' 文件(.git/BISECT_TERMS)。因此,'bisect skip' 命令将使用默认的“bad”/“good”术语。如果二分术语已设置为非默认值(例如通过 'bisect start' 命令),则'bisect skip' 命令将失败。为了解决这个问题,在 'bisect--helper' 的 '--bisect-skip' 命令实现中插入对 get_terms() 函数的调用,该函数从该文件中读取非默认术语(如果设置)。另外,添加一个测试以防止潜在的未来回归。

在 Git 2.33(2021 年第三季度), "git bisect"(man) 仅为了在检出下一个要测试的版本后漂亮地打印提交标题,而生成了 git show-branch(man);现已使用 C 重写。

请查看 提交记录 1fcc40c (2021年7月28日) 和 提交记录 ffcb4e9 (2021年7月27日),作者为 Junio C Hamano (gitster)
(已合并至 提交记录 ae2d05d,由 Junio C Hamano -- gitster -- 完成,日期为2021年8月24日)

bisect: 不必运行show-branch命令来显示当前提交记录

在脚本化的 "git bisect"(man) 版本中,我们使用 "git show-branch"(man) 来描述 bisect 日志中的单个提交,并在检出下一个要测试的版本后向交互用户提供信息。当重写编写 bisect 日志条目的帮助函数时,以前使用 "git show-branch" 的用法已经丢失,该帮助函数在 0f30233 ("bisect--helper: bisect_write shell function in C", 2019-01-02, Git v2.21.0-rc0 -- merge) 中被改写为 C 语言。
但是自从 0871984 (bisect:make "git bisect" use new --next-all bisect-helper function, 2009-05-09, Git v1.6.4-rc0 -- merge) 开始使用了忠实的 C 重写之后,我们一直保留了后者(即向交互用户提供信息)。该重写是在 ef24c7c (bisect--helper: add "--next-exit" to output bisect results, 2009-04-19, Git v1.6.4-rc0 -- merge) 中添加的 (bisect--helper: add "--next-exit" to output bisect results, 2009-04-19)。
使用我们的 helper pretty.c::format_commit_message() 显示 "[<full hex>] <subject>" 很简单,而生成 show-branch 则是一种过度操作。让我们减少一个外部进程。

1
你不断更新这个答案以适应新版本的 Git 的专注精神令人印象深刻! - Parker Coates
1
@ParkerCoates 谢谢。这个用C语言重写的工作跨越了很多Git版本。 (我没有参与其中,我只是在这里报告它发生的情况) - VonC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接