繁体   English   中英

如何分解git pull <REMOTE><BRANCH> 到获取+合并?

[英]How to decompose git pull <REMOTE> <BRANCH> into a fetch + merge?

注意:此问题的动机是更好地理解git ,而不是解决任何特定问题。 IOW,“达成相同目标”的替代方法(即回避标题中的问题)将不重要。

命令

git pull

...应该等同于序列

git fetch
git merge

可以将git pull <REMOTE> <BRANCH> (即具有用于远程对象的明确参数和要从中提取分支的分支)分解为类似的fetch序列,然后进行merge吗?

我认为fetch部分将仅仅是

git fetch <REMOTE> <BRANCH>

...但是,如果是这样,我将无法找出正确的git merge ...


我已经尝试过“显而易见”的事情。 例如,如果我运行git branch -r ,输出在分支之间列出了<REMOTE>/<BRANCH> ,所以我尝试了git merge -m 'some message' <REMOTE>/<BRANCH> ,但是git答复Already up-to-date. git-log显示HEAD保持与尝试git merge之前的提交相同的提交。 为了确认这一点,我将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

从上面的输出中可以看到,

  1. 末尾的获取+合并序列对git log...的输出没有影响git log...
  2. git merge命令的输出Already up-to-date.Already up-to-date. ,即使不是这种情况(远程和本地存储库也已分开一个提交)。
  3. 在此“合并”之后,本地分支( master )是跟踪分支( remrepo/master )之前的一个提交。
  4. 与提取+合并序列相反,即使两组命令都接收到完全相同的信息,拉取也可以做正确的事情(即,它更新跟踪分支并执行合并)。

正如git pull的手册页所说:

将更改从远程存储库合并到当前分支。 在其默认模式下,git pull是git fetch的缩写,其后是git merge FETCH_HEAD。

更精确地讲,git pull使用给定的参数运行git fetch并调用git merge将检索到的分支头合并到当前分支中。 使用--rebase,它将运行git rebase而不是git merge。

基于此(并假设您未使用--rebase ), git pull命令应几乎等同于:

# 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>

从远程引入有关所有引用的信息通常是没有害处的(除非您有一些特定的要求)。 如果可以的话,可以在没有任何refspec的情况下运行第一个git fetch ,即

git fetch <REMOTE>

如果使用--rebase选项,则git merge命令将被以下git rebase命令代替:

git rebase <REMOTE>/<REMOTE_BRANCH_NAME>

PS:与git merge不同, git rebase采用可选的target分支参数。 如果未指定,它将使用当前签出的分支。

感谢kostix指出git fetchlocal-branch:remote-branch语法

我认为问题在于您的玩具示例使用了git fetch <repository> <branch> -仅由分支名称组成的refspec被解释为已获取的远程分支的名称,以及SHA-1的SHA-1名称它的尖端提交被写入.git/FETCH_HEAD文件; 没有任何本地分支被更新,因为refspec错过了“:destination”部分(要用获取的内容更新哪个本地分支)。 因此,基本上您的git fetch可以进行空运行。

请重新阅读git-fetch手册

简短的答案是...

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>

如果这两个不相同,请尝试以下方法。
(如果相同,则您已经是最新的!)

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

如果它仍然说您是最新的,那么也许您本地需要提交,但是这就是为什么您看到不同提交的原因。

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

使用branch:branch格式只是非常具体地说明您要推送的内容的一种方式。 它说推:

现在再次检查那些日志。

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

如果您仍然看到不同的提交-那么您确实有一个极端的情况。 尝试复制您在登录/中获得的提交哈希。 然后直接将其合并到本地分支

git merge <SHA1>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM