git pullは、fetchしてmergeするのと同じなのか?
git

git pullは、fetchしてmergeするのと同じなのか?

このエントリーをはてなブックマークに追加

はじめまして、 はおりん と申します。

phpを食べたり、Androidを食べたり、サーバの面倒を見たり、ギルザットのフォレスドンを狩ったりして毎日を過ごしています。おおむねテンション高めですが、実は寝不足によるミッドナイトハイテンションなのかもしれません。

わたくし、新しい作業branchを作るときに、 git fetch origin してから、
git checkout -b hogehoge origin/master ってやってたんですけど、その後手元のmasterを最新にしたいときに git pull してたんですね。

でも、ふと疑問に思ったんです。

すでにfetchしてあるんだから、手元のorigin/masterからmasterに反映って、できるんじゃね?と。

でもなんか普通に、 git checkout master; git merge origin/master ってやったら、マージコミットが勝手に作られそうで、超面倒だなぁ、って思ってたんです。

で、ちょっと調べてみると、git pullは使わない方が良いとか、fetchとmergeをやっているだけだとか、いろいろネットでは書かれてるじゃないですかー。

でもどれも、git pullはfetchとmergeを両方やってるだけだよ、ほら、証拠はココに。ってがっつり書かれてるサイトって見つけられなかったんですね。

と、いうわけで、本日のエンジニアブログは、 git pullの伝説 です。

伝説を語るだけでなく、真実かを検証するのです。

(ディスカバリーチャンネルの「怪しい伝説」、だいすきです。)

git pullの正体

実は git pull はC言語で実装されていません。git-pull.shというシェルスクリプトです。

CentOSであれば /usr/libexec/git-core/git-pull に配置されています。

guthubでのソースは こちら

256行目まで

256行目までは、現在のhashを取得したり、work treeがcleanかどうかを調べたりしているだけですので、割愛します。

fetchを実行する

257行目で、皆様お待ちかねのfetchを実行しています。

と、ここで、どうやらfetchだけでも作業ツリーのHEADが変わってしまうことがあるようです。

その場合は、

Warning: fetch updated the current branch head.
Warning: fast-forwarding your working tree from
Warning: commit \$orig_head.

というエラーを表示した上で、

git update-index -q --refresh
git read-tree -u -m "$orig_head" "$curr_head"

を実行しています。

このコマンドの内容については、また別の機会にしましょう。

fetchしてくる前のHEADが、無い?

305行目で、orig_headが空だった場合に、

git read-tree -m -u $empty_tree $merge_head &&
git update-ref -m "initial pull" HEAD $merge_head "$curr_head"

を実行してexitしています。

これは、空branchをpullしてきたときのパターンでしょうか・・・

mergeのお時間

さて、ようやくここでmergeのお時間です。

rebaseの場合

rebaseの場合は328行目の中に入っていきます。

git-rebase $diffstat $strategy_args $merge_args $rebase_args $verbosity $gpg_sign_args --onto $merge_head ${oldremoteref:-$merge_head}

というコマンドが実行されるようです。

git-rebaseとは、git rebaseを実行する、実体のシェルスクリプトです。rebaseもC言語ではなくシェスルクリプトで実装されているんですね。

mergeの場合

mergeの場合には333行目の中に入っていきます。

git-merge $diffstat $no_commit $verify_signatures $edit $squash $no_ff $ff_only $log_arg $strategy_args $merge_args $verbosity $progress $gpg_sign_args \"\$merge_name\" HEAD $merge_head

とまぁ、これまたなんとも長いコードが実行されているんですが、なにも引数を付けずにpullを実行すると、

git merge "コミットの文" HEAD 0123456789abcdef0123456789abcdef01234567

というコマンドが実行されるだけなので、シンプルなmergeだと思って良いです。

結論

git pullに、何も引数を付けずに実行した場合、git fetchしてgit mergeするのと同義であると確認できました。

伝説は本当でした。


名無しのエンジニア
ソシオメディア UX戦略フォーラム 2014 Winterに参加しました
あなたのアカマイ大丈夫?