【问题标题】:Rebasing a git history with empty commit messages使用空提交消息重新设置 git 历史记录
【发布时间】:2011-12-17 03:14:44
【问题描述】:

我最近用git svn 转换了一个svn 存储库。不幸的是,svn 历史有许多空提交消息。当我在没有提交消息的情况下在最近的提交之前对提交进行 rebase 和编辑/改写时,这是一个问题。

$ git rebase -i d01
[detached HEAD ff9839c] asdf
 2 files changed, 9 insertions(+), 0 deletions(-)
Aborting commit due to empty commit message.
Could not apply 054e890... 

$ git branch
* (no branch)
  master

$ git commit --amend
fatal: You are in the middle of a cherry-pick -- cannot amend.

在此示例中,我为第二个最近的提交创建了一条提交消息,其中包含一个空的提交消息,并且在最近的一个带有空提交消息的提交上停止了变基。

我想一次编辑所有带有空消息的提交。有没有办法我可以做到这一点?也许我可以使用空提交消息更改所有提交以使提交消息首先“空”?

【问题讨论】:

  • 使用 Git 2.17(2018 年第一季度,6 年后)您将不再遇到此问题。见my answer below

标签: git


【解决方案1】:

要用一些模板替换空的提交消息,你可以这样做:

git filter-branch -f --msg-filter '
read msg
if [ -n "$msg" ] ; then
    echo "$msg"
else
    echo "The commit message was empty"
fi'

【讨论】:

  • 完全按照指定的方式工作,并且使变基变得更加容易!谢谢!
  • 如果您的提交消息包含换行符,这将完全消除它们。很难找到这一点。
【解决方案2】:

正如我之前评论的那样,如果您碰巧在其中有换行符,这将完全破坏 cmets。这是一个 perl 脚本,它可以做到这一点而不会造成破坏:

#!/usr/bin/perl

my $data = "";    
while(<STDIN>) {
    $data .= $_;
}

if($data =~ /^\s*$/) { $data="[Empty message]\n"; }
print "$data";

那么,就git filter-branch -f --msg-filter /path/to/perlfilter.pl

【讨论】:

  • 这行得通,但我想知道为什么当我在 git 扩展中查看我的 repo 图表历史时,我看到我的旧提交带有旧的空消息,而另一个分支具有相同的提交,但是新消息?
  • @didibus,由于 git filter-branch 重写历史并因此更改了 SHA-1 哈希,所有重写的提交都显示为新提交。删除指向旧版本的 refs(我有 refs/remotes/master 和 refs/origin/master 闲逛)从 git log 输出中删除了重复的分支,但我相信提交仍在数据库中。我还没有真正研究过如何删除它们,但你应该使用 git gc --prune 或类似的东西在 SO 上找到一些东西。
【解决方案3】:

如果你有多行,你也可以使用 cat:

git filter-branch -f --msg-filter \
 'msg=$(cat); if [ "$msg" = "" ]; then echo "Here was an empty commit message"; else echo "$msg"; fi'

这处理多行的提交消息以及包含空行的消息。

