git checkout HEAD和git checkout

时间:2019-02-13 23:12:22

标签: git

发出命令'git fetch'后,我是否需要使用'git checkout origin / master file_xyz'或git checkout HEAD origin / master file_xyz,以使用文件副本更新文件'file_xyz'中的更改来自起源/主人?我当前的工作分支不同于来源/主管。 “ git fetch”会同时更新本地存储库和暂存区吗?

1 个答案:

答案 0 :(得分:0)

下面的粗体和斜体字是我的,我认为您的意思是您要问的内容,但我还怀疑您不太了解这里的意思。

  

发出命令git fetch之后,我是否需要使用git checkout origin/master file_xyzgit checkout HEAD origin/master file_xyz来更新 中的更改文件file_xyz和文件origin/master的副本?

尽管第一个是最接近的,但这两个都不对。您可能想使用git merge,但这在 commit 级别而不是 file 级别进行。

  

我当前的工作分支不同于origin/mastergit fetch会同时更新本地存储库和暂存区吗?

不。此外,您真的不希望它更新在Git所称呼的所有条目,各种索引,索引范围,临时区域或目录。 cache (取决于Git的谁或哪个部分正在执行所说的调用)。 git fetch的工作是调用其他一些Git,并从该Git下载,无论他们拥有什么您没有的提交。下载了这些提交后(现在也有了它们),您自己的Git会更新您的远程跟踪名称 (例如origin/master),以记住的哪些提交分支名称,例如 master。请参阅下面的分支说明。

更改与快照

您的问题开始于询问某些文件中的更改。值得强调的是(多次)Git 不存储更改。 Git存储快照。如果您随时间拍摄多个快照,并比较两个快照,则可以找出发生了什么变化。这就像"spot the difference" puzzles中的一个一样,这里的关键实现是必须拍摄两个 快照才能找到区别。一个快照只是一个快照:没有更改

分支和提交

Git中的 branch 这个词是模棱两可的,或者至少是人们使用它的方式。它可以引用名称,例如master,也可以引用一个特定的提交(例如32a38237f30759f18b72d069aebd81bbde47bbec,如果那是{{1 }}),甚至是最后一次提交的整个 结尾的一系列提交。参见What exactly do we mean by "branch"?,通常人们已经很清楚了什么意思,但是当不是的时候,找出它是一个好主意:他们是说 name ,还是 tip commit ? em>或从尖端提交可以到达的部分或全部提交?

您说我当前的工作分支与master 不同,如果用“工作分支”表示分支 name { {1}}报告以下内容:

origin/master

例如。那是因为您不能在任何远程跟踪名称上:“ git status之类的远程跟踪名称实际上不是分支名称,并且On branch develop Your branch is ... 不会放在您“以”这样的名字。相反,您最终将处于Git所谓的“分离式HEAD”模式(我将不在这里介绍)。

如果您在某个分支上 –如果origin/master会为某个 git checkout git status,则名称 On branch B 标识一个特定的提交,而该提交就是您的当前提交。该可以BB之前和/或之后的提交相同。或者,可能是一些不同的提交。

Git中的

commit 是一个唯一的实体,通过其哈希ID进行标识和访问。哈希ID是一个由字母和数字组成的丑陋字符串,例如origin/master,看起来完全是随机的(尽管不是是非常随机的:它实际上是内容的加密校验和的提交)。每个提交都有其自己的,不同的,唯一的哈希ID。如果两个不同的Git存储库的提交都具有相同的哈希ID,则它们包含 same 提交。这就是您的Git知道的,当您调用另一个Git时,是否需要下载一些提交:另一个Git说,例如,我已经提交了git fetch < / em>,然后您的Git检查并说:好,给我不,我已经有了那个。

这些哈希ID对人类几乎没有用,因此,我们为特定的提交给自己指定了名称。这就是分支名称的来源:它们的Git调用最新的主分支提交32a38237f30759f18b72d069aebd81bbde47bbec他们的名称32a38237f30759f18b72d069aebd81bbde47bbec标识了他们的最新提交。该提交可能在您的存储库中,也可能不在。您运行master,Git调用其Git,Git找出其哈希ID是什么,必要时Git 获取。现在您已经拥有了它,现在您的Git更新了您的master来记住:他们的Git最后说他们的git fetch是提交__(填写空白)__。 < / p>

每个提交都存储所有文件的完整完整快照。它们是特殊的,压缩的,冻结的,仅Git的形式。因为它们是冻结的,所以Git可以在一系列提交中 share ,只要它们与先前的提交没有变化。您不能更改Git中任何冻结实体的任何部分,包括提交。每个提交还存储一些元数据,例如谁创建它,何时创建以及为什么(日志消息)。

提交还存储其 parent 或先前提交的哈希ID。这使Git可以从末尾开始-在分支中的 last 提交中-并向后工作:

origin/master

分支名称(例如master)保存我们称为... <-F <-G <-H <--last 的提交的实际哈希ID。这让Git可以找到提交本身。提交包含其父last的哈希ID,这使Git可以找到HG保留其父G的哈希ID,依此类推。

最终,这就是分支在Git中的工作方式和原因。 名称标识 last 提交,其余提交则通过向后工作来找到。

