🗝️

Gitコマンド入門::rebase(-i,drop,その5,何故#Bの修正が必要なのか?)「第二十一回」

2021/02/22に公開

みなさん、こんにちは!

もう、表題の通りで、どうして、Aをdropすると、Bの修正が必要になるのか? しかも同じ内容で、add,commitすることになるので、普通に考えれば、只の二度手間です。(苦笑) そしてさらに、異なる内容で修正すると、こんどは、BとCでコンフィクトとなり、その次は、CとDと、数珠つなぎでコミットの修正を求められる。また、git rebase --skip を実行すると、今度は、Bが消える。dropしたいのは、Aだけなのに、Bまで消えていく、この操作も、やや理解に苦しみますけどね~ とにかく処理のパターンが増えてしまい複雑怪奇です。まあ~、なにはともあれ、途中をdropするのは、きっと実際ではレアケースで、クリティカルな変更を迫られたシーンのときに、使用する裏技に思えてきましたよ!(大爆笑)

とはとは言えども、ここで、ガッツリ勉強して置くと、なんか理解も深まりそうなので、さらに深堀り、実験を繰り返して見ますね!

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

https://zenn.dev/shiozumi/articles/914792c36161c1

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

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

基本は、gitは、差分管理と心得て!

まあ~、何回か出てきましたけど、差分管理ですから、Aがdropされると、1stとBの間が、すっぽり抜けてしまいますので、1stとA、AとBの差分管理で整合性が取れなくなるのでしょう。で、Bの内容が、"# B"と同じにすれば、1stとBの間の差分情報が、再設定されて無事完了! おそらくその部分は、git側で自動処理しないのは、なんらかの理由があるのでしょう。

"# B"以外に修正すると、Cともマージコンフィクト

こちらの動作も、いきなり面をくらいますね。差分管理をしているので、ひとつ手前のコミットが書き換わると「もしくは、Aがdropされたりも同様」自分自身のコミットも修正しないと、過去との整合性も取れなくなるのでしょう。まあ、元のファイルをベースにして、いまがある。基本は、親子関係ですからね~ 親の苗字が変わったら、子も変わる。そんな関係を管理しているのが、gitそのものですからね。なので、Bが変わったら、Cも変わる。なので数珠つなぎに連鎖していくのでしょう。

"# B"以外に修正して、Cは、"# C"と同じにすれば!

ということで、Bを変更すると、こんどは、BとCで、マージコンフィクトになりますが、そこで、Cを、"# C"に、以前と同じ内容で、add,commit すれば、CとDのコンフィクトは発生しません。

ハッシュ値 コメント README.md 更新 説明
c0f998d 1st # rebase - -
0fa830d A # A drop削除 -
f8b5ccd B # B # B+ BとCの間で、コンフィクトが発生!
2d138a2 C # C # C ここでは、変更しない。
cb468d1 D # D - 何も起こらず!

では、実際にこの動作を試してみましょう!

  1. git rebase -i -root [1]
  2. Aをdrop [vi エディターの操作] [2]
  3. 1stとBのコンフィクトでは、# B+ と変更する。
  4. add,commit -m "B+"
  5. git rebase --continue
  6. BとCのコンフィクトでは、# C のままでとする。
  7. add,commit -m "C"
  8. git rebase --continue

1~4までの処理!

$ git rebase --root -i

// Aをdrop して、Esc + wq

Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
error: could not apply f8b5ccd... B
Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply f8b5ccd... B

$ git log --oneline --reverse
c0f998d (HEAD) 1st

// # B+ と編集する!
$ vi README.md
$ cat README.md
# B+

$ git add README.md
$ git commit -m "B+"
[detached HEAD a690765] B+

$ git log --oneline --reverse
c0f998d 1st
a690765 (HEAD) B+

5~8までの処理!

$ git rebase --continue

// 今度は、BとCでコンフィクトが発生!

Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
error: could not apply 2d138a2... C
Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply 2d138a2... C

$ vi README.md
// # C と編集する!・・・前と同じ内容です。

$ cat README.md
# C

$ git add README.md
$ git commit -m "C"
[detached HEAD 5039c01] C
 1 file changed, 1 insertion(+), 1 deletion(-)

$ git log --oneline --reverse
c0f998d 1st
a690765 B+
5039c01 (HEAD) C

$ git rebase --continue
Successfully rebased and updated refs/heads/main.

$ git log --oneline --reverse
c0f998d 1st
a690765 B+
5039c01 C
ebb1ab2 (HEAD -> main) D

次は、1stとBで、コンフィクトした後は、全てskip

  1. git rebase -i -root
  2. Aをdrop [vi エディターの操作]
  3. git rebase --skip を繰り返す!
$ git rebase -i --root

// Aをdrop して、Esc + wq

Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
error: could not apply f8b5ccd... B
Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply f8b5ccd... B

// 1stとBでコンフィクト --skip実行!
$ git rebase --skip

Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
error: could not apply 2d138a2... C
Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply 2d138a2... C

// 今度は、1st と Cのコンフィクト、マージエラー!
$ cat README.md
<<<<<<< HEAD
# rebase
=======
# C
>>>>>>> 2d138a2... C

// --skip実行!
$ git rebase --skip

Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
error: could not apply cb468d1... D
Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply cb468d1... D

// 今度は、1st Dのコンフィクト、マージエラー!
$ cat README.md
<<<<<<< HEAD
# rebase
=======
# D
>>>>>>> cb468d1... D

// --skip実行!
$ git rebase --skip
Successfully rebased and updated refs/heads/main.

// 結果、1stのみとなる。
$ git log --oneline --reverse
c0f998d (HEAD -> main) 1st

まとめ::その1

gitは差分管理なので、dropやeditした場合は、親子関係の再構築、ファイルの内容は同じでも、add,commit で再設定する必要がある。尚、--skipすると、そのコミットが省かれる。その動作は、dropと同じです。そもそも、このコマンドを使うのはレアケースであると思います。ただ、gitの仕組みを理解するには、とてもよいきっかけとなりましたね。(^^;;

まとめ::その2

Aを、drop すると、Bの立場からすれば、A=親が急にいなくなったと同じ、その親の1st=を新しい親だと認識する。ただ、1stと、Aとはファイルの差分が異なるため、コンフィクトエラーとなってしまう。従って同じ内容でコミットすることになるけども、1stとBの差分情報が更新されて、無事、親子関係を設定して完了! 今の時点では、このように解釈して置きましょう![3]

次回の課題

edit にて、コミットの分割、また、editにて、B=子、C=孫、D=ひ孫が、変化することも、試して見たいと思います!

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

https://zenn.dev/shiozumi/articles/8d7d6a31f562f4
https://twitter.com/esmile2013

脚注
  1. 初期状態に戻すには、git reflog + git reset --hard [ハッシュ値] ↩︎

  2. dropは、pickを、dropに変更する他、そのまま、行を削除しても同じです。 ↩︎

  3. 私自身が学習中の過程です。間違っている可能性もありますので、悪しからず! ↩︎

Discussion