大きな画面での利用をおすすめします — アニメーションと操作がより快適になります。
入力

リモートとの共同作業

Git のクローンには独自のオブジェクト庫、ローカルブランチ、サーバー状態のキャッシュがある。fetch、pull、push は違う境界を越えるので、各部分が別のコミットにとどまりうる。

origin/main は最近知ったリモート位置で、サーバーのライブ表示ではない。fetch はローカルオブジェクトと origin/main を更新し、main やチェックアウトは動かさない。pull --ff-only は fetch 後に main とチェックアウトの前進を試す。push はサーバーの現在先端を早送りできる場合だけリモート main を更新する。

クローンと origin は別の状態を持つ

左のローカルにはオブジェクト庫、refs/heads/main、refs/remotes/origin/main、HEAD、チェックアウトした app.py がある。右の origin は独自のオブジェクト庫と、正本の refs/heads/main を持つ。

名前保存場所意味
mainローカル現在のローカルブランチ先端
origin/mainローカルクローンが最後に知ったリモート先端
origin:mainリモート本レッスンのサーバー側 main の表示名

クローン直後は三つとも基点を指し、両庫がそのオブジェクトを持ち、app.py は v1。後で同僚がサーバーを進めても、ローカルの二参照は触られない。

表示 ID は決定的な Git 形式。コミットがツリー、ツリーが app.py の blob を指す。アニメーションはコミット、ツリー、blob をまとめて輸送単位として描き、正確な Git オブジェクト数も報告する。

一回の共同作業のステップ

  1. 同僚の受理された push が app.py=v2 の server-fix を作る。サーバーは blob、ツリー、コミットを保存してから origin:main を基点から進める。ローカル main、origin/main、チェックアウトは変わらず、サーバーの前進をまだ知らない。
  2. git fetch origin がサーバーの main 通告を読み、ローカル庫と比べて不足する到達可能オブジェクトをコピーする。転送中は参照を動かさず、ローカル保存が完了してから origin/main だけを server-fix へ進める。
  3. 同僚のコミットはローカルにあるが、main とチェックアウトは v1。統合前に報告された履歴を調べられる。
  4. git pull --ff-only がまず fetch する。直前に取得済みなのでオブジェクト到着も追跡参照更新もゼロ。次に main が origin/main の祖先かを調べ、成立するので main を server-fix へ進め、app.py=v2 をチェックアウトする。マージコミットは作らない。
  5. ローカルで app.py=v3 の client-ui を作る。server-fix を親とする blob、ツリー、コミットを保存してから main を進める。origin/main と origin:main は動かず、既知のリモートより一コミット先になる。
  6. git push origin main がローカル先端をリモート main に提案する。Git クライアントは送信前に、サーバーが通告した現在先端が提案先端の祖先かを検査する。成立後、不足する client-ui のオブジェクトを保存し、origin:main を進める。成功応答がローカル origin/main を更新し、三参照は client-ui、チェックアウトは v3 でそろう。

通常の fetch、Fast-forward pull、push はコミット ID を変えない。同じ内容アドレスのオブジェクトをコピーして参照を更新し、通信がローカルコミットを別のリモートコミットへ変換することはない。

三つの参照を読む

main はローカルブランチの位置、origin/main は最後の観測、origin:main はサーバーの実位置を答える。追跡参照が古い間にも同僚は push でき、fetch は現在ブランチを動かさずキャッシュを更新する。

  • git status の ahead/behind はローカルの上流参照を使う。新しさが必要なら先に fetch する。
  • git branch -vv はブランチと設定済み上流を示し、main が origin/main を追跡しているか確認できる。
  • git log --oneline main..origin/main は追跡側だけのコミット、逆の origin/main..main はローカル側だけのコミットを示す。

push や ff-only pull の拒否後は両範囲を確認し、merge か rebase を選ぶ。復旧手順自体は本レッスンの対象外だが、三参照で何が分岐し、どの情報が古いか分かる。

境界ケース

  • 同期済みの fetch は、通告対象も追跡参照も既知なので、転送と参照書き込みがゼロ。
  • main がすでに origin/main を含む(同じか main が先行)なら、ff-only pull は最新と報告し、書き込みも拒否もしない。
  • main と origin/main が基点から別々の子を持てば ff-only は統合できない。ただし pull の fetch は取り消されず、新オブジェクトと更新された origin/main は残る。main とチェックアウトだけが不変になる。
  • push はキャッシュではなく実リモート先端を検査する。前回の fetch 後に同僚が、ローカル main に含まれない先端へ進めていれば非 Fast-forward として拒否する。本モデルの拒否は永続的なリモートオブジェクト・参照書き込みをゼロにする。
  • 最新状態の push は不足オブジェクトもリモート移動もないが、成功応答が古いローカル origin/main を更新する場合はある。

よくある間違い

  • fetch がチェックアウトしたファイルを更新すると思う。オブジェクトと追跡参照だけを更新し、統合は merge、rebase、pull で行う。
  • pull を独立した第三の同期原語と考える。取得の後に統合方式を実行する。本レッスンは ff-only なので、成功は一回のブランチ移動、分岐は停止になる。
  • push が作業ツリーやインデックスを送ると思う。提案参照から到達可能なオブジェクトだけが対象で、未コミット編集は main から到達できない。
  • 拒否でローカルコミットが消えたと思う。オブジェクトとブランチは残る。Git は現在先端を含まない履歴への置換を拒否しただけだ。

モデルの範囲

実 Git は pack の交渉、delta 圧縮、設定済み refspec、多ブランチ、多リモート、merge/rebase による pull を扱う。本レッスンは一ブランチ、一ファイル、一リモート、pull --ff-only、表示上八つの異なるコミットに固定する。これらは Git の制限ではない。

コマンドの契約は git fetch、git pull、git push を参照できる。