如何将git pull分解为fetch merge?

注意:这个问题的动机是更好地理解git,而不是解决任何特定问题. IOW,“实现同样的事情”的替代方式(即在标题中侧面提出问题)将是不重要的.

命令

git pull

……应该等同于序列

git fetch
git merge

git pull< REMOTE> < BRANCH> (即使用远程的显式参数和从中拉出的分支)被分解为类似的fetch后续合并序列?

我想这个获取部分很简单

git fetch <REMOTE> <BRANCH>

…但是,如果是这样,我无法弄清楚正确的git合并……跟随它.

我尝试过“明显”的事情.例如,如果我运行git branch -r,则输出列表< REMOTE> /< BRANCH>在分支机构之间,所以我尝试了git merge -m’some message’< REMOTE> /< BRANCH>,但git回复时已经是最新的.,git-log显示HEAD保持在同一个提交它是在尝试git合并之前.为了确认这一点,我将git 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

两次调用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

从上面的输出可以看出,

>接近结束的提取合并序列对git log的输出没有影响…
> git merge命令的输出已经是最新的.即使不是这种情况(远程和本地存储库已经分别进行了一次提交).
>在此“合并”之后,本地分支(主)是跟踪分支(remrepo / master)之前的一个提交.
>与获取合并序列相反,即使两组命令都收到完全相同的信息,拉动也是正确的(即它更新跟踪分支并执行合并).

最佳答案 我认为问题是你的玩具示例使用git fetch< repository> <分支> –

仅由分支名称组成的refspec被解释为远程的分支名称,该分支被提取,其提示提交的SHA-1名称被写入.git / FETCH_HEAD文件;没有本地分支更新,因为refspec错过了“:destination”部分(要使用所提取内容更新的本地分支).所以基本上你的git fetch干涸了.

请重新阅读the git-fetch manual.

点赞