git push — 手元のコミットを GitHub に送る

コミットは、作った時点では手元のパソコンの中にしかありません。それを GitHub に送るのが git push です。一言でいうと、手元のコミットを GitHub に送り、GitHub 側のブランチの付箋を進めるコマンドです。この回では、push で動く2枚の札と出力の読み方、新しいブランチを送る push -u、もう1台の PC が先に push していると拒否される場面を見ます。

画面の見方
  • 上のターミナルは、実際に打ったときと同じ出力です(Git は英語で答えます)
  • 下の中で起きていることには、グラフが2つ並びます。上が GitHub 側、下が手元で、同じコミットは上下で同じ横位置に来ます。丸がコミット、黒い札がブランチ、ピンクの札が HEAD です
  • 手元の点線の札 origin/main は、GitHub の main の位置を手元に写した札です(2-1 で見た追跡ブランチ)。GitHub 側の札が動いても、点線の札は push や fetch をするまで動きません
  • 右の説明をスクロールして読み進めると、左のターミナルでコマンドが1つずつ打たれます。→ キーでも1つずつ進みます(← で1つ戻ります。スマホでは「次へ」ボタン)。最後まで進んでから → を押すと次の区間へ移ります。黄色く光っているのが、そのコマンドで変わった場所です

1. git push — 送ると、2枚の札が動く

2-1 origin と origin/main の正体で見たとおり、clone したリポジトリには origin(GitHub の住所に付けた呼び名)があり、手元には追跡ブランチ origin/main(最後に確かめたときの GitHub の main の位置)が貼ってあります。git push がすることは3つです。

  1. GitHub に無いコミットを、手元から GitHub に送る
  2. GitHub 側のブランチの付箋を、手元のブランチと同じコミットまで進める
  3. 手元の origin/main も同じ位置へ進める

手元の main は、もともと送ったコミットに貼ってあるので動きません。push で動くのは、GitHub 側の main と手元の origin/main の2枚だけです。

git push — コミットを送ると2枚の札が動く

  1. 出発点です。上の GitHub 側の main も、下の手元の main も「卵を追加」に貼ってあります。手元の点線の札 origin/main は、GitHub の main の位置を手元に写した 追跡ブランチ です。

  2. todo.txt に「パンを買う」を書き足して、コミットします。

    $ echo "パンを買う" >> todo.txt
  3. 進んだのは手元の main だけです。GitHub 側の図は何も変わっていません。コミットは、push するまで手元のパソコンの中にしかありません。

    $ git commit -am "パンを追加"
    [main c43e6a8] パンを追加
     1 file changed, 1 insertion(+)
  4. ahead of 'origin/main' by 1 commit は「GitHub の写し(origin/main)より1つ先に進んでいる」という意味です。次の行で Git が、送るなら git push だと教えています。

    $ git status
    On branch main
    Your branch is ahead of 'origin/main' by 1 commit.
      (use "git push" to publish your local commits)
    
    nothing to commit, working tree clean
  5. (HEAD -> main) と (origin/main, origin/HEAD) が別の行に付いています(origin/HEAD は GitHub の既定のブランチを指す写しで、2-1 で見ました)。origin/main の行より上にあるコミットが、push で送られるものです。

    $ git log --oneline --all
    c43e6a8 (HEAD -> main) パンを追加
    8b41d07 (origin/main, origin/HEAD) 卵を追加
    3f2a9c1 牛乳を追加
  6. git push は手元のコミットを GitHub に送り、GitHub 側の main と手元の origin/main を一緒に進めます(手元の main は動きません)。8b41d07..c43e6a8 main -> main は「手元の main を GitHub の main へ送り、8b41d07 から c43e6a8 まで進めた」と読みます。

    $ git push
    To https://github.com/you/memo-app.git
       8b41d07..c43e6a8  main -> main
  7. up to date with 'origin/main' に戻り、ahead の行が消えました。手元の main と GitHub の写しが同じコミットにある、という意味です。

    $ git status
    On branch main
    Your branch is up to date with 'origin/main'.
    
    nothing to commit, working tree clean
  8. 送るものが無いときは Everything up-to-date と出て、何も変わりません。何度打っても害はありません。

    $ git push
    Everything up-to-date
  9. もう1行書き足して、コミットします。

    $ echo "バターを買う" >> todo.txt
  10. また手元の main だけが1つ先に進みました。

    $ git commit -am "バターを追加"
    [main 492da8b] バターを追加
     1 file changed, 1 insertion(+)
  11. -q(quiet=静かに)を付けると、うまくいったときは何も表示しません。中でしていることは git push と同じで、2枚の札が一緒に進みました。Claude Code はこの形をよく打ちます。

    $ git push -q
  12. (HEAD -> main, origin/main, origin/HEAD) と同じ行に並びました。出力の無い push が届いたかどうかは、ここで確かめられます。

    $ git log --oneline -3
    492da8b (HEAD -> main, origin/main, origin/HEAD) バターを追加
    c43e6a8 パンを追加
    8b41d07 卵を追加

