我在学习交互式LearnGitBranching教程时,发现了在分支中移动的两种方法。我想确保我没有错过任何东西。
之间有区别吗
git branch -f master master^
并且,假设HEAD
指向master
,则
git reset HEAD^
而且,如果他们做同样的事情,为什么有reset
命令呢?这是否意味着它只是git branch -f
的简写?
谢谢!
天才在评论中指出,git reset
有多种模式。
忽略所有模式及其作用,第一个问题的答案是:如果HEAD
引用master
,并且您使用git branch
将master
移动到另一个提交,那么是的,这实现了与使用git reset
间接移动master
相同的效果。但是:
- 我们不能简单地忽略
reset
的选项 - 我们还以"如果
HEAD
指的是master
"开始回答。如果没有呢
特别地,对于点#1,git reset
的默认模式是--mixed
。reset
命令不仅可以移动分支尖端,而且在这种情况下确实可以。它还可以更新git的索引(也称为"暂存区")。
您可以——事实上,可能应该——将git的索引/暂存区视为"git准备在下次运行git commit
时提交什么"。当您git add
一个文件以使git为下一次提交拾取更改时,git读取该文件的当前工作树版本,然后将1写入索引。
git reset
所做的(或可以做的,以及对--mixed
所做的)是撤消这种索引修改,方法是更改索引内容以匹配您重置为的提交。也就是说,git reset --mixed HEAD^
不仅备份分支一次提交,而且还将所有索引内容重置为备份一次提交。git branch
命令不接触索引。
通过使用--soft
选项,可以使git reset
不接触索引。在这种情况下,它确实做了与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-1找到的。存储库充当一个简单的键值存储,其中键是SHA-1,值是对象:文件aka"blob"、树、提交或注释标记对象。)SHA-1与文件名和执行权限位一起进入索引。稍后,根据需要,在提交时将索引转换为一个或多个git"树"对象;这些树对象包含各种文件名、modse/execute权限和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
与git branch -f
一样。