間違えてたらごめんなさい。
以下、現在のブランチの位置を「[]」で括って、到達不可能なコミットを「()」で括って表す。
以下、現在のブランチの位置を「[]」で括って、到達不可能なコミットを「()」で括って表す。
「git commit --amend」の挙動
「git commit --amend」は、正確にはコミットを修正するのではなく修正したコミットを履歴ツリー上の「別の枝」にする作業らしい。例えば、以下のようなcが「あるブランチ」のHEADの時、
a---b--[c]
cをxに修正すると次のように見える。
a---b--[x]
でも、「--amend」を指定したときの実際の挙動は次のようになる模様。
[x]
/
a---b--(c)
/
a---b--(c)
この時、ブランチがx側に切り替わるために、cは到達不可能なコミットとなるため、「git log」等でも表示されないようだ。cのコミットIDが分かっている場合、チェックアウトでコミットcに切り替えられる。また、cにタグや別のブランチがあれば、cは参照可能なコミットなのでコミットIDを調べなくても切り替えることができる。
「git commit --amend」は過去のコミットも修正可能
最初に『「git commit --amend」では過去のコミットも修正できる』と聞いたときには次のような動作をすると思っていた。
修正前
a---b--[c]--d---e
修正後
a---b--[x]--d---e
a---b--[c]--d---e
修正後
a---b--[x]--d---e
しかし、実際には次のようになるらしい。
[x]
/
a---b---c--(d)-(e)
/
a---b---c--(d)-(e)
後はdとeを「git rebase」でxのHEADの位置に移動すれば良い。後からコミットIDを調べるのが面倒なので「git commit --amend」を実効する前に、eの位置に別のブランチやタグを作成しておくとリベースしやすい。
「git reset」の挙動
「git reset」も同様の動きを示す。
a---b--[c]
「git reset HEAD^」を実行すると次のようになる。
a--[b]-(c)
つまりresetはコミットを取り消すのではなく、「履歴を遡る」コマンドということらしい。この状態で新しいコミットxを作成すると分岐する。
[x]
/
a---b--(c)
/
a---b--(c)
Gitは全ての履歴を記録しているという意味がやっとわかった気がする。