push で送られるのはコミットだけです。コミットしていない書きかけは送られません。GitHub に変更が出ていないときは、まずコミットしたかを git status で確かめます。

本物の git push をターミナルで打つと、To https://… の前に Enumerating objects: 5, done. のような進み具合の行も出ますが、この画面では省いています。

2. push の出力と status の読み方

1節の push の出力を、部分ごとに読みます。

出力意味
To https://github.com/you/memo-app.git送り先。origin という呼び名の中身
8b41d07..c43e6a8GitHub 側のブランチを 8b41d07 から c43e6a8 まで進めた
main -> main左が手元のブランチ、右が GitHub 側のブランチ
Everything up-to-date送るものが無かった。何も変わっていない

8b41d07..c43e6a8 の左側は、push する前に GitHub 側の main が指していたコミットです。push の前に git log --oneline --all で見た origin/main の付いた行の ID と同じなら、思ったとおりの位置から進めたことになります。

コミットすると git status に Your branch is ahead of 'origin/main' by 1 commit. と出ます。ahead は「手元の main が写しより1つ先にある=まだ送っていないコミットが1つある」という意味で、push すると消えて up to date with 'origin/main' に戻ります。気をつけたいのは、比べている相手が手元にある写しだということです。git status は GitHub に見に行かないので、up to date は「最後に確かめたときの GitHub と同じ」という意味にすぎません。このずれが問題になる場面を4節で見ます。

Claude Code がよく打つ git push -q の -q は quiet(静かに)の略で、うまくいったときは何も表示しません。送るものも、動く札も git push と同じです。届いたかを確かめたいときは、git log --oneline -3 で (HEAD -> main, origin/main, origin/HEAD) が同じ行に並んでいるかを見ます(origin/HEAD は 2-1 で見た、GitHub の既定のブランチを指す写し)。

3. 新しいブランチの push — 上流と git push -u

作業用のブランチを手元で作って push しようとすると、git push だけでは止まります。原因は上流(upstream)が無いことです。上流は、手元のブランチごとに決めておく「push や pull の相手になる GitHub 側のブランチ」です。clone したときの main には最初から上流 origin/main が付いていますが、git switch -c memo で作ったブランチには付いていません。送り先が決まっていないので、Git は勝手に送らずに止まります。

新しいブランチの push — 上流と push -u

  1. main から作業用のブランチ memo を作って乗り換えます。この付箋は手元にしかなく、GitHub 側にはまだ memo がありません。

    $ git switch -c memo
    Switched to a new branch 'memo'
  2. メモ用の新しいファイル notes.txt を作ります。

    $ echo "牛乳は低脂肪" > notes.txt
  3. ステージに写します。

    $ git add notes.txt
  4. 手元の memo が1つ進みました。このコミットは、まだ手元にしかありません。

    $ git commit -m "メモを追加"
    [memo ad1a0b0] メモを追加
     1 file changed, 1 insertion(+)
     create mode 100644 notes.txt
  5. main の行には [origin/main] がありますが、memo の行には角かっこがありません。memo にはまだ 上流(push や pull の相手になる GitHub 側のブランチ)が決まっていない、という意味です。

    $ git branch -vv
      main e5c0a62 [origin/main] パンを追加
    * memo ad1a0b0 メモを追加
  6. 上流が無いので、git push だけでは送り先が決まらず止まります。Git は git push --set-upstream origin memo を打てば送れる、と教えています。GitHub 側の図は何も変わっていません。

    $ git push
    fatal: The current branch memo has no upstream branch.
    To push the current branch and set the remote as upstream, use
    
        git push --set-upstream origin memo
    
    To have this happen automatically for branches without a tracking
    upstream, see 'push.autoSetupRemote' in 'git help config'.
  7. -u は --set-upstream の短い書き方です。GitHub 側に memo ができ(* [new branch])、手元に origin/memo の札が貼られ、branch 'memo' set up to track 'origin/memo'. で上流が決まりました。remote: で始まる行は GitHub からの返事で、プルリクエストを作る画面の URL です(2-4 で扱います)。

    $ git push -u origin memo
    remote: 
    remote: Create a pull request for 'memo' on GitHub by visiting:
    remote:      https://github.com/you/memo-app/pull/new/memo
    remote: 
    To https://github.com/you/memo-app.git
     * [new branch]      memo -> memo
    branch 'memo' set up to track 'origin/memo'.
  8. memo の行に [origin/memo] が付きました。上流の設定は手元に残るので、-u は最初の1回だけで足ります。

    $ git branch -vv
      main e5c0a62 [origin/main] パンを追加
    * memo ad1a0b0 [origin/memo] メモを追加
  9. notes.txt に1行書き足して、コミットします。

    $ echo "卵は10個入り" >> notes.txt
  10. 手元の memo だけが1つ進みました。

    $ git commit -am "卵のメモを追加"
    [memo cd23d7e] 卵のメモを追加
     1 file changed, 1 insertion(+)
  11. 上流があるので、ahead of 'origin/memo' by 1 commit と GitHub の写しとの差が出るようになりました。

    $ git status
    On branch memo
    Your branch is ahead of 'origin/memo' by 1 commit.
      (use "git push" to publish your local commits)
    
    nothing to commit, working tree clean
  12. 今度は git push だけで送れます。ad1a0b0..cd23d7e memo -> memo で、GitHub 側の memo と手元の origin/memo が一緒に進みました。

    $ git push
    To https://github.com/you/memo-app.git
       ad1a0b0..cd23d7e  memo -> memo

