发出命令'git fetch'后,我是否需要使用'git checkout origin / master file_xyz'或git checkout HEAD origin / master file_xyz,以使用文件副本更新文件'file_xyz'中的更改来自起源/主人?我当前的工作分支不同于来源/主管。 “ git fetch”会同时更新本地存储库和暂存区吗?
答案 0 :(得分:0)
下面的粗体和斜体字是我的,我认为您的意思是您要问的内容,但我还怀疑您不太了解这里的意思。
发出命令
git fetch
之后,我是否需要使用git checkout origin/master file_xyz
或git checkout HEAD origin/master file_xyz
来更新 中的更改文件file_xyz
和文件origin/master
的副本?
尽管第一个是最接近的,但这两个都不对。您可能想使用git merge
,但这在 commit 级别而不是 file 级别进行。
我当前的工作分支不同于
origin/master
。git 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
标识一个特定的提交,而该提交就是您的当前提交。该可以与B
在B
之前和/或之后的提交相同。或者,可能是一些不同的提交。
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可以找到H
。 G
保留其父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从J
和git 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
您是在命名文件,而不是选项或分支。