Git:"git pull"到底是做什么的?做? [英] Git: What EXACTLY does "git pull" do?

查看:89
本文介绍了Git:"git pull"到底是做什么的?做?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道 git pull 实际上是 git fetch git merge 的组合,并且它基本上可以将存储库引入其中在远程存储库中.

I know that git pull is actually a combination of git fetch and git merge, and that it basically brings in the repository as it is in the remote repository.

  1. 但是,这仍然意味着在 git pull 之后,我的工作树将与远程仓库相同吗?
  2. 我发现某些情况下,执行 git pull 不会更改本地存储库中的任何内容或创建任何新的提交.对此有什么解释?
  3. git pull 仅在索引处进行更改是否有意义?
  4. 如果确实如此,我如何使索引处的更改前进到工作树?
  1. But still, does it mean that after git pull my working tree will be identical to the remote repo?
  2. I found some cases that doing git pull doesn't change anything in my local repo or create any new commit. What is the explanation for this?
  3. Does it make sense that git pull makes changes at the index only?
  4. If it does, how can I make the changes at index move forward to the working tree?

推荐答案

完全部分确实很难.人们常说-这在大多数情况下都是对的- git pull 运行 git fetch ,然后是 git merge git rebase ,实际上是 git pull (以前是shell脚本,现在是C程序),虽然实际上它直接调用了 git fetch ,但实际上它首先运行了 git fetch .实现 git fetch 的C代码.

The exactly part is really quite tough. It's often said—and it's mostly true—that git pull runs git fetch followed by either git merge or git rebase, and in fact, git pull, which used to be a shell script and is now a C program, quite literally ran git fetch first, though now it directly invokes the C code that implements git fetch.

但是,下一步非常棘手.另外,在评论中,您添加了以下内容:

The next step, however, is quite tricky. Also, in a comment, you added this:

[获取]从远程存储库带来更改.它放在哪里?

[fetch] brings changes from the remote repo. Where does it put them?

要正确理解这一点,您必须了解Git的对象系统.

To understand this properly, you must understand Git's object system.

每个提交都是一种独立的实体.每个提交都具有唯一的哈希ID: b06d364 ... 或其他.该哈希ID是该提交内容的加密校验和.例如,考虑:

Each commit is a sort of standalone entity. Every commit has a unique hash ID: b06d364... or whatever. That hash ID is a cryptographic checksum of the contents of that commit. Consider, for instance:

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