止まったときの出力にあった git push --set-upstream origin memo の短い書き方が -u で、git push -u origin memo はGitHub に memo を作ってコミットを送り、手元に origin/memo を貼り、memo の上流を origin/memo に決める、の3つを一度にします。上流の設定は手元に残るので、-u が要るのはそのブランチを最初に送る1回だけです。

コマンドGitHub にブランチができる上流が付く次から git push だけで送れる
git push(上流が無いとき)できない(止まる)付かない送れない
git push origin memoできる付かない送れない(また止まる)
git push -u origin memoできる付く送れる

git push だけで送るのはいま乗っているブランチだけです。push -u の出力の remote: で始まる行は GitHub からの返事で、その URL はこのブランチからプルリクエストを作る画面です。プルリクエストは 2-4 で扱います。

4. 先に push されていると拒否される

Mac で push したのを忘れて、Windows のノート PC でもコミットして push する。2台で作業するとよく起きるこの場面で、GitHub は push を拒否します。

push が GitHub 側の付箋を進めるのは、GitHub 側のブランチが指すコミットが、送ったコミットの祖先にあるときだけです。この進め方を fast-forward(早送り)と呼びます。GitHub 側に手元に無いコミットがあるのに付箋を動かすと、そのコミットはどのブランチからも辿れなくなります。それを防ぐために、Git は付箋を進めずに断ります。

先に push されていると拒否される

  1. この Windows のノート PC では、手元の main も GitHub の main も「パンを追加」にあります。同じリポジトリを、もう1台の Mac でも使っているとします。

  2. Mac で「バターを追加」をコミットして push しました。GitHub 側の main が1つ進みます。こちらのターミナルには何も出ません。

  3. up to date with 'origin/main' と出ますが、比べている相手は手元にある GitHub の写しです。git status は GitHub に見に行かないので、Mac の push にはまだ気づいていません。

    $ git status
    On branch main
    Your branch is up to date with 'origin/main'.
    
    nothing to commit, working tree clean
  4. それを知らずに、こちらでも「ジャムを買う」を書き足してコミットします。

    $ echo "ジャムを買う" >> todo.txt
  5. 手元の main が「パンを追加」から1つ進みました。GitHub 側の main も同じ「パンを追加」から別のコミットへ進んでいるので、歴史が2つに分かれています。

    $ git commit -am "ジャムを追加"
    [main bbe8599] ジャムを追加
     1 file changed, 1 insertion(+)
  6. main -> main (fetch first) で拒否されました。GitHub 側に手元に無いコミットがあり、このまま main を進めると Mac の「バターを追加」が辿れなくなるからです。GitHub 側の図は何も変わっていません。

    $ git push
    To https://github.com/you/memo-app.git
     ! [rejected]        main -> main (fetch first)
    error: failed to push some refs to 'https://github.com/you/memo-app.git'
    hint: Updates were rejected because the remote contains work that you do not
    hint: have locally. This is usually caused by another repository pushing to
    hint: the same ref. If you want to integrate the remote changes, use
    hint: 'git pull' before pushing again.
    hint: See the 'Note about fast-forwards' in 'git push --help' for details.
  7. 手元の履歴も何も変わっていません。「ジャムを追加」はそのまま残り、Mac の「バターを追加」はまだ手元に届いていないので出てきません。

    $ git log --oneline --all
    bbe8599 (HEAD -> main) ジャムを追加
    e5c0a62 (origin/main, origin/HEAD) パンを追加
    8b41d07 卵を追加
    3f2a9c1 牛乳を追加
  8. ahead of 'origin/main' by 1 commit のままです。拒否された push は、手元にも GitHub にも何も書き込みません。

    $ git status
    On branch main
    Your branch is ahead of 'origin/main' by 1 commit.
      (use "git push" to publish your local commits)
    
    nothing to commit, working tree clean
  9. 拒否は「先に GitHub の新しいコミットを取り込んでから送ってほしい」という合図です。取り込み方(git fetch と git pull)は、次の 2-3 で扱います。

