如何预览 git pull?

254

这真的可能吗?

基本上,我只使用以下命令从一个远程代码库中拉取:

git pull

现在,我想预览一下这个拉取会改变什么(即差异),而不在我的端上触碰任何东西。原因是我正在拉取的东西可能不是“好的”,我希望有人在使我的存储库“脏”之前先修复它。


4
你的编辑有点奇怪。执行“git fetch”不会以任何方式更改你的工作树,因此即使你有未提交的本地更改也没有关系。而且不清楚你要撤消哪部分的fetch,因为它不会触及你的工作树。 - dkagedal
谢谢dkagedal,我在完全理解Git工作原理之前就写了这个。我已经删除了那个编辑。 - Milan Babuškov
2
每个人(包括OP)都会使用“git fetch”来解决问题。但是如果你逐字逐句地看待这个问题呢?例如,你想出于一些奇怪的原因避免fetch,比如一个写保护的磁盘,或者磁盘空间不足的风险?例如,一个混乱的repo可能会发送给你几GB的数据... - Kjell
我知道这是一个老问题,但标题很令人困惑,特别是“不使用fetch”。我认为在撰写本文时对fetch做出了错误的假设。现在修改问题标题是否有意义?(我建议只需删除“不使用fetch”即可。) - TTT
10个回答

294
在执行了git fetch之后,使用git log HEAD..origin/master来显示你最后一次共同提交与源主分支之间的日志记录条目。要显示差异,可以使用git log -p HEAD..origin/master来显示每个补丁,或者使用git diff HEAD...origin/master(三个点而不是两个)来显示单个差异。
通常情况下,并不需要撤消一个fetch操作,因为fetch只会更新远程分支,而不会更新你自己的分支。如果你不想做pull和合并所有远程提交,请使用git cherry-pick接受你想要的特定远程提交。稍后,当你准备好获取全部内容时,git pull将合并剩余的提交。
更新:我不完全确定为什么你想避免使用git fetch。git fetch所做的只是更新你本地的远程分支副本。这个本地的副本与你的任何分支都没有关系,也与未提交的本地更改无关。我听说有人在cron作业中运行git fetch,因为它非常安全。(尽管我通常不建议这样做。)

我想当初在阅读文档时错过了“与我的分支无关”的那一部分。谢谢。 - Milan Babuškov
1
由于某些原因,这对我不起作用。我尝试使用git diff HEAD...origin/master,但它没有列出任何更改,但是当我执行'pull origin master'时,它会获取和合并更改。这是因为我使用git remote add设置了远程存储库吗? - screenm0nkey
1
在我这里有效的操作(在 git fetch 之后):git log origin/master - slaman
无论是 git diff HEAD...origin 还是 git log -p HEAD..origin 都没有返回任何结果(我知道有更改)。git log origin/master 显示所有提交,包括尚未被拉取的提交。 - Rooster242
2
git diff ...@{u}与如果origin/master是上游分支,则与git diff HEAD...origin/master相同。 - cambunctious
显示剩余8条评论

53

我认为你需要使用 git fetch 命令。

此命令将在不提交到本地仓库索引的情况下拉取更改和对象。

稍后可以使用 git merge 命令合并它们。

手册页面

编辑:进一步解释

直接从 Git-SVN崩溃课程 链接 中引用:

现在,如何从远程存储库获取任何新更改?您可以使用fetch命令:

git fetch http://host.xz/path/to/repo.git/ 

此时它们已经在您的代码库中,您可以使用以下命令查看它们:

git log origin 

您还可以对更改进行差异比较。 您还可以使用git log HEAD..origin仅查看您分支中没有的更改。 然后,如果想合并它们 - 只需执行:

git merge origin

注意,如果您没有指定要获取的分支,它将方便地默认为跟踪远程。

阅读man页实际上会让您最好地了解选项以及如何使用它。

我只是试图通过示例和记忆来做这个,目前没有可用于测试的设备。 您应该查看:

git log -p //log with diff

