Gitで一度pushしたブランチでgit commit –amend/git rebase後再度pushする方法
概要
Gitでブランチを作成して,別のブランチの内容を取り込む場合,git merge
とgit rebase
の2種類の基本的なコマンドがある。
git merge
はマージ用のコミットが発生して,コミット履歴が枝分かれして汚くなる。
git rebase
は派生元を付け替えるので,マージ用のコミットが発生せず,コミット履歴の枝分かれもせず,履歴がきれいになる。ただし,一度git push
してしまうと,他の人がリモートリポジトリーの内容を参照できるため,git rebase
して再度git push
するとコンフリクトする。git rebase
だけでなく,git commit --amend
のように過去のコミットを変更する場合も同じパターンとなる。
自分一人のプロジェクトであれば,git push -f
で強制上書きすればいいが,多人数での共有リポジトリーでは,gitサーバーの設定でgit push -f
はほぼ禁止されている。
そのため,git push
していなければ,git rebase
,git push
してしまったらgit merge
で取り込むのがブランチのマージの基本だった。
ただ,git merge
は余計なマージ用コミットが入るのが気に入らなかったり,コミット履歴が汚くなるのが,以前から気に入らなかった。
方法
ぼんやり考えていたら,一度git push
したブランチをgit rebase
してコンフリクトを起こさずに再度git push
する方法を思いついた。
その方法とは,git push
したリモートブランチを削除することだ。
git push
した後にgit rebase
してgit push
すると,当然ながらリモートブランチにはgit rebase
した情報が含まれていないため,ローカルブランチとリモートブランチのコミットの内容に齟齬が生じるため,コンフリクトする。しかし,そもそもリモートブランチを削除してしまえば,ローカルとリモートとの差異を気にする必要がなく,問題なくgit push
できる。
リモートブランチの削除方法は「Gitのリモートブランチとローカルブランチの削除方法 – senooken.jp」に記した通り,以下のコマンドとなる。
git push -d <remote-repository> <branch-name>
git push -d origin topic
リモートブランチさえ削除してしまえば,問題なくgit push
できる。
例
試しにありがちな事例でコマンド例を示す。具体的には,README.txt
を追加するつもりが,誤ってREDME.txt
と入力してgit push
してしまうケースを想定する。
まずはdevelop
ブランチを作成して,間違えた状態でコミットgit push
する。
git checkout -b develop
touch REDME.txt
git add REDME.txt # type miss
git commit -m "Add README.txt"
git push
Enumerating objects: 4, done. Counting objects: 100% (4/4), done. Delta compression using up to 4 threads Compressing objects: 100% (2/2), done. Writing objects: 100% (3/3), 281 bytes | 281.00 KiB/s, done. Total 3 (delta 0), reused 0 (delta 0) remote: remote: Create a pull request for 'develop' on GitHub by visiting: remote: https://github.com/senooken/git-example/pull/new/develop remote: To https://github.com/senooken/git-example.git * [new branch] develop -> develop
ここでタイプミスに気付いて直し,再度pushする。
git mv REDME.txt README.txt
git add README.txt
git commit --amend --no-edit
git push
To https://github.com/senooken/git-example.git ! [rejected] develop -> develop (non-fast-forward) error: failed to push some refs to 'https://github.com/senooken/git-example.git' hint: Updates were rejected because the tip of your current branch is behind hint: its remote counterpart. Integrate the remote changes (e.g. hint: 'git pull ...') before pushing again. hint: See the 'Note about fast-forwards' in 'git push --help' for details.
当然ながら,コンフリクトする。以前まではこれでお手上げだった。こうなると,git pull
でリモートブランチの内容でローカルにマージしてからgit push
する必要があった。
ここでリモートブランチを削除して再度git push
する。
git push -d origin develop
git push
Enumerating objects: 4, done. Counting objects: 100% (4/4), done. Delta compression using up to 4 threads Compressing objects: 100% (2/2), done. Writing objects: 100% (3/3), 284 bytes | 284.00 KiB/s, done. Total 3 (delta 0), reused 0 (delta 0) remote: remote: Create a pull request for 'develop' on GitHub by visiting: remote: https://github.com/senooken/git-example/pull/new/develop remote: To https://github.com/senooken/git-example.git * [new branch] develop -> develop
問題なくgit push
が成功した。git push
してしまっても,リモートブランチを削除してしまえば,コミットのやり直しが自由にできる。
結論
git push
後にgit rebase
やgit commit --amend
で過去のコミットを変更して再度git push
する方法を記した。
Gitはブランチを気軽に作ったり削除することが念頭に置かれている。間違えてgit push
してしまっても,慌てずにリモートブランチを削除して対応すればいい。
ただし,複数人の作業でgit push
した過去の内容を他の誰かが参照していて,その人がgit push
するとコンフリクトしてしまう。安全策を取るならば,削除後にgit push
する際のブランチ名は違う名前にしたほうが無難だろう。
“Gitで一度pushしたブランチでgit commit –amend/git rebase後再度pushする方法” に対して1件のコメントがあります。