歴史は一方通行ではない
今更言うまでもありませんが、Gitは便利ですよね。
Gitの基本的な使い方は歴史を重ね・分岐し・まとめていくことですが、歴史を逆行し・書き換え・削除したくなる場合もあります。
そんなときに使えるエイリアス(というかサブコマンド)をいくつか作ったので解説します。
みなさんにも軽率に歴史改変していただけると幸いです。
なお、実際に使用している.gitconfig
等は以下のリポジトリで管理しています。
dependencies
本記事で紹介するエイリアスでは、git
以外に下記のコマンドを使用します。
xargs
grep
head
fzf
fzf
は改行区切りのテキストからfuzzy findできるCUIアプリです。本当に便利なので知らない方は使ってみてください。
fzf is a general-purpose command-line fuzzy finder.
junegunn/fzf
その他のコマンドは普通の環境には入っていると思いますが、xargs
のバージョンが古い場合、以下で使用しているオプションが対応していない可能性があります。
直前のコミットの修正
歴史をひとつ戻る git uncommit
[alias]
uncommit = reset --soft HEAD^
直前のコミットをなかったことにし、変更をステージングエリアへ戻します。
ウンコミットではない
歴史を修正する git amend
[alias]
amend = commit --amend
現在ステージングされている変更を直前のコミットにまとめる形で再度コミットします。
コミットメッセージの修正もできます。
2つ以上前のコミットの修正
歴史を思い出す git remember
[alias]
remember = __remember
#!/bin/bash
git log --graph --color=always --format="%C(auto)%h%d %C(black bold)%cr %C(auto)%s" "$@" | \
fzf --ansi --exit-0 --no-sort --no-multi --tiebreak=index --height=100% \
--preview="grep -o '[a-f0-9]\{7\}' <<< {} | head -1 | xargs --no-run-if-empty git show --color=always" \
--header="Ctrl-y to toggle preview, Ctrl-u to preview down, Ctrl-i to preview up" \
--bind="ctrl-y:toggle-preview,ctrl-u:preview-down,ctrl-i:preview-up" \
--preview-window=down:60% | grep -oE '[a-f0-9]{7}' | head -1
コミットグラフからfzfでコミットハッシュを取り出すコマンドです1。変更内容を見つつコミットを選択できます。
Gitはgit-xxx
という名前の実行可能ファイルをPATHの通ったディレクトリに置くことでサブコマンドを追加することができます。今回のもので言うと、git-remember
という実行可能ファイルを上記の内容で作成し、PATHの通ったディレクトリに配置すれば、自動的にgit remember
というコマンドが使えるようになります。
ただ、私は自分の追加したコマンド群を.gitconfig
内で一覧したいため、git-__remember
というファイルを追加し、さらに.gitconfig
にてエイリアスを定義して呼び出すという形をとっています。
本質的には以下のワンライナーです。調整していくうちに、プレビューや色付けなどのオプションが増えて長くなりました。
git log --oneline | fzf --no-multi | grep -oE '[a-f0-9]{7}' | head -1
歴史を巻き戻す git rewind
[alias]
rewind = !git remember | xargs --no-run-if-empty git reset --soft
最初に示したgit uncommit
の増強版です。2つ以上前の段階へ戻りたいとき、git uncommit
を何度も打つよりはこちらを使ったほうが楽です。
前出のgit remember
でコミットを選択し、そこまで一気に戻り、以降の作業をなかったこと2にします。
歴史を書き換える git allohistory
[alias]
allohistory = !git remember | xargs --no-run-if-empty --open-tty git rebase -i
git rebase -i
をカジュアルに使うためのコマンドです。
前出のgit rewind
と同様に過去のコミットまで戻りますが、こちらは戻ったコミット以降の歴史を壊さないため、過去の1点のみを修正するということが出来ます。
ここではrebase
の使い方の説明は省略しますが、修正の他にも、歴史の削除や整理が可能です。
未来へ帰る git btf
[alias]
btf = rebase --continue
前出のgit allohistory
で過去に戻った後、1.21ジゴワット使って 未来へ帰るためのコマンドです。
git delorean
でも良かったかもしれません。
なお、未来へ帰ってくる途中の歴史の流れによってはコンフリクトが発生します。
歴史を整理する git fixup
[alias]
fixup = !git remember | xargs --no-run-if-empty -I_ git commit --fixup _ && git rebase -i --autosquash
git allohistory
なら柔軟に歴史を編集できますが、過去のコミットひとつに変更を加えたいときにはこちらのほうが便利です。
選択したコミットへ現在ステージングされている変更をねじ込みます。
こちらも変更内容によりコンフリクトが発生し得ます。
さあ歴史を変えよう
簡単に歴史を移動できるようになると、自分がどの段階にいるのかわからなくなるので、簡単に確認できるツールがあるといいと思います。私はstarshipを使っています。
歴史改変コマンドは用法・用量を守って正しくお使いください。