第6章 push と pull
ローカル、リモート、リモート追跡ブランチ
前章で origin という名前のリモートを設定した。ここで登場人物を整理しておく。
- ローカルブランチ: 手元のリポジトリにある
main等。コミットを積むのはここ - リモートブランチ: GitHub 側に存在する実体の
main。他のコラボレーターと共有される - リモート追跡ブランチ:
origin/mainの形で表される、ローカルがリモートの状態を覚えておくためのブランチ。手元のキャッシュだと思うと分かりやすい
「ローカルの main」と「origin/main」はぜんぜん別のブランチである。
手元でコミットを積むと、ローカル main だけが前進する。
誰かが GitHub 側で main を更新しても、git fetch するまで手元の origin/main は古いままである。
push で GitHub に送る
初回 push の -u
前章で git remote add origin ... したばかりの状態では、ローカル main はまだどのリモートブランチとも紐づいていない。
初回だけ -u (--set-upstream の短縮形) を付けて、「このローカル main は origin/main を追いかけるよ」という関係を記録する。
git push -u origin main
2 回目以降
一度 upstream が紐づけば、以降は引数なしで OK。Git はどのリモートのどのブランチに送ればいいかを自分で判断してくれる。
git push
リモートが自分のローカルより先に進んでいる状態で git push しようとすると、! [rejected] というエラーで断られる。
これは「君の手元は古い。先に pull してから出直して」という意味のサイン。後述する pull で最新を取り込んでから push し直せばよい。
間違っても、慌てて --force を付けないこと。他人のコミットを押しつぶす事故になる。
pull で GitHub から受け取る
他の人が GitHub の main にコミットを積んだあと、自分も同じ最新状態に追いつきたい。
そのときに打つのが git pull。たった 1 つのコマンドに見えて、実は 2 段階の処理がまとまっている。
git fetch: リモートの最新情報をダウンロードし、手元のorigin/mainを更新する (ローカルmainはまだ動かない)git merge origin/main: 手元のmainにorigin/mainの変更を取り込む
git pull
# これは実質↓と同じ
# git fetch
# git merge origin/main
fetch だけしたいとき
「ひとまずリモートの状態だけ見たい。merge するかどうかは差分を確認してから決めたい」という場面もある。
その場合は git fetch だけ打てばよい。
# リモートの最新を取得 (マージはしない)
git fetch
# ローカル main と origin/main の差分を確認
git log main..origin/main --oneline
チームによっては git pull のデフォルト挙動を rebase (マージコミットを作らず履歴を直列に並べ直す) にそろえる流儀もある。
git config --global pull.rebase true でその動作になる。プロジェクトのポリシーに合わせて選ぶとよい。
よくあるトラブルの入り口
push が rejected される
「リモートが先行している」が原因。git pull で最新を取り込み、コンフリクトがあれば解消してから git push。
コンフリクト解消の作法は発展編で詳しく扱う。
Permission denied (publickey)
SSH 鍵が GitHub 側に登録されていない、あるいは鍵のパーミッションがおかしい、が定番。
ssh -T git@github.com で挨拶が返ってこないなら、前章の手順を見直す。
リモートがずれてきた気がする
git fetch してから git status を打つと、「Your branch is behind 'origin/main' by N commits」のように、
ローカルとリモート追跡ブランチの関係を Git が教えてくれる。
迷子になったと感じたら、まず git fetch + git status で現在地を確認するのが近道である。
まとめ
- ローカル
mainとorigin/mainは別物。origin/mainはリモートの状態を覚えておくキャッシュ - 初回だけ
git push -u origin mainで upstream を設定、以降はgit pushだけで OK git pullはgit fetch+git mergeの合成技- push が rejected されたら、
--forceではなくpullで最新を取り込んで出直す