如何在非当前分支中执行'git pull'操作?

171
当你在master分支上运行git pull时,通常会从origin/master拉取。我现在在另一个名为newbranch的分支中,但我需要运行一个命令,它可以将origin/master中的内容拉取到master中,但在拉取完成之前我不能运行git checkout来改变选择的分支。是否有方法可以解决这个问题?
背景介绍一下,该代码库存储了一个网站。我在newbranch中进行了一些更改,并通过将网站切换到newbranch来部署了这些更改。现在这些更改已经合并到了master分支中,我也尝试将网站切换回master分支。此时,newbranchorigin/master是相同的,但master落后于origin/master,需要更新。问题是,如果按照传统的方式操作:
$ git checkout master
   # Uh oh, production website has now reverted back to old version in master
$ git pull
   # Website is now up to date again

我需要实现与上述相同的目标 (git checkout master && git pull),但在此过程中不更改工作目录到早期版本。


@phi:我认为这不会起作用,因为我在newbranch中,那里没有需要stash的东西! - Malvineous
@aet 他现在可以通过在“newbranch”中执行“git fetch; git merge origin/master”来完成当前目录中的操作。克隆整个仓库副本没有任何好处。 - user229044
上游已经在master上进行了快进合并,因此newbranchmaster已经相同。问题是我不能切换到master分支,而不需要回退十几个提交(失去工作目录中的许多文件),然后执行git pull(将事物恢复到它们现在的状态)。 - Malvineous
3
好的,我会尽力为您翻译。以下是需要翻译的内容:closely related: https://dev59.com/u3A75IYBdhLWcg3wlqET - Ciro Santilli OurBigBook.com
显示剩余3条评论
8个回答

208

简单明了:从一个远程分支更新到当前未检出的分支 master:

git fetch origin master:master

假设您当前已经在某个分支(例如dev),并且origin是您的远程副本。如果您想同时更新当前分支和指定的分支:

git pull origin master:master

6
嗯,看起来它并不总是有效;我刚刚被提示合并我的WIP分支。 - underscore_d
@underscore_d 我也是。 - Greg
1
对我有效...如果它提示合并,那么我想你正在更新的分支中有未提交到源的更改。 - skim
2
这个应该怎么工作?对我来说它不起作用,它只是尝试将 origin/master 合并到我当前检出的分支中。 - mhogerheijde
4
这会将主分支合并到当前分支。这绝对不是所要求的操作。如果您将“pull”更改为“fetch”,那么这就是所需的操作。 - Jeff Wolski
无论如何,git fetch origin master:master都会将本地的master分支覆盖为远程版本吗?还是有一种保护机制,如果变更不是快进方式,会阻止你这样做? - pqnet

107

这里已经回答了这个问题:合并、更新和拉取 Git 分支而无需使用检出

# Merge local branch foo into local branch master,
# without having to checkout master first.
# Here `.` means to use the local repository as the "remote":
git fetch . foo:master

# Merge remote branch origin/foo into local branch foo,
# without having to checkout foo first:
git fetch origin foo:foo

3
这是最好的选择,因为它可以与未提交的本地更改一起使用。 - Tomasz Gandor
3
如果你只是想追踪最新的更改,可以执行 git fetch origin master:master。仅执行 git fetch 会默认更新当前分支而不是其他分支。 - John Leidegren
3
这是最简单直接的答案,我认为这应该是被采纳的答案。 - Keego
@JohnLeidegren - 但它并不总是按预期工作。请参见 https://dev59.com/4WMk5IYBdhLWcg3wxAhM#42902058 答案的评论。 - ysap
如果你想像 git pull 一样从源头获取所有内容,你可以执行 git fetch; git fetch origin foo:foo。但是有没有更好的方法呢? - undefined

24

事实证明,答案出奇的简单:

$ git fetch                           # Update without changing any files
$ git branch -d master                # Remove out-of-date 'master' branch
$ git checkout --track origin/master  # Create and check out up-to-date 'master' branch

这允许您在更新master分支之前不必切换到它,直到在更新后。


12
这不是你要求的操作。 - jthill
正如上面的评论所说,你最终提出的问题并不是你最终得到答案的问题。你应该更新你的问题,使其不再仅仅关于在没有检出分支的情况下合并,而更多地关于直接移动到远程可用的分支的最新版本,而无需先检出旧版本。 - user229044
1
这绝对是我在这里寻找的答案 :) - Sophistifunk
1
不是 OP 想要的,但老实说帮了我很多。 - Marcel Bro
1
@anoniim,不是OP想要的吗?你是指刚回答这个问题的那个OP吗? - smac89
显示剩余3条评论