【讨论】:

    【解决方案4】:

    由于提交消息为空而中止提交。

    Git 2.17(2018 年第一季度)不会出现此问题,因为“git rebase”学会了采用新选项:“--allow-empty-message”。 (这是 Git 2.19 中的默认设置,见下文)

    参见Genki Sky (``)commit a6c612b(2018 年 2 月 4 日)。
    (由 Junio C Hamano -- gitster -- 合并于 commit 2f6128d,2018 年 2 月 21 日)

    rebase:添加--allow-empty-message选项

    此选项允许重新设置带有空提交消息的提交, 匹配 git-commitgit-cherry-pick 中的相同选项。
    虽然空日志消息不受欢迎,但有时人们会发现它们在较旧的 存储库(例如从另一个 VCS 翻译),或有其他 渴望它们的原因。
    该选项在 git-commitgit-cherry-pick 中可用,因此很自然地可以让其他 git 工具与它们很好地配合。
    将此添加为选项允许默认设置为“让用户有机会修复”,否则不会中断用户的工作流程。

    注意:“空消息中止”部分在 Git 2.33 中被删除(见下文末尾)


    Elan Ruusamäe 确认in the comments

    像魅力一样工作。使用提到的提交构建。 +

    git rebase --root HEAD --allow-empty-message 
     Successfully rebased and updated detached HEAD. 
    
    git checkout -B master 
    

    对于 Git 2.19(2018 年第三季度),--allow-empty-message 是默认选项:

    commit b00bf1ccommit 1634688commit 0661e49commit 4d34dffcommit 983f464commit c840e1acommit 9929430(2018 年 6 月 27 日)和 commit d4e8062commit 5dacd4a(6 月 25 日) by Elijah Newren (newren).
    (由 Junio C Hamano -- gitster -- 合并于 commit 0ce5a69,2018 年 7 月 24 日)

    git-rebase:将--allow-empty-message设为默认

    rebase 后端当前的行为与空提交消息不同, 主要是作为不同基础命令的副作用 它们是基于的。
    基于am 的变基应用带有空提交消息的提交,而无需停止或要求用户指定额外的标志。
    (有趣的是,基于am 的变基是默认变基 类型,并且没有人请求过 --no-allow-empty-message 标志 改变这种行为。)
    基于合并和基于交互的变基(最终基于git commit)目前将在任何此类提交时停止,并要求用户手动指定如何处理提交并继续。

    行为差异的一个可能原因是目的 基于“am”的变基仅用于移植现有历史,而 “交互式”rebase 是一个旨在完善之前的系列的rebase 使其可发布。
    因此,在后一种情况下,停止并要求确认可能的问题更合适。

    但是,这个理由有两个问题:

      1. 基于合并的变基也是非交互的,并且有多种类型的变基使用交互机制但不是显式交互的(例如,当指定 --rebase-merges--keep-empty没有 --interactive)。
        这些变基也仅用于移植现有历史记录,因此也应默认为--allow-empty-message
      1. 这个理由只是说用户更愿意在显式交互式变基的情况下停止,而不是因为这个特定原因而停止实际上是有意义的。
        探索它是否有意义,需要备份和分析底层命令...

    如果git-commit 默认没有在空提交上出错,则为意外 使用空消息创建提交将是很常见的情况 (这张支票已经抓到我很多次了)。
    此外,几乎所有此类空提交消息都将被视为意外错误(正如跨版本控制系统的大量文档以及解释提交消息重要性的各种博客文章所证明的那样)。
    因此,对可能是常见错误的简单检查非常有意义,git-commit 获得了 --allow-empty-message 标志以用于特殊情况覆盖。
    这使得带有空消息的提交非常罕见。

    rebase(和cherry-pick)的空消息提交有两个来源:

    • (a) 在用户之前在 git 中创建的提交 将 --allow-empty-message 指定给 git-commit,并且
    • (b) 从其他版本控制系统导入 git 的提交。

    在情况 (a) 中,用户已经明确指定此提交有一些特殊之处,使他们不想指定提交消息;强迫他们在每次挑选或变基时重新指定似乎更有可能令人愤怒而不是帮助。

    在情况 (b) 中,提交极不可能是由导入历史并正在执行 rebase 或樱桃挑选的人创作的,因此用户不太可能是编写 a提交消息。
    因此,停止并期望用户在继续之前修改提交似乎适得其反。

    此外,请注意,虽然空提交消息是常见的错误情况 git-commit 来处理,这是一种罕见的变基(或樱桃挑选)的情况。
    它很少见的事实引发了为什么它值得的问题 检查并停止此特定条件而不是其他条件。

    例如,为什么交互式变基不会自动停止,如果 提交消息的第一行是 2000 列长,或者缺少一个空白 第一行之后的行,或每行缩进五个空格,或 还有其他无数的问题吗?

    最后,请注意,如果执行交互式变基的用户确实具有 为任何此类提交添加消息并想要做的必要知识 所以,他们很容易从 “挑选”到“改写”。
    用户编辑的待办事项列表中的主题为空这一事实甚至应该作为通知他们的一种方式。

    据我所知,基于合并和基于交互的事实 rebases stop on commits with empty commit messages 只是一个副产品 基于git-commit
    正是因为这种情况很少见,所以它在很长一段时间内没有得到通知。这种情况很少见,很难推理,所以当人们最终注意到这种行为时,他们认为这是有充分理由的,只是添加了一个 --allow-empty-message 标志。
    在我看来,在任何这些情况下,即使是(显式)交互式情况下,停止处理此类消息也是不可取的。


    注意:Git 2.19 中的“git rebase”等在给出空值时无法中止 提交日志消息作为编辑的结果,已在 Git 2.20(2018 年第四季度)中更正。

    sequencer:修复 --allow-empty-message 行为,让它更智能

    commit b00bf1c ("git-rebase: 使--allow-empty-message default", 2018-06-27, Git v2.19.0-rc0),给出了几个参数来移植空提交而不停止并要求用户确认每个提交。

    这些论点是不完整的,因为逻辑清楚地假设正在考虑的唯一情况是移植带有空消息的提交(请参阅有关“有两个源用于带有空消息的提交)的评论。

    它没有讨论甚至考虑改写、挤压等,其中明确要求用户提供新的提交消息并提供一个空的。
    (我的错,我当时完全应该考虑到这一点,但只是没有。)

    不过,如前所述,rewords 和 squashes 明显不同 通过 SZEDER:

    假设您启动了一个交互式变基,选择一个提交到 squash,保存说明书,rebase 启动你的编辑器,然后 然后你注意到你错误地选择了错误的提交 壁球。你是做什么的,你是怎么流产的?

    在 [那个提交] 之前,您可以清除提交消息,退出编辑器,然后 rebase 会说“由于提交消息为空而中止提交。”,然后您可以运行“git rebase --abort”,然后重新开始。

    但是 [自从那次提交,...] 保存提交消息会让 rebase 继续并创建一堆不必要的对象,然后您将不得不使用 reflog 返回到 pre-rebase 状态。

    另外,他说:

    提交消息模板中的说明,也显示为“reword”和“squash”,仍然说...

    # Please enter the commit message for your changes. Lines starting
    # with '#' will be ignored, and an empty message aborts the commit.
    

    这些是合理的论点,在定序器操作期间编辑提交消息时,如果提交消息为空,则操作应停止并要求用户更正。
    提交 b00bf1c(上面引用)中的参数在移植先前创建的带有空提交消息的提交时仍然适用,因此排序器不应该因为这些而停止。

    此外,到目前为止,所有理由都同样适用于cherry-pick和rebase。

    因此,编写代码:

    • 在移植现有提交时默认为 --allow-empty-message,以及
    • 默认为 halting 当用户被要求编辑提交消息并提供一个空的 - 用于 rebase 和cherry-pick。

    注意,在处理空提交时,请确保使用 Git 2.25+(2020 年第二季度)。
    请参阅“How to fill in an empty commit message?”(最后一节)。


    使用 Git 2.26(2020 年第一季度),文档已更新

    commit 10cdb9fcommit 2ac0d62commit 8295ed6commit 76340c8commit 980b482commit c2417d3commit 6d04ce7commit 52eb738commit 52eb738commit 8af14f0、@9876545350、@9876545350、@989 @、commit 93122c9commit 55d2b6dcommit 8a997edcommit 7db00f0commit e98c426commit d48e5e2(2020 年 2 月 15 日)和commit a9ae8fdcommit 22a69fd(2020 年 1 月 16 日)@987654。 br>(由 Junio C Hamano -- gitster -- 合并于 commit 8c22bd9,2020 年 3 月 2 日)

    git-rebase.txt: 更新 --allow-empty-message 的描述

    签字人:Elijah Newren

    提交b00bf1c9a8dd ("git-rebase: 使 --allow-empty-message 成为默认值", 2018-06-27, Git v2.19.0-rc0 -- merge 列在batch #4) 中 - -allow-empty-message 默认值,因此将 --allow-empty-message 变为无操作,但没有更新文档以反映这一点。

    现在更新文档,并在正常的 -h 输出中隐藏该选项,因为它没有用。

    git rebase man page 现在包括:

    --allow-empty-message:

    无操作。
    使用空消息重新定位提交会失败,此选项将覆盖该行为,允许重新定位带有空消息的提交。
    现在,带有空消息的提交不会导致 rebase 停止。


    在 Git 2.26(2020 年第一季度)中,“git rebase”已经学会默认使用合并后端(即驱动“rebase -i”的机器),同时允许"--apply”选项使用“@” 987654457@" 后端(例如“format-patch piped to am”的道德等价物)。
    rebase.backend配置变量可以设置自定义。)

    它更好地管理空提交:

    commit 10cdb9fcommit 2ac0d62commit 8295ed6commit 76340c8commit 980b482commit c2417d3commit 6d04ce7commit 52eb738commit 8af14f0commit befb89c、@989 @、commit 93122c9commit 55d2b6dcommit 8a997edcommit 7db00f0commit e98c426commit d48e5e2(2020 年 2 月 15 日)和commit a9ae8fdcommit 22a69fd(2020 年 1 月 16 日)@987654。 br>(由 Junio C Hamano -- gitster -- 合并于 commit 8c22bd9,2020 年 3 月 2 日)

    rebase (interactive-backend):修复处理变为空的提交

    签字人:Elijah Newren

    如上一次提交和commit b00bf1c9a8dd("git-rebase: make --allow-empty-message the default", 2018-06-27, Git v2.19.0-rc0 -- merge 中所列batch #4),在各种边缘或角落情况下使用不同后端的 rebase 的行为通常比设计更偶然。

    此提交解决了另一个此类极端情况:提交“变为空”

    细心的读者可能会注意到,有两种类型的提交会由于变基而变为空:

    • [clean cherry-pick] 提交是上游提交的干净樱桃选择,由 git log --cherry-mark ... 确定。
      重新应用这些提交将导致一组空的更改和重复的提交消息;即,这些是上游“已经应用”的提交。
    • [become empty] 开始时不为空的提交,不是上游提交的干净樱桃选择,但在重新定位后仍然为空。
      发生这种情况,例如当提交的更改是上游提交中更改的严格子集时,或者当可以发现提交的更改分布在多个上游提交中时。

    显然,在这两种情况下,相关提交中的更改已经在上游找到,但提交消息可能不在后一种情况下。

    当cherry-mark 可以确定提交已经在上游时,由于cherry-mark 的工作方式,这意味着上游提交消息是关于确切相同的一组更改。

    因此,可以假设提交消息是完全可互换的(实际上可能完全相同)。

    因此,clean cherry-pick case 表示通过保留额外提交无法获得任何信息的情况。

    所有变基类型总是放弃这些提交,据我所知,没有人要求我们这样做。

    对于许多变为空的情况(甚至可能是大多数情况),我们也可以在不丢失信息的情况下放弃提交——但情况并非总是如此。

    由于这些提交代表的案例不是干净利落的,因此没有上游提交消息解释同一组更改。

    具有良好提交消息卫生的项目可能会将我们的提交消息中的解释包含在相关上游提交中或在相关上游提交之间传播,但并非所有项目都以这种方式运行。

    因此,被 rebase 的提交的提交消息可能具有暗示应进行其他更改以适应新基础的推理,或者它可能包含有人想要作为注释添加到另一个提交的信息,或者也许有人甚至想按原样使用提交消息创建一个空提交。

    Junio 评论了“成为空”类型的提交as follows

    WRT 最终为空的更改(而不是从一开始就为空的更改),我认为当前的行为是可取的。
    基于“am”的变基仅仅是为了移植现有的历史,并且想要停止比“交互式”要少得多,后者的目的是在使其可发布之前润色一个系列,并要求确认(“这已经变成空的--做你想放弃它吗?”)从工作流程的角度来看更合适。

    我只想补充一点,他关于基于“am”的变基的论点实际上适用于所有非显式交互式变基。

    此外,由于我们声明不同的情况应该有不同的默认值,因此可能值得提供一个标志以允许用户选择他们希望这些提交的行为。

    引入一个新的命令行标志来选择所需的行为:

    --empty={drop,keep,ask}

    定义:

    • drop:丢弃变为空的提交
    • keep:保留变为空的提交
    • ask:为用户提供一个互动的机会,并根据具体情况选择如何处理变为空的提交

    根据 Junio 的建议,如果没有指定 --empty 标志,则选择默认值如下:

    • 显式交互:询问
    • 否则:放弃

    在 Git 2.33(2021 年第三季度)之前,“git commit --allow-empty-message(man) 不会在出现空消息时中止操作,但编辑器中显示的提示另有说明。此问题已修复。

    参见Hu Jialun (SuibianP)commit 6f70f00commit 54ba2f1(2021 年 7 月 10 日)。
    (由 Junio C Hamano -- gitster -- 合并于 commit 14793a4,2021 年 7 月 28 日)

    commit:删除--allow-empty-message 上的无关提示

    帮助:Junio C Hamano
    帮助:Đoàn Trần Công Danh
    帮助:Felipe Contreras
    签字人:胡家伦

    即使给出了--allow-empty-message 选项,“git commit(man) 也会提供一个带有预填充消息的交互式编辑器会话,如果缓冲区被清空,提交将被中止,这是错误的。

    在给出选项修复它时,从消息中删除“@ 987654480”。

    【讨论】:

    • 就像一个魅力。使用提到的提交构建。 + git rebase --root HEAD --allow-empty-messageSuccessfully rebased and updated detached HEAD.+ git checkout -B master
    • @ElanRuusamäe 谢谢。我已将您的评论包含在答案中以提高知名度。
    【解决方案5】:

    您可以使用樱桃采摘:

    git checkout -b temp_branch master
    git checkout
    git cherry-pick --allow-empty-message first_commit_to_include^..my_branch
    # delete old my_branch and rename temp_branch to my_branch
    git branch -D my_branch
    git branch -m my_branch
    

    【讨论】:

      【解决方案6】:

      您可以重新提交并继续使用空的提交消息:

      Aborting commit due to empty commit message.
      Could not apply XXX... XXX
      $ git commit --allow-empty -C $(<"$(git rev-parse --git-dir)/rebase-merge/onto")
      $ git rebase --continue
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-10-19
        • 2019-08-10
        • 2018-01-29
        • 2014-11-20
        • 1970-01-01
        • 2015-04-20
        • 2015-07-24
        • 2012-04-06
        相关资源
        最近更新 更多