git pullに関して思うこと

git pullに関していろいろと調べてみると、あれこれと書かれてるんですが、
正直まどろっこしいというかややこしいというか…。

git-pullは幸い(?)なことにシェルスクリプトなので、
echoを入れてコマンド見れば良いんじゃないかなと思うんです。

ということで、主によく問題とされている以下の2点について調べてみました。

  • git pull origin <branch>:<branch> をやってはいけない理由
  • git pullするとカレントブランチが更新される理由
    • さらに言うと、単純なgit pullだと追跡ブランチも更新される理由(「追跡ブランチ」は後述)

(本記事はgit version 1.9.5 (Apple Git-50.3)をベースとして記述しています)

以下のようなリポジトリ構成の場合、

1$ git branch -a
2  devel
3* master
4  remotes/origin/devel
5  remotes/origin/master

git pullは以下の結果となる。

1$ git pull origin devel:devel
2git fetch     --update-head-ok "origin devel:devel" || exit 1
3git-merge              "$merge_name" HEAD 312fc9f10fc4cba111d72f322d6a71147d34d976
1$ git pull origin
2git fetch     --update-head-ok "origin" || exit 1
3git-merge              "$merge_name" HEAD b909223d2d6094374e86bf32b036ff341ce149d6

git-merge

ここで注目するべきは2箇所。まず1つはgit-mergeの引数。
HEADにあるリビジョンをマージするから、 カレントのブランチにマージされるんです
git-pullのドキュメントにも

More precisely, git pull runs git fetch with the given parameters and calls git merge to merge the retrieved branch heads into the current branch.

となっている。
このことから、リモートブランチをpullすることを期待して、"git pull origin <branch>:<branch>"すると
カレントブランチにマージされてしまいます。
また、上記の事から"git pull"だけだとカレントブランチに対しての更新は、意図通りのものとなります。

git fetch

もう1つはgit fetchの挙動。
git fetchはoriginのみを指定した場合は、originの追跡ブランチをすべて更新し、さらに追跡ブランチに対応するローカルブランチを更新します。
詳細な説明は以下のとおり。

When git fetch is run without specifying what branches and/or tags to fetch on the command line,
e.g. git fetch origin or git fetch, remote.<repository>.fetch values are used as the refspecs---they specify which
refs to fetch and which local refs to update.
The example above will fetch all branches that exist in the origin (i.e. any ref that matches the left-hand side of the value,
refs/heads/) and update the corresponding remote-tracking branches in the refs/remotes/origin/ hierarchy.

git fetchだけを試しにやってみると

1$ git fetch origin
2remote: Counting objects: 3, done.
3remote: Compressing objects: 100% (2/2), done.
4remote: Total 3 (delta 0), reused 3 (delta 0), pack-reused 0
5Unpacking objects: 100% (3/3), done.
6From github.com:yasuharu/test
7   312fc9f..c1f1af3  devel     -> origin/devel

の通り、fetchだけでdevelは更新されます。
このことから、git pullするとカレントブランチ以外の追跡ブランチも更新されることがわかります。

追跡ブランチについて

以下のページが分かりやすかったです。

git pull しても更新されない

git pullしても以下のエラーで更新されない場合、追跡ブランチに登録されていないです。

 1$ git pull
 2There is no tracking information for the current branch.
 3Please specify which branch you want to merge with.
 4See git-pull(1) for details
 5
 6    git pull <remote> <branch>
 7
 8If you wish to set tracking information for this branch you can do so with:
 9
10    git branch --set-upstream-to=origin/<branch> devel

もし、リモートブランチが"origin"の場合、説明の通りにすればOK。

git branch --set-upstream-to=origin/devel devel

git pull時のmergeするリビジョン

リビジョンはgit fetchした後の、.git/FETCH_HEADから取得します。
「not-for-merge以外のもの」(=カレントブランチ)がmergeするリビジョンになります。

1$ git checkout devel
2Switched to branch 'devel'
3$ git fetch origin
4$ cat .git/FETCH_HEAD
5c1f1af3d7f4a02c252effb5ad8cdd390b541fff1                branch 'devel' of github.com:yasuharu/test
6b909223d2d6094374e86bf32b036ff341ce149d6        not-for-merge   branch 'master' of github.com:yasuharu/test
1$ git checkout master
2Switched to branch 'master'
3$ git fetch origin
4$ cat .git/FETCH_HEAD
5b909223d2d6094374e86bf32b036ff341ce149d6                branch 'master' of github.com:yasuharu/test
6c1f1af3d7f4a02c252effb5ad8cdd390b541fff1        not-for-merge   branch 'devel' of github.com:yasuharu/test
Posted at : 2015-11-03 09:46:16 / Category : none

コメント

まだコメントはありません

コメントを投稿


お名前


メールアドレス(返信を通知する場合のみ記入)

認証コード(200526 と記入してください)