拒否された push は、手元にも GitHub にも何も書き込みません。理由の (fetch first) は「GitHub 側に、手元がまだ受け取っていないコミットがある。先に取ってきて」という意味で、ヒントが 'git pull' before pushing again(もう一度 push する前に git pull して)と勧めているのも同じことです。先に GitHub の新しいコミットを取り込み、それから送り直すのが正しい順番です。

拒否を力ずくで通す git push --force を打つと、Mac で push した「バターを追加」は GitHub のどのブランチからも辿れなくなります。拒否は「上書きすると誰かのコミットが消える」という知らせなので、まずは取り込む方を選びます。force push とその安全な形 --force-with-lease は、第3部の 3-3 で扱います。

5. Claude Code と push

Claude Code が延べ約14,000回打った Git のコマンドのうち、push は310回でした。多いのは git push -q と git push -u origin ブランチ です。push の前後でよく打つのが git branch -r --contains コミットID です。origin/main などの追跡ブランチのうち、そのコミットを含むものを一覧するコマンドで、「このコミットは GitHub に送ってあるか」を確かめています。答えは「最後に確かめたときの GitHub」についてのものなので、別の PC から push された分まで確かめるには、先に git fetch が要ります。

6. Claude Code の許可画面で見かけたら

第1部のコマンドは、どれも手元のパソコンの中だけで完結していました。push は違います。GitHub 側が変わるので、ほかの人や別の PC から見えるようになります。手元なら reflog で取り戻せたものも、一度 GitHub に出たものは「出た」という事実が残ります。

コマンド何が起きるか消えうるもの
git status / git branch -vv / git branch -r --contains見るだけ(手元の写しと比べる)なし
git push / git push -q / git push origin mainコミットを GitHub に送り、GitHub 側のブランチと手元の origin/main を進める注意 消えるものは無い。GitHub 側が変わり、ほかの人や別の PC から見える。取り消しても跡が外に残る
git push -u origin ブランチGitHub に新しいブランチを作って送り、上流を決める注意 消えるものは無い。そのブランチが GitHub 上で見えるようになる
拒否された push(! [rejected])何も書き込まずに止まるなし
git push --force / git push --force-with-lease早送りできない場面でも、GitHub 側のブランチを手元の位置へ動かす(--force-with-lease は手元の写しが古ければ止まる。詳しくは 3-3)GitHub 側にだけあるコミット(ほかの人や別の PC が push したもの)

見分け方は、--force(-f)や --force-with-lease が付いているかどうかです。付いていない push は早送りでしか付箋を進めないので、誰のコミットも消しません。代わりに気にするのは、送る先が合っているかと送ってよい中身かです。許可する前に git log --oneline origin/main..HEAD(origin/main には無く HEAD にはあるコミットの一覧)で、送られるコミットを確かめると安心です。

まとめ

  • git push は、手元のコミットを GitHub に送り、GitHub 側のブランチを進める。同時に手元の origin/main も進む。手元の main は動かない
  • 8b41d07..c43e6a8 main -> main は「手元の main を GitHub の main へ送り、8b41d07 から c43e6a8 まで進めた」。送るものが無ければ Everything up-to-date
  • git status の ahead は「まだ送っていないコミットの数」。push すると消える。比べる相手は手元の写しで、GitHub には見に行かない
  • 新しいブランチには上流が無いので git push だけでは止まる。最初に git push -u origin ブランチ を1回打てば、次から git push だけで送れる
  • GitHub 側に手元に無いコミットがあると (fetch first) で拒否される。拒否された push は何も書き込まない。git push -q は出力が消えるだけ

次の回では、拒否されたときに GitHub の新しいコミットを取り込む git fetch と git pull を扱います。fetch は手元の origin/main の札だけを動かし、手元の main と作業ツリーには触りません。