git rebase -i
のsquash
とreword
はよく使っているが、edit
もなんとなくわかったのでメモ。
具体例として「ファイルをあるリビジョンから別のRev.に移動する」、「リビジョンを分離する」の例を示す。
git rebae の edit の動き
リビジョン(以降Rev.)が下記のようにあるとする(上ほど古い)。
aaa1111
bbb2222
ccc3333
ddd4444
eee5555 ← HEAD
この状態から Rev.bbb2222 と Rev.ddd4444 を変更したい場合、git rebase -i
で次のように bbb2222 と ddd4444 のコマンドを e(またはedit)と変更する。
pick aaa1111 change a
e bbb2222 chnage b
pick ccc3333 chnage c
e ddd4444 chnage d
pick eee5555 change e
すると、まず e と変更したRev.のうち、一番古い Rev.bbb2222 が コミットされた直後の状態となる(HEADが Rev.bbb2222を指している)。
aaa1111
bbb2222 ← HEAD
コミット直後の状態なので、modifiedなファイルもstagedなファイルもない。
リビジョンの変更の方法
ここから変更内容によって以下のように操作する。
新たなファイルの追加する場合
Rev.bbb2222 に含まれていないファイルをadd
してcommit --amend
する。
git add <追加するファイル>
git commit --amend
変更対象Rev.に含まれているファイルを再編集する場合
Rev.bbb2222 に含まれているファイルを変更し、add
してcommit --amend
する。
- ファイルを編集する。
git add <編集したファイル>
git commit --amend
変更対象Rev.からファイルを除外する場合
reset @^
で1つ前のRev.に戻る。そして除外するファイル以外をadd
してコミットする。
git reset @^
git add <Rev.に残すファイル>
git commit
modifiedのまま残っているファイルは、以下のように処理する。
・変更を捨てるならcheckout
する。
・直後に別なRev.としてコミットするならadd
してcommit
する。
・もっと先のRev.で使うなら一旦stash
する。
rebase --continue
Rev.bbb2222 に対する編集が終わったら git rebase --continue
を実行する。
すると次の変更対象Rev.の Rev.ddd4444 に移動する(HEADが Rev.ddd4444 を指すようになる)。
Rev.ddd4444の変更が終わって git rebase --continue
を実行すると、git rebase
が完了する。
例
具体例として
y.into@pc01 MINGW64 /c/git_test (master)
$ git log --oneline --name-status -4
41f8473 (HEAD -> master) change d
M d1.txt
M d2.txt
d07aa72 change c
M c1.txt
f721de1 change b
M b1.txt
M b2.txt
1109412 change a
M a1.txt
M a2.txt
M c2.txt
という状態から次の変更を git rebase
で行う。
- Rev.1109412 "change a" に含まている c2.txt の変更を Rev.d07aa72 "chanage c" に移す。
- Rev.f721de1 "change b" を2つのRev.に分割する。
環境は Windows10、Git for Windows、gitbash。
まず、git rebase -i @~4
を実行する。
pick 1109412 change a
pick f721de1 change b
pick d07aa72 change c
pick 41f8473 change d
# Rebase 1544237..41f8473 onto 41f8473 (4 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
<以下略>
変更対象のRev.1109412、f721de1、d07aa72 のコマンドを "e"(=edit)と変更する。
e 1109412 change a
e f721de1 change b
e d07aa72 change c
pick 41f8473 change d
viを終了すると、最初の変更対象Rev.である Rev.1109412 をコミットした直後の状態となる(HEADが Rev.1109412 を指している)。
y.into@pc01 MINGW64 /c/git_test (master)
$ git rebase -i @~4
Stopped at 1109412... change a
You can amend the commit now, with
git commit --amend
Once you are satisfied with your changes, run
git rebase --continue
y.into@pc01 MINGW64 /c/git_test (master|REBASE-i 1/4)
$ git status
interactive rebase in progress; onto 1544237
Last command done (1 command done):
edit 1109412 change a
Next commands to do (3 remaining commands):
edit f721de1 change b
edit d07aa72 change c
(use "git rebase --edit-todo" to view and edit)
You are currently editing a commit while rebasing branch 'master' on '1544237'.
(use "git commit --amend" to amend the current commit)
(use "git rebase --continue" once you are satisfied with your changes)
nothing to commit, working tree clean
y.into@pc01 MINGW64 /c/git_test (master|REBASE-i 1/4)
$ git log --oneline --name-status -1
1109412 (HEAD) change a
M a1.txt
M a2.txt
M c2.txt
reset
で1つ前のRev.に戻し、残したい変更だけadd
してcommit
する。
y.into@pc01 MINGW64 /c/git_test (master|REBASE-i 1/4)
$ git reset @^
Unstaged changes after reset:
M a1.txt
M a2.txt
M c2.txt
y.into@pc01 MINGW64 /c/git_test (master|REBASE-i 1/4)
$ git status
interactive rebase in progress; onto 1544237
Last command done (1 command done):
edit 1109412 change a
Next commands to do (3 remaining commands):
edit f721de1 change b
edit d07aa72 change c
(use "git rebase --edit-todo" to view and edit)
You are currently splitting a commit while rebasing branch 'master' on '1544237'.
(Once your working directory is clean, run "git rebase --continue")
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: a1.txt
modified: a2.txt
modified: c2.txt
no changes added to commit (use "git add" and/or "git commit -a")
y.into@pc01 MINGW64 /c/git_test (master|REBASE-i 1/4)
$ git add a1.txt a2.txt
y.into@pc01 MINGW64 /c/git_test (master|REBASE-i 1/4)
$ git commit -m 'change a'
[detached HEAD dcd363b] change a
2 files changed, 2 insertions(+)
y.into@pc01 MINGW64 /c/git_test (master|REBASE-i 1/4)
$ git log --oneline --name-status -1
dcd363b (HEAD) change a
M a1.txt
M a2.txt
残されたmodifiedな c2.txt は後のRev.に追加するのでstash
で退避しておく。
y.into@pc01 MINGW64 /c/git_test (master|REBASE-i 1/4)
$ git status
interactive rebase in progress; onto 1544237
Last command done (1 command done):
edit 1109412 change a
Next commands to do (3 remaining commands):
edit f721de1 change b
edit d07aa72 change c
(use "git rebase --edit-todo" to view and edit)
You are currently splitting a commit while rebasing branch 'master' on '1544237'.
(Once your working directory is clean, run "git rebase --continue")
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: c2.txt
no changes added to commit (use "git add" and/or "git commit -a")
y.into@pc01 MINGW64 /c/git_test (master|REBASE-i 1/4)
$ git stash push
Saved working directory and index state WIP on (no branch): dcd363b change a
y.into@pc01 MINGW64 /c/git_test (master|REBASE-i 1/4)
$ git status
interactive rebase in progress; onto 1544237
<省略>
nothing to commit, working tree clean
最初の変更対象Rev.の操作は終わったので、git rebase --continue
で次の変更対象Rev.まで進む。
y.into@pc01 MINGW64 /c/git_test (master|REBASE-i 1/4)
$ git rebase --continue
Stopped at f721de1... change b
You can amend the commit now, with
git commit --amend
Once you are satisfied with your changes, run
git rebase --continue
y.into@pc01 MINGW64 /c/git_test (master|REBASE-i 2/4)
$ git status
interactive rebase in progress; onto 1544237
Last commands done (2 commands done):
edit 1109412 change a
edit f721de1 change b
Next commands to do (2 remaining commands):
edit d07aa72 change c
pick 41f8473 change d
(use "git rebase --edit-todo" to view and edit)
You are currently editing a commit while rebasing branch 'master' on '1544237'.
(use "git commit --amend" to amend the current commit)
(use "git rebase --continue" once you are satisfied with your changes)
nothing to commit, working tree clean
y.into@pc01 MINGW64 /c/git_test (master|REBASE-i 2/4)
$ git log --oneline --name-status -1
207e142 (HEAD) change b
M b1.txt
M b2.txt
第2の変更対象である Rev. は2個に分割する。
reset
で1つ前のRev.に戻した後、2つのファイルをそれぞれ別々にコミットする。
y.into@pc01 MINGW64 /c/git_test (master|REBASE-i 2/4)
$ git reset @^
Unstaged changes after reset:
M b1.txt
M b2.txt
y.into@pc01 MINGW64 /c/git_test (master|REBASE-i 2/4)
$ git status
interactive rebase in progress; onto 1544237
Last commands done (2 commands done):
edit 1109412 change a
edit f721de1 change b
Next commands to do (2 remaining commands):
edit d07aa72 change c
pick 41f8473 change d
(use "git rebase --edit-todo" to view and edit)
You are currently splitting a commit while rebasing branch 'master' on '1544237'.
(Once your working directory is clean, run "git rebase --continue")
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: b1.txt
modified: b2.txt
no changes added to commit (use "git add" and/or "git commit -a")
y.into@pc01 MINGW64 /c/git_test (master|REBASE-i 2/4)
$ git add b1.txt
y.into@pc01 MINGW64 /c/git_test (master|REBASE-i 2/4)
$ git commit -m 'change b1'
[detached HEAD b23ff21] change b1
1 file changed, 1 insertion(+)
y.into@pc01 MINGW64 /c/git_test (master|REBASE-i 2/4)
$ git add b2.txt
y.into@pc01 MINGW64 /c/git_test (master|REBASE-i 2/4)
$ git commit -m 'change b2'
[detached HEAD fb3874d] change b2
1 file changed, 1 insertion(+)
y.into@pc01 MINGW64 /c/git_test (master|REBASE-i 2/4)
$ git log --oneline --name-status -2
fb3874d (HEAD) change b2
M b2.txt
b23ff21 change b1
M b1.txt
第2の変更対象Rev.の操作も終わったので、git rebase --continue
で最後の変更対象Rev.に進む。
y.into@pc01 MINGW64 /c/git_test (master|REBASE-i 2/4)
$ git rebase --continue
Stopped at d07aa72... change c
You can amend the commit now, with
git commit --amend
Once you are satisfied with your changes, run
git rebase --continue
y.into@pc01 MINGW64 /c/git_test (master|REBASE-i 3/4)
$ git status
interactive rebase in progress; onto 1544237
Last commands done (3 commands done):
edit f721de1 change b
edit d07aa72 change c
(see more in file .git/rebase-merge/done)
Next command to do (1 remaining command):
pick 41f8473 change d
(use "git rebase --edit-todo" to view and edit)
You are currently editing a commit while rebasing branch 'master' on '1544237'.
(use "git commit --amend" to amend the current commit)
(use "git rebase --continue" once you are satisfied with your changes)
nothing to commit, working tree clean
y.into@pc01 MINGW64 /c/git_test (master|REBASE-i 3/4)
$ git log --oneline --name-status -1
41567ce (HEAD) change c
M c1.txt
Rev.89f04bc "change c" に Rev.9b59dca "change a" から取り除いた c2.txt を追加する。
stash
から取り出してadd
してcommit --amend
する。
y.into@pc01 MINGW64 /c/git_test (master|REBASE-i 3/4)
$ git stash pop
interactive rebase in progress; onto 1544237
Last commands done (3 commands done):
edit f721de1 change b
edit d07aa72 change c
(see more in file .git/rebase-merge/done)
Next command to do (1 remaining command):
pick 41f8473 change d
(use "git rebase --edit-todo" to view and edit)
You are currently splitting a commit while rebasing branch 'master' on '1544237'.
(Once your working directory is clean, run "git rebase --continue")
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: c2.txt
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (28cf2135c67665f5ca212664692fd66ad8a5d050)
y.into@pc01 MINGW64 /c/git_test (master|REBASE-i 3/4)
$ git status
interactive rebase in progress; onto 1544237
Last commands done (3 commands done):
edit f721de1 change b
edit d07aa72 change c
(see more in file .git/rebase-merge/done)
Next command to do (1 remaining command):
pick 41f8473 change d
(use "git rebase --edit-todo" to view and edit)
You are currently splitting a commit while rebasing branch 'master' on '1544237'.
(Once your working directory is clean, run "git rebase --continue")
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: c2.txt
no changes added to commit (use "git add" and/or "git commit -a")
y.into@pc01 MINGW64 /c/git_test (master|REBASE-i 3/4)
$ git add c2.txt
y.into@pc01 MINGW64 /c/git_test (master|REBASE-i 3/4)
$ git commit --amend --no-edit
[detached HEAD 90c4996] change c
Date: Sun Jul 28 20:44:25 2019 +0900
2 files changed, 2 insertions(+)
y.into@pc01 MINGW64 /c/git_test (master|REBASE-i 3/4)
$ git log --oneline --name-status -1
90c4996 (HEAD) change c
M c1.txt
M c2.txt
3つのRev.の変更が終わったので最後の git rebase --continue
で作業完了。
下記のgit log
の結果にあるようにRev.の変更がなされた。
y.into@pc01 MINGW64 /c/git_test (master|REBASE-i 3/4)
$ git rebase --continue
Successfully rebased and updated refs/heads/master.
y.into@pc01 MINGW64 /c/git_test (master)
$ git log --oneline --name-status -5
5043827 (HEAD -> master) change d
M d1.txt
M d2.txt
90c4996 change c
M c1.txt
M c2.txt
fb3874d change b2
M b2.txt
b23ff21 change b1
M b1.txt
dcd363b change a
M a1.txt
M a2.txt