世界を動かす技術を、日本語で。

Gitの履歴コマンドはもっと注目されるべきだ

2026年7月14日原文(lalitm.com)

概要

  • git で並行して多くの変更を扱う際の課題とストレス
  • jj という新しいツールの登場とその評価
  • git history コマンドの紹介とその三つのサブコマンド
  • 各サブコマンドの特徴と実際の使い方
  • 今後の期待と git history の将来性

gitでの並行作業の課題とjjの登場

  • 複数の変更 を扱う際、ブランチやコミットの管理が複雑化
  • git rebase -i のようなコマンドは、途中でエラーが起きるとツリーが壊れるリスク
  • jj はこの問題への新しいアプローチとして注目されるツール
    • jj はGitの課題解決を目指すが、使い勝手がまだ自分には合わない
    • 1.5年にわたり定期的に試すが、最終的にはgitに戻る傾向

git historyコマンドの登場と利点

  • git history は実験的なコマンドで、リリース2.54(reword/split)と2.55(fixup)で追加
  • jj の利点の一部を git 内で実現可能
  • git本体に標準搭載 されているため、追加インストール不要
  • fixup, reword, split の三つのサブコマンドを提供

fixupサブコマンドの特徴

  • git history fixup <commit> で、過去のコミットを修正し、全ての関連ブランチを自動再構築
    • 修正内容を git add でステージし、fixupで指定コミットに統合
    • git commit --fixup + autosquash rebase に似ているが、さらにブランチ全体を自動更新
    • merge commit が存在する場合は非対応
    • 操作は アトミック で、ツリーが中途半端な状態にならない
    • 競合が発生する場合は操作自体を拒否 し、安全性を確保

rewordサブコマンドの特徴

  • git history reword <commit> で、過去のコミットメッセージを変更し、上位コミットを自動再構築
    • コミット内容は変更せず、メッセージのみ編集
    • インデックスや作業ツリーには一切影響なし
    • チェックアウトしていないブランチのコミットも安全に書き換え可能

splitサブコマンドの特徴

  • git history split <commit> で、1つのコミットを2つに分割
    • インタラクティブに差分を選択し、 2つの新コミット として分割
    • git add -p に似ているが、rebaseの複雑な操作が不要
    • 特殊な用途だが、必要な場面では非常に有用

jjとgit historyの比較・今後への期待

  • jj は操作ログや簡単なundo、作業コピーのコミット化、競合の持ち越しなど高度な機能を提供
  • git history はjjほどの柔軟性はないが、 日常のgitワークフローに自然に統合可能
  • ドキュメントからも、今後さらに機能拡張される可能性に期待

まとめ

  • git history は、 jj の利点の一部を git 本体で実現
  • 安全性と簡便さ を両立し、既存のワークフローに取り入れやすい
  • 今後のアップデートで、さらに多くの機能が追加される可能性

Hackerたちの意見

要するに、新しいバージョンのgitでは、git rebase --interactiveのよく使われる3つのケースを別の簡単なコマンドとして実装したみたい。どうやら、コンフリクトがないときだけ機能するらしい。

historyコマンドって、そんなに役に立つのかな?俺はインタラクティブリベースの方が好きで、よく使ってる。コミットを「視覚的」に動かす方が、ローカルブランチにもうない孤立したコミットハッシュに「git history」を当てるより全然いいよ。

怖いリベース -i コマンドは、ちょっとしたことでツリーが半分壊れた状態になることがあるけど、git rebase --abortがあるから安心して。リベースする前にタグを設定しておけば、何でもやった後にgit reset --hard $set_tagで戻れるし。怖がることなんてないよ。元の状態が失われるわけじゃないから。

git reflog使ってる?

その理由で、tempbefore-rebaseって名前のブランチがめっちゃたくさんあるよ。実質的にはタグとして使ってるけど、タグよりもブランチの方が気軽に動かせるからね(タグはv1.2.3みたいな特定のもののために作られて、一度置いたらほとんど動かさないし)。だから、大きなrebase -iを実行する前に、いつもgit branch before-rebase/some-featureってやってる。git reset before-rebaseを実行する必要はほとんどないけど、git log -p before-rebaseをよくやって、リベース後のブランチの状態と比べて、リベース中に出たマージコンフリクトの解決が意図しない変更を引き起こしてないか確認してる。

それすら必要ないよ。git reflogで好きなところに戻ればいいだけ!

git history splitは、ジュニアたちが大きなPRを小さくて分かりやすい変更に分けるのを手助けしてくれる。もし簡単にブランチ全体を2つに分けるオプションがあればいいのに。

ブランチを2つに分けるって、どういう意味?

もしかしたら、PRを高価なものだと思ってるのかもね。最初から小さなことをやって、そのPRを作ればいいのに。もし今やった変更を基に将来の変更をするなら、その場で新しいフィーチャーブランチを作ればいいし、最初のがマージされるまで二つ目のフィーチャーのPRを作らなくてもいい。あるいは、二つ目のPRを作って、レビューアに「これには他のPRの変更が含まれてるから、そっちを先にレビューしてほしい」ってメモを付ければいい。最初のフィーチャーに変更を加えたいなら、そのブランチをチェックアウトして変更して、二つ目のフィーチャーブランチにマージすれば、そこでも使えるようになるよ。

最後の部分は、git rebase --update-refsよりも進んでいて、これはアクティブにリベースしている範囲内にあるrefsだけを移動させる。git historyは、コミットから派生したすべてのローカルブランチを見つけて書き換える(現在のブランチのみに制限するオプションもある)。これを読むと、今Dをチェックアウトしていて、BB'に更新する場合、次の状態になるってこと? A ──► B ──► C ──► D │ └───► E これだとEはそのまま残る? A ──► B' ─► C' ─► D' │ └───► B ──► E (追記:最初はEB'を指してたけど、それは意味がないね)もしgit history fixupを使ったら、Eも更新されてこうなる? A ──► B' ─► C' ─► D' │ └───► E' そうなるなら、git rebaseに同じ動作をさせる方法はあるのかな?もう何十年もgit rebaseを使ってきたから、指が覚えてるよ。

これだとEはそのまま残る?無理だよ、コミットのハッシュは親のハッシュも考慮するから。--update-refsは使ったことないけど、読む限りでは、君の3つ目のグラフになるはず。だから、> git rebaseに同じ動作をさせる方法はあるの?はもう実際そうなってるよ。

見てみて: https://blog.hot-coffee.dev/en/blog/git_update_refs/

Hacker Newsで議論の続きを見る