🗝️

Gitコマンド入門::rebase(-i,コミット入替え)「第二十四回」

2021/02/25に公開

みなさん、こんにちは! 今日は、コミット順番を入れ替えてみたいと思います! もう、ここまでやってきたので、お分かりだと思いますが、gitは差分管理なので、基本的には入れ替えなんて、、、そんな無茶なことして大丈夫なのか? って思うと思いますが、、、基本それで正しいです。(爆笑) じゃ、なんでコミットの入れ替え機能なんて出来るのか?! 答えは、複数ファイルにおいて、そのような事ができると便利だということなんですよね。
まあ~、前置きはこのぐらいにして、具体的に試して行きましょう!

前回の記事はこちらから!

https://zenn.dev/shiozumi/articles/ff5ba26a567308

git本家本元の情報はこちらから!

https://git-scm.com/book/ja/v2

今回は、a.txt,b.txt,c.txt,3つのファイルを使います!

echo "# rebase exchange" >> README.md

echo "A" >  a.txt
git add a.txt
git commit -m "A"

echo "B" >  b.txt
git add b.txt
git commit -m "B"

echo "C" >  c.txt
git add c.txt
git commit -m "C"

ここまでは、README.md の内容をコミット毎に変更しましたが、今回は、a.txt, b.txt, c.txtのファイルを、それぞれ追加した状態です。

ハッシュ値 コメント ファイルの中身 補足事項
97926e9 1st # rebase exchange README.md を追加
01c48ba A::a.txt A a.txt を追加
07804af B::b.txt B b.txt を追加
7f44cc2 C::c.txt C c.txt を追加
$  git log --oneline --reverse -p

97926e9 1st
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..ba3d811
--- /dev/null
+++ b/README.md
@@ -0,0 +1 @@
+# rebase exchange

01c48ba A::a.txt
diff --git a/a.txt b/a.txt
new file mode 100644
index 0000000..f70f10e
--- /dev/null
+++ b/a.txt
@@ -0,0 +1 @@
+A

07804af B::b.txt
diff --git a/b.txt b/b.txt
new file mode 100644
index 0000000..223b783
--- /dev/null
+++ b/b.txt
@@ -0,0 +1 @@
+B

7f44cc2 (HEAD -> main) C::c.txt
diff --git a/c.txt b/c.txt
new file mode 100644
index 0000000..3cc58df
--- /dev/null
+++ b/c.txt
@@ -0,0 +1 @@
+C

git rebase -i --root

$ git rebase -i --root

// viが起動!
pick 97926e9 1st
pick 01c48ba A::a.txt  // この行を一番したに移動してみましょう!
pick 07804af B::b.txt
pick 7f44cc2 C::c.txt

// 編集後は、こうなりますね。
pick 97926e9 1st
pick 07804af B::b.txt
pick 7f44cc2 C::c.txt
pick 01c48ba A::a.txt // 一番下に移動しました!

// Esc + wq でエディターの保存終了!

// なんの問題もなく成功!
Successfully rebased and updated refs/heads/main.

// 確認すると、順番も、1st -> B, C, A
$ git log --oneline --reverse
97926e9 1st
947efac B::b.txt
5de6b4c C::c.txt
c3e45b5 (HEAD -> main) A::a.txt

無事完了ですね!

まあ~、どのコミットも、ファイルが増えるだけですから、順番を変えても問題ありません。勿論、まだまだ、複雑なことも想像できるのですが、今は、シンプルに覚えて置きましょう。

実験: git rm a.txt で削除したら?[1]

$ ls
README.md  a.txt  b.txt  c.txt

git rm a.txt
rm 'a.txt'

$ ls
README.md  b.txt  c.txt

$ git add . // <-- ピリオドは、全てのファイルを指します。
$ git commit -m "a.txt delete"
[main 757d814] a.txt delete
 1 file changed, 1 deletion(-)
 delete mode 100644 a.txt

$ git log --oneline --reverse
97926e9 1st
01c48ba A::a.txt
07804af B::b.txt
7f44cc2 C::c.txt
757d814 (HEAD -> main) a.txt delete

