4

注:この質問の動機は、理解を深めることgitであり、特定の問題を解決することではありません。IOW、「同じことを達成する」ための別の方法(つまり、タイトルの質問を回避する)は要点から外れます。

コマンド

git pull

...シーケンスと同等であると想定されています

git fetch
git merge

(つまり、リモートとそこからプルするブランチの明示的な引数を使用して)は、に続く?git pull <REMOTE> <BRANCH>の同様のシーケンスに分解できます。fetchmerge

fetchその部分は単純だと思います

git fetch <REMOTE> <BRANCH>

...しかし、もしそうなら、私はそれに続く正しいことがわかりませんgit merge ....


私は「明らかな」ことを試しました。たとえば、 を実行すると、ブランチ間のgit branch -r出力リストが表示されるので、 を試しましたが、 で応答し、 を試行する前と同じコミットのままであることを示しています。これを確認するために、次のようにandを への呼び出しで囲みました。<REMOTE>/<BRANCH>git merge -m 'some message' <REMOTE>/<BRANCH>gitAlready up-to-date.git-logHEADgit mergegit fetch ...git merge ...git log ...

git log --all --oneline --graph --decorate -10
git fetch <REMOTE> <BRANCH>
git merge -m 'some message' <REMOTE>/<BRANCH>
git log --all --oneline --graph --decorate -10

への 2 つの呼び出しによって生成される出力git log ...同一であり、どちらもローカル<BRANCH>が より進んでいることを示してい<REMOTE>/<BRANCH>ます。


次のおもちゃの例は、/bin/shスクリプトの形式で、上で説明した結果を再現しています。(スクリプトは Ubuntu Linux; YMMV でテストされました。)

#!/bin/sh

BASEDIR=/tmp/gittest
REMOTENAME=remrepo
REMOTEURL="$BASEDIR/$REMOTENAME"
BRANCHNAME=test
BRANCHNAME=master

rm -rf $REMOTEURL
mkdir -p $REMOTEURL

rm -rf $BASEDIR/clone1 $BASEDIR/clone2

git init --bare -q $REMOTEURL/.git
git clone -q -o $REMOTENAME $REMOTEURL $BASEDIR/clone1
git clone -q -o $REMOTENAME $REMOTEURL $BASEDIR/clone2

pushd $BASEDIR/clone1 >/dev/null
git checkout -qb $BRANCHNAME
echo $RANDOM >> random1.txt
git add .
git commit -qam "$(date -Ins)"
git push -q $REMOTENAME $BRANCHNAME

pushd $BASEDIR/clone2 >/dev/null
git pull -q $REMOTENAME
git checkout -q $BRANCHNAME
echo $RANDOM >> random2.txt
git add .
git commit -qam "$(date -Ins)"
git push -q $REMOTENAME $BRANCHNAME

echo
echo 'git log --all --oneline --decorate --graph :'
git log --all --oneline --decorate --graph
echo

pushd >/dev/null
git checkout -q $BRANCHNAME
echo $RANDOM >> random1.txt
git commit -qam "$(date -Ins)"

echo 'git log --all --oneline --decorate --graph :'
git log --all --oneline --decorate --graph
echo

git fetch -q $REMOTENAME $BRANCHNAME
git merge -m "$(date -Ins)" $REMOTENAME/$BRANCHNAME

echo
echo 'git log --all --oneline --decorate --graph :'
git log --all --oneline --decorate --graph

git pull -q --no-edit $REMOTENAME $BRANCHNAME

echo
echo 'git log --all --oneline --decorate --graph :'
git log --all --oneline --decorate --graph

実行すると、出力は次のようになります。

warning: You appear to have cloned an empty repository.
warning: You appear to have cloned an empty repository.

git log --all --oneline --decorate --graph :
* 2326793 (HEAD, remrepo/master, master) 2013-03-19T10:56:42,838038000-0400
* 34ea848 2013-03-19T10:56:42,360743000-0400

git log --all --oneline --decorate --graph :
* 81cb43f (HEAD, master) 2013-03-19T10:56:43,057198000-0400
* 34ea848 (remrepo/master) 2013-03-19T10:56:42,360743000-0400

Already up-to-date.

git log --all --oneline --decorate --graph :
* 81cb43f (HEAD, master) 2013-03-19T10:56:43,057198000-0400
* 34ea848 (remrepo/master) 2013-03-19T10:56:42,360743000-0400

git log --all --oneline --decorate --graph :
*   e60b993 (HEAD, master) Merge branch 'master' of /tmp/gittest/remrepo
|\
| * 2326793 2013-03-19T10:56:42,838038000-0400
* | 81cb43f 2013-03-19T10:56:43,057198000-0400
|/
* 34ea848 (remrepo/master) 2013-03-19T10:56:42,360743000-0400