如果将这些内容(减去的/@//'部分,但Git添加到每个对象的标头)提供给SHA-1校验和计算器,则将获得哈希值ID.这意味着拥有此提交的每个人都具有 same 哈希ID.

If you feed these contents (minus the 's/@/ /' part but with the header that Git adds to every object) to a SHA-1 checksum calculator, you will get the hash ID. This means that everyone who has this commit has the same hash ID for it.

您可以获取Git的Git存储库,然后运行 git cat-file -p v2.13.0 ^ {commit} 来查看相同的数据.注意:标签 v2.13.0 转换为 074ffb61b4b507b3bde7dcf6006e5660a0430860 ,它是一个标签对象;标签对象本身引用了 b06d364 ... :

You can get the Git repository for Git and run git cat-file -p v2.13.0^{commit} to see this same data. Note: the tag v2.13.0 translates to 074ffb61b4b507b3bde7dcf6006e5660a0430860, which is a tag object; the tag object itself refers to the commit b06d364...:

$ git cat-file -p v2.13.0
object b06d3643105c8758ed019125a4399cb7efdcce2c
type commit
tag v2.13.0
[snip]

要进行提交,Git必须将提交对象(具有哈希ID b06d364 ... 的项目)本身存储在某个位置,还应存储其 tree 对象和 tree 需要的任何其他对象.这些是您在 git fetch git push 期间看到的Git计数和压缩的对象.

To work with a commit, Git must store the commit object—the item with the hash ID b06d364...—itself somewhere, and also its tree object and any additional objects that tree needs. These are the objects that you see Git counting and compressing during a git fetch or git push.

parent 行告诉哪个提交(或者,对于合并,提交,复数)是此特定提交的前身.要拥有完整的提交集,Git必须具有父提交(-shallow 克隆可以故意省略各种父级,其ID记录在浅层嫁接"的特殊文件,但正常的克隆将始终包含所有内容.

The parent line tells which commit (or, for a merge, commits, plural) are the predecessors of this particular commit. To have a complete set of commits, Git must also have the parent commit(s) (a --shallow clone can deliberately omit various parents, whose IDs are recorded in a special file of "shallow grafts", but a normal clone will always have everything).

共有四种类型的对象:提交,(带注释)标签,树和Git称为 blob 对象.Blob主要存储实际文件.所有这些对象都驻留在Git的对象数据库中.然后,Git可以通过哈希ID轻松地检索它们:例如, git cat-file -p< hash> 以模糊的人类可读格式显示它们.(尽管树对象具有必须首先格式化的二进制数据,但大多数时候除解压缩外几乎不需要做其他事情.)

There are four types of object in total: commits, (annotated) tags, trees, and what Git calls blob objects. Blobs mostly store the actual files. All of these objects reside in Git's object database. Git can then retrieve them easily by hash ID: git cat-file -p <hash>, for instance, displays them in a vaguely human-readable format. (Most of the time there is little that must be done other than de-compressing, though tree objects have binary data that must be formatted first.)

当您运行 git fetch 时-或让 git pull 为其运行时-您的Git从另一个Git获取一些初始对象的哈希ID,然后使用Git传输协议,以找出完成Git存储库所需的其他对象.如果已经有某个对象,则无需再次获取它;如果该对象是提交对象,则也不需要其任何父对象. 1 因此,您只会得到尚未拥有的提交(以及树和Blob).然后,您的Git将这些填充到存储库的对象数据库中.

When you run git fetch—or have git pull run it for you—your Git obtains the hash IDs of some initial objects from another Git, then uses the Git transfer protocols to figure out what additional objects are required to complete your Git repository. If you already have some object, you do not need to fetch it again, and if that object is a commit object, you do not need any of its parents either.1 So you get only the commits (and trees and blobs) that you do not already have. Your Git then stuffs these into your repository's object database.

一旦安全地保存了对象,您的Git会将哈希ID记录在特殊的 FETCH_HEAD 文件中.如果您的Git至少为1.8.4,那么它此时还会 更新任何相应的远程跟踪分支名称:例如,它可能会更新您的 origin/掌握.

Once the objects are safely saved away, your Git records the hash IDs in the special FETCH_HEAD file. If your Git is at least 1.8.4, it will also update any corresponding remote-tracking branch names at this time: e.g., it may update your origin/master.

(如果您手动运行 git fetch ,则您的Git会遵守所有正常的refspec更新规则,如

(If you run git fetch manually, your Git obeys all the normal refspec update rules, as described in the git fetch documentation. It's the additional arguments passed to git fetch by git pull that inhibit some of these, depending on your Git version.)

那么,这就是我认为您真正的第一个问题的答案: git fetch 将这些对象存储在Git的对象数据库中,在这里可以通过其哈希ID对其进行检索.它将哈希ID添加到 .git/FETCH_HEAD 中(总是),并且经常还会更新您的一些引用- refs/tags/中的标签名称以及远程跟踪分支 refs/remotes/中的名称.

That, then, is the answer to what I think is your real first question: git fetch stores these objects in Git's object database, where they may be retrieved by their hash IDs. It adds the hash IDs to .git/FETCH_HEAD (always), and often also updates some of your references—tag names in refs/tags/, and remote-tracking branch names in refs/remotes/.

1 除外,即取消整理"浅表克隆.

1Except, that is, to "unshallow" a shallow clone.

运行 git fetch 可以获取对象,但不会执行任何操作将这些对象合并到您的的任何工作中.如果您想使用所获取的提交或其他数据,则需要执行第二步.

Running git fetch gets you objects, but does nothing to incorporate those objects into any of your work. If you wish to use the fetched commits or other data, you need a second step.

您可以在此处执行的两个主要操作是 git merge git rebase .理解它们的最好方法是在其他地方阅读它们(其他SO帖子,其他文档等).但是,它们都是复杂的命令,而 git pull 有一种特殊情况,这两种情况没有涵盖:特别是,您可以 git pull 到一个不存在的分支中.在以下两种情况下,您有一个不存在的分支(Git也称为 orphan分支 unborn分支):

The two main actions you can do here are git merge or git rebase. The best way to understand them is to read about them elsewhere (other SO postings, other documentation, and so on). Both are, however, complicated commands—and there is one special case for git pull that is not covered by those two: in particular, you can git pull into a non-existent branch. You have a non-existent branch (which Git also calls an orphan branch or an unborn branch) in two cases:

  • 在一个新的,空的存储库中(没有提交),或者
  • 运行 git checkout --orphan newbranch

在这两种情况下,都没有当前提交,因此没有要重新设置或合并的内容.但是,索引和/或工作树不一定是空的!它们最初在一个新的空存储库中为空,但是当您运行 git pull 时,您可能已经创建了文件并将其复制到索引中.

In both cases, there is no current commit so there is nothing to rebase or merge. However, the index and/or work-tree are not necessarily empty! They are initially empty in a new, empty repository, but by the time you run git pull you could have created files and copied them into the index.

这种 git pull 一直以来都是越野车,因此请注意:1.8-ish之前的Git版本有时会破坏未完成的工作.我认为最好完全避免在这里进行 git pull :自己运行 git fetch ,然后弄清楚自己想做什么.据我所知,在现代Git中还可以-这些版本不会破坏您的索引和工作树-但我有避免自己使用 git pull 的习惯.

This kind of git pull has traditionally been buggy, so be careful: versions of Git before 1.8-ish will sometimes destroy uncommitted work. I think it's best to avoid git pull entirely here: just run git fetch yourself, and then figure out what you want to do. As far as I know, it's OK in modern Git—these versions will not destroy your index and work-tree—but I am in the habit of avoiding git pull myself.

无论如何,即使您不在孤儿/未出生/不存在的分支上,尝试运行带有肮脏索引和/或工作的 git merge 也不是一个好主意-树(未完成的工作"). git rebase 命令现在具有一个自动隐藏选项( rebase.autoStash ),因此您可以让Git自动运行 git stash save 进行创建任何此类未提交的工作中都有一些分支分支的提交.然后,可以运行重新配置本身,之后Git可以自动应用并删除存储.

In any case, even if you are not on an orphan/unborn/non-existent branch, it's not a great idea to try to run git merge with a dirty index and/or work-tree ("uncommitted work"). The git rebase command now has an automatic-stash option (rebase.autoStash), so you can have Git automatically run git stash save to create some off-branch commits out of any such uncommitted work. Then the rebase itself can run, after which Git can automatically apply and drop the stash.

git merge 命令没有此自动选项,但是您当然可以手动进行.

The git merge command does not have this automatic option, but of course you can do it manually.

请注意,如果您处于冲突合并的中间,则上述方法均无效.在这种状态下,索引具有额外的条目:在解决冲突之前,您无法提交这些条目,甚至无法存储它们(这自然是因为 git stash 确实进行了提交).您可以在任何时间运行 git fetch ,因为这只是将新对象添加到对象数据库中.但是当索引处于这种状态时,您将无法合并或变基.

Note that none of this works if you are in the middle of a conflicted merge. In this state, the index has extra entries: you cannot commit these until you resolve the conflicts, and you cannot even stash them (which follows naturally from the fact that git stash really makes commits). You can run git fetch, at any time, since that just adds new objects to the object database; but you cannot merge or rebase when the index is in this state.

这篇关于Git:"git pull"到底是做什么的?做?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