使用 git reset --hard 命令(链接)可以撤销一个 fetch 操作,但是您树中的所有未提交更改以及您获取的更改都将丢失。


如果您能解释以下两个问题,那就太好了:1. 如何撤销 git-fetch?2. 如何查看差异? - Milan Babuškov
1
  1. 撤销git-fetch?
  2. git diff HEAD..origin
- Chris Vest
差异已经完成,就像Christian所说,通过git reset --hard命令可以撤消fetch操作,但是您的树中所有未提交的更改以及您获取的更改都将丢失。 - Brian Gianforcaro
你是在寻找 git reset --soft 还是 --mixed 呢?请查看手册。 - Aristotle Pagaltzis
1
如果我理解正确的话,那么没有必要撤销“git fetch”,因为它不会影响你的工作副本,也不会影响你的代码库。“git fetch”会将对象和引用存储在.git/FETCH_HEAD中。 - Thorsten Niehues

25
你可以从远程仓库获取代码并查看差异,然后再进行拉取或合并操作。
这是一个关于远程仓库的例子,名为origin,分支名为master,追踪的远程分支名为origin/master
git checkout master                                                  
git fetch                                        
git diff origin/master
git pull --rebase origin master

12

我创建了一个自定义的Git别名来为我执行此操作:

alias.changes=!git log --name-status HEAD..

通过这个,你可以做到这一点:

$git fetch
$git changes origin

这将为您提供在执行merge之前预览更改的简单有效方法。


5
我可能有些晚了,但这是我长期以来一直感到困扰的问题。从我的经验来看,我宁愿想要看到哪些更改正在等待处理,而不是更新我的工作副本并处理这些更改。
这些内容需要添加到~/.gitconfig文件中:
[alias]
    diffpull = !git fetch && git diff HEAD..@{u}

它获取当前分支,然后在工作副本和此获取的分支之间进行差异比较。因此,您应该只能看到使用git pull会出现的更改。

1
这是一个很好的别名,但我不确定你为什么要一开始就这样做。你迟早都得处理这些变化,对吧?如果你不喜欢git pull正在做的事情,你应该能够中止合并部分...所以我不确定这个用例是什么。 - Marnen Laibow-Koser
我知道我必须在某个时候处理这些变化,但有时我不想。我只想知道是否会出现问题,我是否需要为此保留更多时间 - 或者我之后是否可以只做一个 git pull。我认为这就是提问者的问题所在。 - Andy P

4
我使用这两个命令,就可以看到要更改的文件。
第一步执行git fetch,它会输出如下内容(部分输出):
...
72f8433..c8af041  develop -> origin/develop
...
此操作将给我们两个提交ID,第一个是旧的,第二个是新的。
然后使用git diff比较这两个提交:
git diff 72f8433..c8af041 | grep "diff --git"
此命令将列出将要更新的文件。
diff --git a/app/controller/xxxx.php b/app/controller/xxxx.php
diff --git a/app/view/yyyy.php b/app/view/yyyy.php

例如,app/controller/xxxx.phpapp/view/yyyy.php将被更新。
使用git diff比较两个提交时,会打印所有更新的文件及其更改的行,但使用grep搜索并仅获取包含输出中的diff --git的行。

2
我从https://gist.github.com/jtdp/5443297链接中挑选了以下有用的命令。感谢https://gist.github.com/jtdp
git fetch origin

# show commit logs of changes
git log master..origin/master

# show diffs of changes
git diff master..origin/master

# apply the changes by merge..
git merge origin/master

# .. or just pull the changes
git pull

1

13年后,您现在有了一个prefetch任务,在 "git maintenance"(man) 中。

预取任务会从所有注册的远程仓库中更新对象目录。
对于每个远程仓库,会运行git fetch命令。
引用映射是自定义的,以避免更新本地或远程分支(位于refs/headsrefs/remotes)。
相反,远程分支存储在refs/prefetch/<remote>/中。
同时,标签不会被更新。
这样做是为了避免破坏远程跟踪分支。
最终用户期望这些参考保持不变,除非他们启动获取操作。
使用预取任务,完成稍后真实获取所需的对象已经被获取,因此真实获取将更快进行。
在理想情况下,它只会成为一堆远程跟踪分支的更新,没有任何对象传输。
自Git 2.32(2021年第二季度)起,您还可以使用git fetch --prefetch执行上述操作,而无需修改上次提取的状态。

