📝

[git 2.43リリース] git revertを2回するとコミットメッセージがReapplyと表示される

2023/12/11に公開

こんにちは、M-Yamashitaです。

この記事は、Money Forward Engineering 1 Advent Calendar 2023 11日目の投稿です。前回はOno Toshikiさんの記事でした。

今回の記事は、git 2.43リリースに含まれていたgit revertコマンドのアップデートの話です。

https://github.blog/2023-11-20-highlights-from-git-2-43/

公式ドキュメントでは変更概要が軽く触れてある程度でしたが、私にとっては結構ありがたい変更と感じました。そのため、どう変わったのかを確認するとともに、前バージョンを跨いだ場合の動作パターンを確認してみました。

この記事で伝えたいこと

  • git revertコマンドで2回revertすると、コミットメッセージがReapplyに変わる
  • 過去のGitを使って対象コミットを1回revertしていると、最新gitのgit revertでコミットメッセージがReapplyに変わる
  • 過去のGitを使って対象コミットを2回revertしていると、最新gitのgit revertでもコミットメッセージがRevert Revertとなる。Reapplyにならない

git 2.43リリースによるgit revertコマンドの変更

git 2.43リリース記事から引用します。

Beginning in Git 2.43, Git will realize when it’s about to perform a double-revert, and instead produce the much more pleasing message:

$ git revert --no-edit HEAD >/dev/null
$ git revert --no-edit HEAD >/dev/null
$ git log --oneline
a300922 (HEAD -> main) Reapply "fix bug"
0050730 Revert "fix bug"
b290810 fix bug
[...]

説明にあるように、2回revertをすると、Reapplyのprefixがコミットメッセージに追加されるようです。

ちなみにここからさらにrevertしたとき、つまり3回revertしたときの挙動も記事にあります。

If you decide to revert for a third time, Git will produce a commit message like Revert "Reapply "fix bug", causing the length of the commit message to grow at a much more reasonable rate over many reverts.

3回Revertすると、Reapplyメッセージに対して、Revertのprefixが追加されます。

実際にやってみる

今回は、適当なファイル作成のコミット1回と、それに対するrevertを4回実施しました。

❯ git log --oneline
0f03ae1 (HEAD -> main) Reapply "Reapply "Create test.txt""
2358c19 Revert "Reapply "Create test.txt""
0eae994 Reapply "Create test.txt"
9410b2e Revert "Create test.txt"
36ef48b Create test.txt

記事通り、2回目のgit revertではReapplyのコミットメッセージとなっています。また3回目以降はRevertがつき、それがReapplyに変わるようになっています。

gitバージョンをまたがったrevertの場合

git 2.43ではReapplyになることが分かりました。それではgitのバージョンをまたがったrevertの場合を確認してみます。
git 2.43未満のgitを使って、revertを1回実行していた場合と、revertを2回実行していた場合を比較します。

ここで、"git 2.43未満のgit"については、今回は2.39.3のgitで試します。

❯ git version 
git version 2.39.3 (Apple Git-145)

git 2.43未満でgit revertを1回実施

以下手順で確認します。

  1. git 2.43未満のgitを使用
  2. 適当なコミットを1回実施し、git revertを1回実施
  3. git 2.43のgitを使用
  4. 2のrevertコミットに対し、2回revertする

結果は以下のとおりです。最新gitでgit revertしたe4f7791のコミットメッセージを見ると、Reapplyのメッセージとなっていることが分かります。

❯ git log --oneline
2645012 (HEAD -> main) Revert "Reapply "Create test.txt""
e4f7791 Reapply "Create test.txt"
5d57d73 Revert "Create test.txt"
cb03863 Create test.txt

git 2.43未満でgit revertを2回実施

以下手順で確認します。

  1. git 2.43未満のgitを使用
  2. 適当なコミットを1回実施し、git revertを2回実施
  3. git 2.43のgitを使用
  4. 2のrevertコミットに対し、2回revertする

結果は以下のとおりです。過去のgitでgit revertを2回実施後、最新gitでgit revertした1b96691のコミットでは、ReapplyとならずRevertコメントが続く事がわかります。

❯ git log --oneline
65dd2eb (HEAD -> main) Revert "Revert "Revert "Revert "Create test.txt""""
1b96691 Revert "Revert "Revert "Create test.txt"""
6596121 Revert "Revert "Create test.txt""
089644f Revert "Create test.txt"
cb03863 Create test.txt

考察

なぜ、2.43未満のgitを使って2回revertを実施していると、Reapplyとはならず、Revertが続くのでしょうか。
この仕様は、2.43リリース時のgitのコードで表されています。

    if (command == TODO_REVERT) {
        const char *orig_subject;

        base = commit;
        base_label = msg.label;
        next = parent;
        next_label = msg.parent_label;
        if (opts->commit_use_reference) {
            strbuf_addstr(&msgbuf,
                "# *** SAY WHY WE ARE REVERTING ON THE TITLE LINE ***");
        } else if (skip_prefix(msg.subject, "Revert \"", &orig_subject) &&
               /*
                * We don't touch pre-existing repeated reverts, because
                * theoretically these can be nested arbitrarily deeply,
                * thus requiring excessive complexity to deal with.
                */
               !starts_with(orig_subject, "Revert \"")) {
            strbuf_addstr(&msgbuf, "Reapply \"");
            strbuf_addstr(&msgbuf, orig_subject);
        } else {

https://github.com/git/git/compare/86b56ff267962ab91aa368b10d6df10b1e9e291e...c9192f9e45f12f7e4c93488eb77a3098e75a78cc

私はCのコードの知識をあまり持っていませんが、このelseifにて以下条件を満たした場合に、コミットメッセージがReapplyに変わるようです。

  1. コミットメッセージが"Revert ""で始まること
  2. 残りのコミットメッセージが"Revert ""で始まらない

つまり厳密には、gitのバージョンに関わらず、コミットメッセージによって挙動が異なるようです。
今回の場合、2.43未満のgitを使ってgit revertを2回実施したため、2つ目の条件に引っかかりませんでした。そのため、Revertのコミットメッセージが追加されたと思われます。

おわりに

今回はgit 2.43リリースに含まれていたgit revertの話をしました。
Reapplyとなったことでコミット内容が結構わかりやすくなったのではないかなと思います。

この記事が誰かのお役に立てれば幸いです。

Discussion