Git の Push コマンドの使い方
ローカルレボジトリの変更内容をリモートレポジトリにアップロードするコマンド Git Push の使い方を紹介します.
Git Push はローカルレポジトリのコミットをリモートレポジトリにアップロードします. なのでリモートからコミットの内容をダウンロードする Git Fetch や Git Pull コマンドの対にあたるコマンドになります.
ローカルのコミットヒストリが, git commit --amend
によって書き換えられたり, 最後に git fetch
や git pull
した状態から他のコントリビュータによるコミットによって書き換えられたりしていなければ, そのまま git push
でローカルのコミットをリモートにアップロードすることができますが, そうでない場合, git push
は失敗します.
そのような場合でも無理矢理ローカルのコミットを git push --force
でリモートにアップロードすることもできますが, 他のコントリビュータがいない場合はいいですが, そうでない場合限られた場合でのみ使うことが許されます.
Git Push の使い方
それぞれの状況に応じた git push
の使い方を紹介します.
コントリビュータが自分一人だけ
コミットヒストリを書き換えていない
コントリビュータが自分一人だけで, git reset
や git commit --amend
などでコミットヒストリを書き換えていない場合, ローカルとリモートのコミットヒストリは一致するので, そのまま git push
できます.
例えば次のようなコミットヒストリの場合:
A---B---C---D <- master <- HEAD
^
|
origin/master
そのまま次のコマンドを打つと:
git push origin master
次のようになり:
A---B---C---D <- (master <- HEAD, origin/master)
ファストフォワード Push となり, C
, D
のローカルのコミットをそのままリモートに送信することができます.
コミットヒストリを書き換えている
コントリビュータが自分一人だけで, git reset
や git commit --amend
などでコミットヒストリを書き換えた場合, --force
オプションをも使うことによって無理矢理リモートのコミットヒストリをローカルのコミットヒストリに一致させることができます.
例えば次のようなローカルの master
とリモートの master
が一致しているコミットヒストリで:
A---B---C <- master <- HEAD
^
|
origin/master
C
のコミットになんらかの不具合があったので, 不具合を修正し git commit --amend
で C
のコミットを書き換えた場合, 次のようにコミットヒストリが変化します:
A---B---D <- master <- HEAD
\
\
C
^
|
origin/master
ご覧のように B
まではローカルとリモートのコミットヒストリは一致するのですが, git commit --amend
したことによって C
と D
とにコミットが B
から分岐してしまいました.
なので新しく書き換えられた A
, B
, D
というローカルのコミットヒストリに無理矢理リモートのコミットヒストリを一致させる場合, 次のコマンドでできます:
git push --force origin master
するとコミットヒストリは次のようになります:
A---B---D <- (master <- HEAD, origin/master)
このようにコントリビュータが自分一人だけでしたら, git commit --amend
などで既存のコミットヒストリを書き換えたとしても無理矢理 git push --force
でローカルのコミットヒストリにリモートのコミットヒストリを一致させることができます.
コントリビュータが自分以外にいる
コントリビュータが自分以外にいる場合, 自分が最後に git fetch
した時のリモートのコミットヒストリから現在のリモートのコミットヒストリが変わっている可能性がありますので, まず最初に git fetch
してリモートのコミットヒストリをダウンロードします:
git fetch origin master
そして次のようにローカルのコミットヒストリとリモートのコミットヒストリが異なっていた場合:
A---B---C <- origin/master
/
/
D---E---F---G---H <- master <- HEAD
このままでは git push
しても失敗するのであらかじめ git merge
したり git rebase
する必要があります.
それぞれの場合のやり方を紹介します:
git merge
の場合
そのままリモートのコミット C
をローカルのコミット H
にマージさせる場合, 次のコマンドでできます:
git merge origin/master
そしてマージコンフリクトが発生した場合, コンフリクトを解消し git add <file>
でコンフリクトが解消されたというマークをし, git commit
でマージを完了させます.
すると C
と H
がマージした I
というコミットが作られます:
A---B---C <- origin/master
/ \
/ \
D---E---F---G---H-----I <- master <- HEAD
そしたら次のコマンドで:
git push origin master
このようになり, git push
を完了させることができます:
A---B---C
/ \
/ \
D---E---F---G---H-----I <- (master <- HEAD, origin/master)
git rebase
の場合
そのまま git merge
で C
と H
をマージさせて I
というコミットを作ってもいいのですが, コミットヒストリが一直線でなくなりやや複雑になってしまうので, コミットヒストリを一直線にさせたいという場合は git merge
の代わりに git rebase
を使うこともできます.
次のコマンドを入力すると:
git rebase origin/master
このように今度はコミットヒストリが変化します:
D---E---F---A---B---C---G---H <- master <- HEAD
^
|
origin/master
もし git merge
の時のようにマージコンフリクトが発生した場合は, コンフリクトを解消し, git add <file>
でコンフリクトが解消されたというマークをし, git rebase --continue
でリベースを完了させます.
リベースが完了したら, 次のコマンドを入力し:
git push origin master
ローカルのコミットをリモートにアップロードすることができます:
D---E---F---A---B---C---G---H <- (master <- HEAD, origin/master)
まとめ
このように git push
はローカルのコミットをリモートにアップロードし, ローカルとリモートのレポジトリを同期させるためのコマンドです.
コントリビュータが自分一人だけの場合は, 他の人のコミットというものが存在しないので git fetch
や git merge
を使う必要はなく, そのまま git push
したり, 場合によっては git push --force
で無理矢理アップロードすることもできます.
ただ, コントリビュータが自分以外にもいる場合は, git fetch
や git merge
で他の人のコミットを自身のローカルのレポジトリに取り込んだ上で, git push
する必要があります.
そのような共有のレポジトリで git push --force
することは, 他の人のコミットをなかった事にしてしまう可能性があり, コミットヒストリも書き換えてしまって混乱を呼んでしまう事にもなりかねないので, 共有のレポジトリで git push --force
することは本当に必要な場合を除いて避けるべきだと思います.
git push
はそのような事態を引き起こすリスクがあるので, 使われるときは注意して使う必要があるコマンドです.
ただ git push
は Git の操作において必要不可欠な役割を担っているコマンドですので, 上手に付き合っていきたいコマンドです.
関連記事
git rebase でヒストリを直線的にする方法と使う時の注意点2018.08.13
Git の Pull コマンドの使い方2018.06.07
Git のコミット履歴を大胆に書き換えるなら git rebase -i がオススメ2018.08.23
Git の Reset, Checkout, Revert の違い2018.06.01
git merge オプションの --ff, --no-ff, --ff-only の違い2018.08.15