deleteコミットの後に、a.txtを移動!

$ git rebase -i --root

// viが起動!
pick 97926e9 1st
pick 01c48ba A::a.txt  // この行を一番したに移動してみましょう!
pick 07804af B::b.txt
pick 7f44cc2 C::c.txt
pick 757d814 a.txt delete

pick 97926e9 1st
pick 07804af B::b.txt
pick 7f44cc2 C::c.txt
pick 757d814 a.txt delete
pick 01c48ba A::a.txt  // 一番下に移動しました!

// Esc + wq でエディターの保存終了!

The previous cherry-pick is now empty, possibly due to conflict resolution.
If you wish to commit it anyway, use:

    git commit --allow-empty

Otherwise, please use 'git cherry-pick --skip'
interactive rebase in progress; onto 653a31d
Last commands done (4 commands done):
   pick 7f44cc2 C::c.txt
   pick 757d814 a.txt delete
Next command to do (1 remaining command):
   pick 01c48ba A::a.txt
You are currently rebasing branch 'main' on '653a31d'.

nothing to commit, working tree clean
Could not apply 757d814... a.txt delete

はい! しっかりエラーになりました!(笑)

Google翻訳
以前のチェリーピックは、おそらく競合解決のために空になりました。
とにかくコミットしたい場合は、以下を使用してください。

git commit --allow-empty

それ以外の場合は、「git cherry-pick --skip」を使用してください
進行中のインタラクティブなリベース。 653a31dに
最後に実行されたコマンド(4つのコマンドが実行されました):
7f44cc2 C :: c.txtを選択してください
757d814a.txtを選択して削除
次に実行するコマンド(残りの1つのコマンド):
01c48ba A :: a.txtを選択してください
現在、ブランチ「main」を「653a31d」にリベースしています。

コミットするものは何もありません。
757d814を適用できませんでした... a.txt削除

それでは最後に、HEADを移動させて、その都度、lsコマンドで、ファイルの存在を確認してみましょう!

// 現状、私の環境は、rebaseして、このような並びになっています。
$ git log --oneline --reverse
97926e9 1st
bcddb69 C::c.txt
de3e7a1 A::a.txt
af2792e a.txt delete
45e0420 (HEAD -> main) B::b.txt

// では、1stにヘッダーを移動!
$ git reset --hard 97926e9
HEAD is now at 97926e9 1st

// 当然、README.md 1ファイルのみですね!
$ ls
README.md

// 次に、C::c.txtにヘッダーを移動!
$ git reset --hard bcddb69
HEAD is now at bcddb69 C::c.txt

// c.txt が追加されました!
$ ls
README.md  c.txt

// 次に、A::a.txtにヘッダーを移動!
$ git reset --hard de3e7a1
HEAD is now at de3e7a1 A::a.txt

// a.txt が追加されました!
$ ls
README.md  a.txt  c.txt

// 次に、a.txt deleteにヘッダーを移動!
$ git reset --hard af2792e
HEAD is now at af2792e a.txt delete

// a.txt が削除されています。
$ ls
README.md  c.txt

// 最後に、B::b.txtにヘッダーを移動!
$ git reset --hard 45e0420
HEAD is now at 45e0420 B::b.txt

// b.txt が追加されました!
$ ls
README.md  b.txt  c.txt

さあ~、ここまで、いかがでしたか? gitは、ファイル単体の差分だけではなく、ファイルの存在そのものも管理しているんですよね。尚、HEADの位置が変わると、、、あれ?ファイルが無いなあ~、なんてことも起こるので、そのあたりにも慣れて置きましょう。

それでは、今回はここまで、お疲れ様でした!

https://zenn.dev/shiozumi/articles/03422819b8613c
https://twitter.com/esmile2013

脚注
  1. git rm コマンドは、おそらく、linuxの、rmコマンドのラッピングのみだと思うので、通常通り、$ rm a.txt でも問題ありませんが、いまのところは、git rm を使いましょう! ↩︎

Discussion