注意:此问题的动机是更好地理解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.
,{{1 }}表示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>
脚本的形式再现了我上面描述的结果。 (该脚本在Ubuntu Linux上进行了测试; YMMV。)
/bin/sh
如果您运行它,输出将类似于以下内容:
#!/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
,即使不是这种情况(远程和本地存储库已经分别进行了一次提交)。Already up-to-date.
)是跟踪分支(master
)之前的一次提交。答案 0 :(得分:1)
正如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
也采用可选的目标分支参数。如果您没有指定,它将使用当前签出的分支。
感谢kostix指向git fetch
local-branch:remote-branch
语法
答案 1 :(得分:1)
我认为问题在于您的玩具示例使用git fetch <repository> <branch>
-
仅由分支名称组成的 refspec 被解释为远程的分支名称,该分支被提取,其提示提交的SHA-1名称被写入.git/FETCH_HEAD
文件;没有本地分支更新,因为refspec错过了“:destination”部分(要使用所提取内容更新的本地分支)。所以基本上你的git fetch干涸了。
请重新阅读the git-fetch manual。
答案 2 :(得分: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>
如果这两者不相同,请尝试以下方法 (如果相同,那么你已经是最新的!)
git checkout <local_branch>
git merge <remote>/<remote_branch>
如果它仍然说你是最新的,那么也许你本地有提交你需要推高,也许这就是为什么你看到不同的提交。
git push <remote> <local_branch>:<remote_branch>
使用分支:分支格式只是对您尝试推送的内容非常具体的一种方式。它说推:
现在再次检查这些日志..
git log -1 <local_branch>
git log -1 <remote>/<remote_branch>
如果你仍然看到一个不同的提交 - 那么你确实有一个边缘案例。尝试复制您为登录/获取的提交哈希。然后直接将其合并到您的本地分支
git merge <SHA1>