12
你正在担心一个无法解决的问题,因为Git操作不是原子性的。即使你在更新主分支(master)之前没有切换到它,你的工作目录仍然会处于两个分支之间的“半路状态”。这就是为什么Git不是部署工具的原因。
既然你实际上并没有在生产环境中提交代码(希望如此),那么你实际上也不需要检出一个分支。你只需要执行`git fetch`命令来更新远程引用,然后执行`git checkout origin/master`命令将工作目录直接移动到由`origin/master`指向的提交。这将使你处于“游离头指针(detached head)”的状态,但是,由于你并没有提交代码,所以这并不重要。
这是你可能会遇到的最小问题,但正如我所说,仍然存在一个问题;`checkout`操作并不是原子的。

我理解使用git进行部署的限制,问题在于这种情况下的漏洞将会持续几分钟而不是不到一秒钟。不过检出origin/master的想法不错,这可能会奏效。 - Malvineous
什么导致“分钟”这条线路很慢?是网络传输数据的缘故吗?在开始任何操作之前,只需执行“git fetch”以将实际的数据传输完成。 - user229044
它需要几分钟,因为一个(现在)未被跟踪的文件将被之前的提交覆盖。 所以我必须复制该文件,执行git操作,然后再把它放回去。 "几分钟"源于我的打字速度。(是的,我可以编写脚本,但这只是为了证明让git自己完成所有操作更快。 ) - Malvineous

4

git fetch origin master:master

  • “拉取”(实际上是获取)master
  • 如果你的 master 上有未推送的更改,origin/master 将合并到你的master中。
  • 如果有合并冲突,你需要先解决它们。

4
您可以使用update-ref来实现此操作:
git fetch
git update-ref refs/heads/master origin/master
git checkout master

请注意,这将丢弃主分支中的任何本地提交。在您的情况下,不会有任何提交,所以这是可以的。对于其他想要执行此操作但存在本地提交的人来说,我认为这是不可能的,因为合并只能在当前分支上运行。

这是否等同于 git branch --force master origin/master?这将强制本地的 master 分支指向 originmaster 分支头。 - Keego

3

如果您不想触碰某个工作树,请使用另一个工作树。克隆是便宜的,它专门用于此。

git fetch origin master       # nice linear tree
git clone . ../wip -b master  # wip's `origin/master` is my `master`
cd ../wip                     # .
git pull origin origin/master # merge origin's origin/master
git push origin master        # job's done, turn it in.
cd ../main
rm -rf ../wip                 # wip was pushed here, wip's done

git checkout master           # payload

这里其他答案的问题是,它们实际上并没有执行拉取操作。如果您需要合并或变基,您需要另一个工作树和上述过程。否则,只需要git fetch; git checkout -B master origin/master就可以了。


2
当你运行 git checkout master 时,你将会检出旧的 master 分支,因为你还没有在 main 文件夹中执行 git pull 命令来将其与 origin/master 同步。这就是我试图避免的。 - Malvineous
克隆完成的检出是旧主机的,但该检出是进入Web服务器未查看的目录。最后的主要检出是完全合并的主要检出,这是从wip推回的。 - jthill
当我在第5行尝试它时,我遇到了错误 fatal: 'origin/wip' does not appear to be a git repository 但是我意识到了我的误解。当你推送到origin时,你是在将其推送到main中的存储库 - 我以为你是在推送到main的源,忘记了git clone不是完全相同的副本,上游分支是不同的。所以我明白你所做的事情是从外部推送到目标分支,而不是拉取到目标分支。 - Malvineous
没错,当时我应该说抱歉我的脚本出现了错误,同时感谢你的纠正和耐心等待。 - jthill
1
@jwg 相对于什么,请问?请确保满足所有原帖作者所需求的内容。 - jthill
显示剩余3条评论

2
Malvineous的解决方案对我有用。
$ git fetch                           # Update without changing any files
$ git branch -d master                # Remove out-of-date 'master' branch
$ git checkout --track origin/master  # Create and check out up-to-date 'master' branch

只是出现了错误


warning: not deleting branch 'master' that is not yet merged to
         'refs/remotes/origin/master', even though it is merged to HEAD.
error: The branch 'master' is not fully merged.
If you are sure you want to delete it, run 'git branch -D master'.

所以我使用-D选项运行。
谢谢。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接