Works by

Ren's blog

@rennnosuke_rk 技術ブログです

【git】git pushのデフォルト動作を追う

git push

前回の記事では、引数やオプションのないgit pushの挙動を確認しました。
今回はgit pushに何も指定しない場合、どのような動作になるのかを検証しました。

git pushの挙動

試しにmasterブランチ上でファイルhoge1.txtに変更を加え、リモートリポジトリにgit pushします。

# ブランチの構成
$ git branch
  branch1
  branch2
* master

# ファイルの構成
$ ls
LICENSE    README.md  hoge1.txt

# hoge1.txtに変更を加える
$ echo "hoge" >> hoge1.txt

# hoge1.txtがブランチのheadから変更された
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   hoge1.txt

no changes added to commit (use "git add" and/or "git commit -a")

# 変更をステージング&コミット
$ git commit -a -m "modify hoge1.txt"
[master 6c13eb5] modify hoge1.txt
 1 file changed, 1 insertion(+)

# 怒られるけど、なんだかんだpushは許してくれる
$ git push
warning: push.default is unset; its implicit value has changed in
Git 2.0 from 'matching' to 'simple'. To squelch this message
and maintain the traditional behavior, use:

  git config --global push.default matching

To squelch this message and adopt the new behavior now, use:

  git config --global push.default simple

When push.default is set to 'matching', git will push local branches
to the remote branches that already exist with the same name.

Since Git 2.0, Git defaults to the more conservative 'simple'
behavior, which only pushes the current branch to the corresponding
remote branch that 'git pull' uses to update the current branch.

See 'git help config' and search for 'push.default' for further information.
(the 'simple' mode was introduced in Git 1.7.11. Use the similar mode
'current' instead of 'simple' if you sometimes use older versions of Git)

Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 259 bytes | 0 bytes/s, done.
Total 3 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
To https://github.com/kanairen/Hoge
   5bf5762..6c13eb5  master -> master

なんだかとてつもなく怒られてるような気がしないでもないですが、
とりあえずpushはできました。

git push時の説明を見てみると、

注意:push.defaultが未設定だよ。
Git2.0だとちゃっかりデフォルト設定が'matching'から'simple'に変わっちゃってるよ。
このうざいメッセージを表示させないようにするには、デフォルト設定を

git config --global push.default matching

で変えてね。

新しいデフォルト設定にあわせるなら

  git config --global push.default simple

してね。

push.defaultを'matching'に変えると、gitはローカルにある全ブランチを同じ名前のリモートブランチにpushしちゃうよ。

Git2.0からデフォルトになったもっと安全な'simple'は、デフォルトの`git pull`を使った更新のように、
現在のローカルブランチにアップストリームとして設定されている同名のブランチにのみpushするよ。

push.defaultについてもっと知りたかったら、`git help config`を見てpush.defaultを探してみてね。
('simple'モードはGit1.7.11から公開されたんだ。もし古いGitを使ってたら、似たモードの'current'を代わりに使ってね)

(アップストリームについてはこちら

この説明から、

  • git pushのデフォルト操作はgit push.defaultの設定で決まる
  • git push.defaultの設定は複数存在する

ことがわかりました。

git push.defaultの種類

push.defaultについてもっと知りたかったら、git help configを見てpush.defaultを探してみてね。

言われたとおりに探してみました。

$ git help config

# ----ここから lessコマンド のようにスクロールするヘルプ出現----

GIT-CONFIG(1)                                    Git Manual                                   GIT-CONFIG(1)

NAME
       git-config - Get and set repository or global options

# ...
# さまざまなhelp項目
# ...

push.default
           Defines the action git push should take if no refspec is explicitly given. Different values are
           well-suited for specific workflows; for instance, in a purely central workflow (i.e. the fetch
           source is equal to the push destination), upstream is probably what you want. Possible values
           are:

           o   nothing - do not push anything (error out) unless a refspec is explicitly given. This is
               primarily meant for people who want to avoid mistakes by always being explicit.

           o   current - push the current branch to update a branch with the same name on the receiving
               end. Works in both central and non-central workflows.

           o   upstream - push the current branch back to the branch whose changes are usually integrated
               into the current branch (which is called @{upstream}). This mode only makes sense if you are
               pushing to the same repository you would normally pull from (i.e. central workflow).

           o   simple - in centralized workflow, work like upstream with an added safety to refuse to push
               if the upstream branch's name is different from the local one.

               When pushing to a remote that is different from the remote you normally pull from, work as
               current. This is the safest option and is suited for beginners.

               This mode has become the default in Git 2.0.

           o   matching - push all branches having the same name on both ends. This makes the repository
               you are pushing to remember the set of branches that will be pushed out (e.g. if you always
               push maint and master there and no other branches, the repository you push to will have
               these two branches, and your local maint and master will be pushed there).

               To use this mode effectively, you have to make sure all the branches you would push out are
               ready to be pushed out before running git push, as the whole point of this mode is to allow
               you to push all of the branches in one go. If you usually finish work on only one branch and
               push out the result, while other branches are unfinished, this mode is not for you. Also
               this mode is not suitable for pushing into a shared central repository, as other people may
               add new branches there, or update the tip of existing branches outside your control.

               This used to be the default, but not since Git 2.0 (simple is the new default).

ありました。が、全文訳す気力はないのでかいつまんでまとめます。

nothing

明示的なブランチ名の指定がなければgit pushが実行されない。
すなわち、デフォルトgit pushが使えなくなります。

current

現在いるローカルブランチと同名のリモートブランチへpushする。

upstream

現在いるローカルブランチに指定されているアップストリームへpushする。

simple

current + upstream。現在いるローカルブランチと同名、かつアップストリームとして指定されているリモートブランチへpushする。

matching

ローカルにある各ブランチを同名のリモートブランチにpushする。

git push.default のデフォルト値

すでに上の警告文内にも出ていましたが、

  • Git2.0以前であれば、git push.defaultmatching
  • Git2.0以降であれば、git push.defaultsimple

だったんですね。

ちなみに自分が使っていたGitのバージョンは2.7.4でした。
デフォルトのgit pushを確かめてみたところ、確かに現在いるローカルブランチしかpushされないsimpleでした。

$ git --version
git version 2.7.4 (Apple Git-66)
hub version 2.2.3

# masterで変更(出力省略)
$ echo "piyo" >> hoge1.txt           
$ git commit -a -m "modify hoge1.txt"

# branch1で変更(出力省略)
$ git checkout branch1
$ echo "piyo" >> hoge1.txt 
$ git commit -a -m "modify hoge1.txt" 

# branch2で変更(出力省略)
$ git checkout branch2 
$ echo "piyo" >> hoge1.txt 
$ git commit -a -m "modify hoge1.txt" 

$ git push
warning: push.default is unset; its implicit value has changed in
...
#
# 警告文省略
#

Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 268 bytes | 0 bytes/s, done.
Total 3 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
To https://github.com/kanairen/Hoge
   f5a2b8c..6add3e3  branch2 -> branch2