我正在关注交互式LearnGitBranching教程,并遇到了两种移动分支的方法。我想确定我没有遗漏任何东西。
之间是否存在差异:
git branch -f master master^
并假设HEAD
指向master
,
git reset HEAD^
并且,如果他们做同样的事情,为什么要有reset
命令呢?这是否意味着它只是git branch -f
的缩写?
谢天谢地!
答案 0 :(得分:2)
正如a comment中提到的genisage,git reset
有多种模式。
忽略所有模式及其操作,第一个问题的答案是:如果HEAD
引用master
,您将master
移至另一个提交git branch
然后是的,这实现了与master
间接移动git reset
相同的事情。但是:
reset
的选项。HEAD
引用master
”。如果没有怎么办?特别是,对于第1点,git reset
的默认模式为--mixed
。 reset
命令可以,并且在这种情况下,不仅仅是移动分支尖端。它还可以更新git的索引(也称为“临时区域”)。
你可以 - 事实上,可能应该将git的索引/暂存区域视为“下次运行git commit
时git准备提交的内容”。当你git add
一个文件让git为下次提交提取更改时,git会读取该文件的当前工作树版本,然后将 1 写入索引。
通过更改索引内容以匹配提交,git reset
对(--mixed
)做什么(或可以做什么,以及对git reset --mixed HEAD^
做什么)是撤消这种索引修改复位到。也就是说,git branch
不仅支持分支一次提交,而且还将所有索引内容重置为逐个提交的提交。 git reset
命令不会触及索引。
您可以使--soft
选项无法触及索引。在这种情况下,它确实与您的git branch -f
做同样的事情 - 尽管如第2点所述,这仅在HEAD
引用master
时才有效。如果您想在不使用git reset
的情况下进行软重置,则第一步是找出HEAD
指向的分支(如果有)。只有这样才能更新分支(然后只有当你没有处于“分离的HEAD”模式时)。
为了完整起见,值得注意的是git reset --hard
甚至超过git reset --mixed
:它不仅更新分支提示并重置索引,还会“重置”您的工作树,使其成为看起来像新的目标提交。
值得补充的是,git reset
的几个常见用法只是故意使用它的一些动作:
git reset --soft HEAD^
支持你一次提交,而不更改索引或工作树,以便新的git commit
提供一个新的分支提示,其内容与提交的内容相同备份-过来。这允许你更改提交消息。 2 这与git commit --amend
完全相同,除了后者实际上更容易;所以这种用法不再常见(这是git commit
--amend
选项之前的做法。
git reset --mixed -- <path>
“移动”你当前的提交 - 也就是说,它会重写当前分支以指向它已经指向的位置,这是一个无操作 - 但会重置索引,而不会改变工作树。这样,您就可以“撤消”git add
或git rm --cached
。 3 通常它拼写为git reset <path>
,因为--mixed
是默认值。
git reset --hard
或git reset --hard <path>
再次“移动”您根本不会“移动”,但会重置索引并恢复工作树版本。
reset
命令有几个额外的选项(--merge
和--keep
;还有-p
)不太适合这种模式。不过,我只是在这里忽略它们,以避免让这个答案变得太长。
1 实际上,git将文件(或“blob”)写入存储库,而不是写入索引。在编写blob的过程中,git还会计算得到的SHA-1:对象的“真实名称”。 (所有存储库对象都是由它们的“真实名称”SHA-1s找到。存储库充当一个简单的键值存储,键是SHA-1,值是对象:文件aka“blob”,或者tree,或commit,或annotated-tag-object。)SHA-1进入索引,连同文件名和执行权限位。根据需要,索引稍后在提交时转换为一个或多个git“tree”对象;这些树对象包含各种文件名,modse / execute-permissions和SHA-1。
2 更确切地说,您使用更正后的消息进行新的不同提交。这也是git commit --amend
的作用。旧的(修改前的)提交仍然在存储库中,具有相同的SHA-1;新提交具有不同的消息和不同的时间戳,具有不同的SHA-1,即使它从相同的索引开始,因此附加了相同的树。
3 常规(不是--cached
)git rm
已从工作树中删除了该文件,因此git reset --mixed
将无法执行此操作。 git reset --hard <path>
会这样做,或者您可以git checkout HEAD -- <path>
来恢复该文件。后者“写入”索引,所以这些最终会在命令方面多余,例如git reset --soft
vs git branch -f
。