索引和工作树

提交中的文件被冻结且仅支持Git,这对于归档很好,但对完成工作没有用。因此,Git必须有一种方法可以从提交中提取文件,并将其提取到可以进行处理的区域。该区域是工作树

这将足够好:您在可以使用它的工作树中拥有保存在提交中的每个文件的当前冻结副本,以及每个文件的工作副本。您可以告诉Git:从我的工作树中进行新提交,Git将重新压缩每个文件,将其与当前压缩的文件进行比较,然后查看是否需要保存新副本或可以重用旧副本。当它最终完成每个文件的压缩后,就可以进行新的提交了。这将是有效的,但是很慢–例如,对于Linus Torvalds来说太慢了。所以那不是Git要做的。

相反,Git保留每个文件的 1/3 副本。第三份副本已经压缩,可以进入 next 提交了。但是与 current 提交中的副本不同,它不是很冻结。它只是准备冻结。如果您已经对工作树中的文件的可用副本进行了某些操作,则可以运行G将工作树的副本复制回“就绪”副本。现在,该文件已准备提交。请注意,它已经早于,只是之前的副本与当前冻结的提交中的(仍)副本相同F进程只是用新的更新后的进程覆盖它。

该区域保存了Git提取并提交到您的工作树中的提交中的所有文件,并准备好进入 next 提交(换句话说,就是分阶段提交), index 登台区域缓存,具体取决于Git的调用方是谁或谁。因此,索引/暂存区的目的是记住下一次提交的内容

保存新快照

有时候,您可能在工作树中加入了git add filename并做了一些事情。您现在可能想要保存该内容以供将来参考。例如,您可以将其与提交之前 中的版本进行比较,以查看所做的更改。您拍摄了两个快照(新提交的父快照和新提交的快照),然后将它们进行比较并找出差异。

为此,您先运行git add,然后运行file_xyz。 commit命令收集您的日志消息-为什么您做了什么 -并添加您的姓名和当前时间以及所有内容,保存当前提交的哈希ID,并做出新的提交:

git add file_xyz

记住git commit 的哈希ID,您的Git现在将该哈希ID写入已签出的分支的 name 中。如果是...--F--G--H <-- [before your new commit] \ I <-- [your new commit] ,您现在拥有:

I

名称master附加到当前分支,这就是Git知道它应该更新 I <-- master (HEAD) / ...--F--G--H <-- origin/master 的方式。 HEAD也是这样说master的。您大概是从git status创建了On branch master的-Git的提交他们的他们的 master,因此您的origin/master仍然记得哈希ID master

获取新提交

现在您运行origin/master。您的Git调用他们的Git并获取他们的新提交。假设他们有一个这样的:

H

由于他们的git fetch现在可以标识提交 I <-- master (HEAD) / ...--F--G--H--J <-- origin/master ,所以您的 master现在还可以标识其新提交J

合并更改

此时,您可以运行:

origin/master

这告诉您的Git:找到常见的起始提交,我从中进行一些更改和提交,并从中进行一些更改和提交。找出我们两者所做的更改,然后自动合并它们。

因此,您的Git从Jgit merge origin/master 向后走,发现您俩都从提交I开始。这是合并基础

您的Git然后运行,或多或少:

J

如果您更改了H而他们没有更改,或者如果他们更改了您却没有更改,则合并更改很容易:Git可以获取您的版本。如果您都更改了文件,则Git会对文件的合并基础版本(来自提交git diff --find-renames <hash-of-H> <hash-of-I> # what we changed git diff --find-renames <hash-of-H> <hash-of-J> # what they changed )与您的文件进行相互比较。然后,它组合两组更改,将组合更改应用于file_xyz中的文件,并将其用于合并结果。

如果所有文件的所有合并均顺利进行,Git将从结果中重新提交:

H

您的名字H现在指向这个新提交,它将新的更改和您的更改结合在一起。新提交具有两个父级-提交 I--K <-- master (HEAD) / / ...--F--G--H--J <-- origin/master (您先前的分支提示)和提交master(其当前分支提示)-并且其内容包括冻结的{{ 1}}, combined 会更改为应用于合并基础I

如果您确实要放弃您自己的更改

如果毕竟您想放弃J的更改,而只需使用他们的,然后然后想要您建议的第一个命令:

file_xyz

这告诉您的Git:找到H标识的提交。到达该提交并获取冻结的内容。将这些冻结的内容放入我的索引中,以便它们将在我的下一次提交中,并将它们解冻/解压缩到我的工作树中,以便我可以查看和使用它们。您当前的 commit < / em>完全没有变化,但是您的索引和工作树现在包含该文件的版本。

请注意,如果您想从提交file_xyz返回到保存的版本,则可以使用相同的技巧:

git checkout origin/master file_xyz

由于没有明显的提交origin/master名称,您可能要使用其哈希ID。这里的H不是必需的(我们以前不需要),但是这是一种很好的习惯,因为git checkout <hash-of-H> -- file_xyz 看起来不像分支名称或H选项,其他名称可能会。如果您有一个名为--的文件或一个名为file_xyz的文件,则git checkout会告诉-f您是在命名文件,而不是选项或分支。