我知道“git pull”实际上是“git fetch”和“git merge”的组合,基本上它将存储库与远程存储库中的存储库相结合。
答案 0 :(得分:4)
完全部分真的很难。它经常被说 - 而且大部分都是正确的 - git pull
运行git fetch
后跟git merge
或git rebase
,事实上,{git fetch
1}},曾经是一个shell脚本,现在是一个C程序,首先运行git fetch
,但现在它直接调用实现git fetch
的C代码。
然而,下一步非常棘手。此外,在评论中,您添加了以下内容:
[fetch]从远程仓库中获取更改。它把它们放在哪里?
要正确理解这一点,你必须了解Git的对象系统。
git fetch
每次提交都是一种独立的实体。每个提交都有一个唯一的哈希ID:b06d364...
或其他。该哈希ID是该提交内容的加密校验和。例如,考虑一下:
$ git cat-file -p HEAD | sed 's/@/ /g'
tree a15b54eb544033f8c1ad04dd0a5278a59cc36cc9
parent 951ea7656ebb3f30e6c5e941e625a1318ac58298
author Junio C Hamano <gitster pobox.com> 1494339962 +0900
committer Junio C Hamano <gitster pobox.com> 1494339962 +0900
Git 2.13
Signed-off-by: Junio C Hamano <gitster pobox.com>
如果您将这些内容(减去's/@/ /'
部分,但Git添加到每个对象的标头)提供给SHA-1校验和计算器,您将获得哈希ID。这意味着拥有此提交的所有人都具有相同的哈希ID。
您可以获取Git的Git存储库并运行git cat-file -p v2.13.0^{commit}
以查看相同的数据。注意:标记v2.13.0
会转换为074ffb61b4b507b3bde7dcf6006e5660a0430860
,这是一个标记对象;标记对象本身是指提交b06d364...
:
$ git cat-file -p v2.13.0
object b06d3643105c8758ed019125a4399cb7efdcce2c
type commit
tag v2.13.0
[snip]
要使用提交,Git必须存储提交对象 - 具有哈希标识b06d364...
的项目 - 本身,以及其tree
对象和tree
的任何其他对象需要。这些是您在objects
或git fetch
期间看到Git计数和压缩的git push
。
parent
行告诉哪个提交(或者,对于合并,提交,复数)是此特定提交的前任。要拥有一组完整的提交,Git必须还拥有父提交(--shallow
克隆可以故意省略各种父母,其ID记录在&#的特殊文件中34;浅层移植物&#34;,但正常的克隆将始终拥有一切)。
总共有四种类型的对象:提交,(注释)标记,树和Git调用 blob 对象。 Blob主要存储实际文件。所有这些对象都驻留在Git的对象数据库中。然后,Git可以通过哈希ID轻松检索它们:git cat-file -p <hash>
,例如,以模糊的人类可读格式显示它们。 (除了解压缩之外,大部分时间都没有什么必须完成的,尽管树对象具有必须首先格式化的二进制数据。)
当你运行git fetch
- 或让git pull
为你运行它时 - 你的Git从另一个Git获取一些初始对象的哈希ID,然后使用Git传输协议来找出其他对象需要完成您的Git存储库。如果已经某个对象,则不需要再次获取它,如果该对象是提交对象,则不需要任何父对象。 1 因此,您只获得了您尚未拥有的提交(以及树和blob)。然后,您的Git会将这些内容填充到您的存储库对象数据库中。
一旦安全地保存了对象,Git就会在特殊的FETCH_HEAD
文件中记录哈希ID。如果您的Git至少为1.8.4,那么此时还会更新任何相应的远程跟踪分支名称:例如,它可能会更新您的origin/master
(如果您手动运行git fetch
,您的Git将遵循所有正常的refspec更新规则,如the git fetch
documentation中所述。它是git fetch
传递给git pull
的其他参数{1}}根据你的Git版本禁止其中一些。)
git fetch
将这些对象存储在Git的对象数据库中,可以通过它们的哈希ID来检索它们。它会将哈希ID添加到.git/FETCH_HEAD
(总是),并且通常还会更新refs/tags/
中的部分引用标记名称和refs/remotes/
中的远程跟踪分支名称。
1 除了,&#34; unshallow&#34;一个浅浅的克隆。
git pull
运行git fetch
可以获取对象,但不会将这些对象合并到任何 工作中。如果您希望使用提取的提交或其他数据,则需要第二步。
您可以在此处执行的两项主要操作是git merge
或git rebase
。理解它们的最好方法是在别处阅读它们(其他SO帖子,其他文档等)。然而,两者都是复杂的命令 - git pull
有一个特殊情况,不涵盖了这两个:特别是,你可以git pull
成为不存在的科。在两种情况下,你有一个不存在的分支(Git也称为孤儿分支或未出生的分支):
git checkout --orphan newbranch
在这两种情况下,都没有当前提交,因此无需重组或合并。但是,索引和/或工作树不一定是空的!它们最初在一个新的空存储库中是空的,但是当你运行git pull
时,你可以创建文件并将它们复制到索引中。
这种git pull
传统上都是错误的,所以要小心:在1.8-ish之前的Git版本有时会破坏未提交的工作。我认为最好完全避免git pull
:只需自己运行git fetch
,然后弄清楚你想做什么。据我所知,它在现代Git中没问题 - 这些版本不会破坏你的索引和工作树 - 但我习惯于自己避免使用git pull
。
在任何情况下,即使您不在孤儿/未出生/不存在的分支上,尝试使用脏索引和/或工作运行git merge
也不是一个好主意 - 树(&#34;未提交的作品&#34;)。 git rebase
命令现在有一个自动存储选项(rebase.autoStash
),因此您可以让Git自动运行git stash save
以从任何此类未提交的工作中创建一些分支外提交。然后,rebase本身可以运行,之后Git可以自动应用并删除存储。
git merge
命令没有此自动选项,但您当然可以手动执行此操作。
请注意,如果您处于冲突的合并中,则无法解决此问题。在这种状态下,索引有额外的条目:在解决冲突之前你不能提交这些条目,你甚至不能存储它们(这自然地跟随git stash
真正提交的事实)。您可以 在任何时间运行git fetch
,因为这只会将新对象添加到对象数据库中;但是当索引处于此状态时,您无法合并或变基。
答案 1 :(得分:2)
- 但是,这仍然意味着在“git pull”之后我的工作树将与远程回购相同吗?
醇>
不一定。您正在拉动的分支上的任何本地提交都将与上游的更改合并。使用git pull --rebase
将您的本地更改置于上游提交之上。你可以在没有--rebase
的情况下获得一些非常时髦的合并路径。
- 我发现有些情况下“git pull”不会改变我本地仓库中的任何内容或创建任何新提交?
醇>
如果上游没有新的提交,则本地副本中的任何内容都不会改变。
- “git pull”仅在索引处进行更改是否有意义?
醇>
不是我知道的。也许如果它无法与你的本地提交合并,但是你应该至少在这个过程中遇到一些错误。
- 如果是,我怎样才能使索引的更改继续前进到工作树?
醇>
git pull
:)或git rebase <upstream> <branchname>
。这将在该分支的上游提交之上重新绑定分支<branchname>
中的本地提交。
答案 2 :(得分:2)
否:
如果您有本地提交但尚未推送,或者某些已编制索引的更改(git add
ed),您仍会在上次公开提交之前进行本地更改(或与上次公开提交合并)提交);
是的:
如果自上次git pull
以来没有任何东西被推送到远程仓库,那么你已经是最新的,所以什么都不会改变;
否:
如果您在git pull之后看到索引中的更改,则在运行git pull
之前已经将文件编入索引;
git
已经出现以下警告:如果您的某个索引文件应由merge
更新,git将不会执行合并,并打印一条消息:
error: Your local changes to the following files would be overwritten
by merge:
bb
Please commit your changes or stash them before you merge.
Aborting
在这种情况下:您应该从索引创建提交,并运行git merge origin/current/branch
(或git rebase origin/current/branch
)以将远程修改与您的本地修改合并。
git fetch [origin]
的默认行为是读取存储在远程仓库中的所有分支,并更新存储在refs/remotes/[origin]/*
下的所有本地引用。
然后,您可以在所有标准origin/branch/name
命令中使用git
作为有效的树名称:
# difference with remote "master" branch :
$ git diff HEAD origin/master
# history of remote branch "feature" alongside your local branch "feature" :
$ git log --oneline --graphe feature origin/feature
# merge changes from remote "master" :
$ git merge origin/master
# rebase your local commits on top of remote "develop" branch :
$ git rebase origin/develop
# etc ...
您还有一个快捷方式,可以说&#34;远程分支链接到我的活动分支&#34; :@{u}
$ git diff @{u}
$ git log --oneline --graph HEAD @{u}
$ git merge @{u}
$ git rebase @{u}
# etc ...
什么是完全&#34; git pull&#34;做什么?
在git fetch
之后,git
更新名为FETCH_HEAD
的特殊引用,该引用通常与活动分支的@{u}
匹配;
git pull
git fetch && git merge FETH_HEAD
。
我试图在上面的段落中用我自己的话解释git fetch
。
答案 3 :(得分:0)
获取与此时正在使用的分支相关的las changes of your remote repo
答案 4 :(得分:0)
Git pull是为了使本地分支与其远程版本保持同步,同时还更新其他分支。请阅读此处的文档:Git Pull Documentation