请查看 提交 32f6788, 提交 cfd781e, 提交 2e03115 (2021年4月16日),以及 提交 a039a1f (2021年4月6日) 由 Derrick Stolee (derrickstolee) 提交。
(由 Junio C Hamano -- gitster -- 合并于 提交 d250f90,2021年4月30日)

fetch:添加--prefetch选项

协助者:Tom Saeger
协助者:Ramsay Jones
已签署:Derrick Stolee

--prefetch选项将由“预取”维护任务使用,而不是通过命令行显式发送refspecs。
目的是修改refspec以将所有结果放置在refs/prefetch/中,而不是其他任何地方。

创建辅助方法filter_prefetch_refspec()来修改给定的refspec以适应预取任务所期望的规则:

  • 负refspecs保留。
  • 没有目标的refspecs被删除。
  • 源以"refs/tags/"开头的refspecs被删除。
  • 其他refspecs被放置在"refs/prefetch/"中。

最后,我们添加“force”选项,以确保必要时替换预取引用。

有一些值得测试的有趣情况。

此更改的早期版本从循环中删除了一个refspec项并将剩余条目向下移动的"i--"。
这允许某些refspecs不被修改。
关于第一个--prefetch测试的微妙之处在于,refs/tags/* refspec直接出现在refs/heads/bogus/* refspec之前。
如果没有那个"i--",这个顺序将删除"refs/tags/*" refspec并使最后一个未修改,将结果放置在"refs/heads/*"中。

可能会有一个空的refspec。
这通常是针对不同于origin的远程主机的情况,用户想要获取特定的标签或分支。
为了正确测试这种情况,我们需要进一步删除本地分支的上游远程主机。
因此,我们正在测试将被删除的refspec,不留下任何内容可供提取。

fetch-options现在在其手册页面中包含以下内容:

--prefetch

修改配置的refspec,将所有引用放置在refs/prefetch/命名空间中。


0
如果您不想让 git-fetch 更新本地的 .git,只需将本地存储库复制到临时目录并在那里进行 pull。这是一个简写:
$ alias gtp="tar -c . | (cd /tmp && mkdir tp && cd tp && tar -x && git pull; rm -rf /tmp/tp)"

Ex.:

$ git status
# On branch master
nothing to commit (working directory clean)

$ gtp
remote: Finding sources: 100% (25/25)
remote: Total 25 (delta 10), reused 25 (delta 10)
Unpacking objects: 100% (25/25), done.
From ssh://my.git.domain/reapO
   32d61dc..05287d6  master     -> origin/master
Updating 32d61dc..05287d6
Fast-forward
 subdir/some.file       |    2 +-
 .../somepath/by.tes    |    3 ++-
 .../somepath/data      |   11 +++++++++++
 3 files changed, 14 insertions(+), 2 deletions(-)

$ git status
# On branch master
nothing to commit (working directory clean)

$ git fetch
remote: Finding sources: 100% (25/25)
remote: Total 25 (delta 10), reused 25 (delta 10)
Unpacking objects: 100% (25/25), done.
From ssh://my.git.domain/reapO
   32d61dc..05287d6  master     -> origin/master

$ git status
# On branch master
# Your branch is behind 'origin/master' by 3 commits, and can be fast-forwarded.
#
nothing to commit (working directory clean)

“gtp” 需要在本地仓库的根目录下执行,即 .git 所在的位置。 - AXE Labs

-3

将存储库克隆到其他位置,然后在实际检出和新克隆上执行git log,以查看是否获得了相同的内容。


本地副本比另一个克隆更能反映状态。请参阅我的主要帖子以获取详细信息 - AXE Labs

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