上記の出力からわかるように、

  1. 最後のフェッチ + マージ シーケンスは、の出力には影響しません。git log...
  2. git mergeコマンドの出力はですがAlready up-to-date.、そうではありません (リモートリポジトリとローカルリポジトリはそれぞれ 1 つのコミットで分岐しています)。
  3. この「マージ」の後、ローカル ブランチ ( master) はトラッキング ブランチ ( remrepo/master) より 1 つコミットが進んでいます。
  4. フェッチ + マージ シーケンスとは対照的に、両方のコマンド セットがまったく同じ情報を受け取ったとしても、プルは正しいことを行います (つまり、トラッキング ブランチを更新し、マージを実行します)。
4

3 に答える 3

1

のマニュアルページにあるようにgit pull

リモート リポジトリからの変更を現在のブランチに組み込みます。デフォルトモードでは、git pull は git fetch の略で、その後に git merge FETCH_HEAD が続きます。

より正確には、git pull は指定されたパラメーターで git fetch を実行し、git merge を呼び出して、取得したブランチ ヘッドを現在のブランチにマージします。--rebase を指定すると、git merge の代わりに git rebase が実行されます。

それに基づいて (そして を使用していないと仮定して--rebase)、git pullcommand は次とほぼ同等である必要があります。

# Fetch the info about the branch from the remote
git fetch <REMOTE> <BRANCH>:<REMOTE>/<BRANCH>

# Switches your working copy to the branch that you would like the
# changes to be merged into
git checkout <LOCAL_BRANCH_NAME>

# Merge the changes from <REMOTE>/<REMOTE_BRANCH_NAME> into your
# currently checked out branch which should <LOCAL_BRANCH_NAME>
# after the previous checkout command
git merge <REMOTE>/<REMOTE_BRANCH_NAME>

通常、リモートからすべての参照に関する情報を持ち込んでも害はありません (そうしないという特定の要件がない限り)。それでよろしければ、最初のgit fetchものは refspec なしで実行できます。

git fetch <REMOTE>

--rebaseこのオプションを使用した場合、コマンドは次のコマンドgit mergeに置き換えられます。git rebase

git rebase <REMOTE>/<REMOTE_BRANCH_NAME>

PS: とは異なりgit mergegit rebaseオプションのターゲット ブランチ引数も受け取ります。指定しない場合は、現在チェックアウトされているブランチが使用されます。

local-branch:remote-branchの構文を指摘してくれたkostixに感謝しますgit fetch

于 2013-03-18T19:14:28.123 に答える
1

問題は、おもちゃの例が使用していることだと思いますgit fetch <repository> <branch>-ブランチ名のみで構成されるrefspecは、フェッチされるリモート上のブランチの名前として解釈され、そのヒントコミットのSHA-1名がファイルに書き込まれ.git/FETCH_HEADます; refspec が「:destination」の部分 (フェッチされたもので更新するローカル ブランチ) を欠いているため、ローカル ブランチは更新されません。したがって、基本的に git fetch は予行演習を行います。

git-fetch manualを読み直してください。

于 2013-03-19T14:31:07.230 に答える
0

簡単な答えは...

git pull <remote> <branch>

機能的には次のものと同等です。

git fetch <remote>
git merge <remote>/<remote_branch>

すべてが最新であるという応答を受け取っている場合は、実行していないか、git fetch <remote>実際に最新の状態になっています。


編集:別の回答に関するコメントのいくつかを読んだ後、コマンドを実行したように聞こえますがgit merge <remote>/<branch>、それらが異なるコミットにあることを確認したにもかかわらず、更新を取得していません。これらの手順を試してください (繰り返しになる可能性がありますが、試してみてください)。

git log -1 <local_branch>
git log -1 <remote>/<remote_branch>

これらの 2 つが同じでない場合は、次の手順を試してください。
(同じであれば、すでに最新です!)

git checkout <local_branch>
git merge <remote>/<remote_branch>

それでも最新の状態であると表示される場合は、プッシュする必要のあるコミットがローカルにある可能性があります。これが、別のコミットが表示されている理由かもしれません。

git push <remote> <local_branch>:<remote_branch>

branch:branch 形式を使用することは、何をプッシュしようとしているのかを非常に具体的に示す方法にすぎません。それは言う push :

これらのログをもう一度確認してください..

git log -1 <local_branch>
git log -1 <remote>/<remote_branch>

それでも別のコミットが表示される場合は、確かにエッジ ケースがあります。/.log で取得したコミット ハッシュをコピーしてみてください。次に、ローカルブランチに直接マージします

git merge <SHA1>
于 2013-03-19T00:04:32.920 に答える