git reset --soft仅更改哈希值吗?

时间:2019-01-30 10:42:00

标签: git git-reset

在这篇文章中,作者很好地解释了git reset的3个选项(软,混合,硬): https://www.atlassian.com/git/tutorials/undoing-changes/git-reset

他使用“三棵树”作为代表1)工作树,2)临时区域,3)“提交历史记录/提交引用”的设备:

--hard重设(1),(2),(3);

--mixed重置(2)和(3);

--soft仅更改(3)。

这是(3)实际代表的意思,我不清楚。我可以看到如何使用git reset --soft来更改分支指向哪个提交。但是我不知道为什么在这里使用历史这个词。除了分支和HEAD都引用的提交以外,究竟做了哪些修改?

编辑:特别是git reset --soft <SHA1> 编辑i).git/refs/heads/master文件中的哈希值和ii).git/HEAD内部的哈希值,而没有其他内容吗?

2 个答案:

答案 0 :(得分:3)

由于您正在询问具体的实现方式(我认为实际上还是更容易解释),因此在分支机构时,请查看.git/HEAD中的实际内容:

$ cat .git/HEAD
ref: refs/heads/master
$ git checkout -b new
Switched to a new branch 'new'
$ cat .git/HEAD
ref: refs/heads/new
$ git checkout master
Switched to branch 'master'
Your branch is up to date with 'origin/master'.
$ cat .git/HEAD
ref: refs/heads/master

因此,只要我git status会说“在树枝上”,树枝的名称(实际上就是引用的全名)就位于{ {1}}。因此.git/HEAD不会改变,也不需要改变。

.git/HEAD是否存在还存在更多问题:

.git/refs/heads/master

这里发生的是Git已经打包了我的引用名称,因此不再有一个普通文件:$ cat .git/refs/heads/master cat: .git/refs/heads/master: No such file or directory $ git rev-parse master b5101f929789889c2e536d915698f58d5c5c6b7a $ grep master .git/packed-refs b5101f929789889c2e536d915698f58d5c5c6b7a refs/heads/master b5101f929789889c2e536d915698f58d5c5c6b7a refs/remotes/origin/master 被存储在refs/heads/master中,作为以下几个文件之一行(在这种情况下,另一条匹配行是.git/packed-refs)。

也就是说,对哈希ID的引用映射存储在某些数据库中,不一定存储在简单文件中。 (不过,打包引用的“数据库”仍然非常简单。)

不过,要回答您的最终问题,只是refs/remotes/origin/mastergit reset --soft <hash>写入名称到哈希ID的映射中。即使我们使用名称而不是哈希ID,也是如此:

<hash>

名称$ git checkout new $ git reset --soft master~3 现在与名称new所引用的提交哈希ID相同:

master~3

(在当前版本的Git中,将新的哈希ID写入名称$ git rev-parse new 371820d5f1bb3c3e691ad21cee652c02c36ea758 $ git rev-parse master~3 371820d5f1bb3c3e691ad21cee652c02c36ea758 的行为是通过编写简单文件new来覆盖打包引用的数据库,但是您不应这样做取决于此,请改用.git/refs/heads/newgit rev-parse。)

自从我从上方的git update-ref创建new以来,这只产生了将名称master移回三个第一亲跳(new)的效果。这意味着master~3new的祖先,所以:

master

......这样Git就可以了,只需立即删除名称$ git checkout master Switched to branch 'master' Your branch is up to date with 'origin/master'. $ git branch -d new Deleted branch new (was 371820d5f1). ,因为它已完全合并到new

  

但是我不知道为什么在这里使用历史这个词。

“历史”并不是最好的词。要真正理解这一点,请阅读网站Think Like (a) Git。这里的关键概念是可达性。像master一样,更改存储在分支名称下的提交哈希ID,会更改可到达的提交集。如果集合增加,则可以达到更多提交;如果缩小,则可到达的提交更少;如果保持相同的大小,则可以达到相同的数量个提交,但是集合本身可以相同也可以不相同。

从松散和模糊的角度来说,“历史记录”是存储库中的一组提交,或者某些名称可以到达的一组提交,或者某些名称可以到达的某些提交子集。使用一些但不是全部这些松散的定义,移动名称会更改历史记录。

答案 1 :(得分:1)

  

正如作者在主题中所写,为了理解这一点,您需要   了解git内部原理。

我会尽力解释。

在git commit中,是引用树的链接列表,其中引用了blob(文件)和树。

>    C1<------C2<--------C3
>     |        |          |
>     V        V          V
>     T1       T2         T3
>     |       / \         /\
>     V      /   v       /  \
>     B1 <--     B2 <---    B1'

如您所见

  • 在提交1(即)中,C1具有文件B1
  • 在C2中,添加了一个新文件B2。
  • 在C3中,更改了B1文件(B1'),并在数据结构中添加了完整文件的新快照。

我上面解释的是git的内部结构。

  

GIT使用DAG(有向无环图数据结构)

现在,分支,重置和签出命令仅在提交级别上起作用(如您所见,提交来自链接列表)。

因此,假设您的分支指向C2提交,现在您在同一分支中添加了一个新的C3,因此分支指针将从C2移到C3。

类似地,重置与提交相反,因此当您执行重置时,指针将移动到从当前提交向后的提交。 假设您正在提交C2,并且要进行重置,则将当前分支指针移至上一个提交。

让它们变软,变硬并混合。重置有3个选项

  1. hard:这里的指针移至上一次提交,并且先前提交的更改已从工作目录中完全删除。

  2. 已混合:此处将指针移至上一个提交,并且对上一个提交的更改将保留在工作目录中,而无需暂存/添加它们,即在运行命令的情况下

      

    git reset --mixed HEAD〜1

         

    git commit

         

    什么也没提交,工作树很干净

    因为您需要使用

  3. 添加/登台文件
git add <filename>
  1. soft:在这里,指针被移至上一个提交,并且先前的提交更改在添加了它们的工作目录中维护,即如果您运行命令
      

    git reset --mixed HEAD〜1

         

    git commit

由于所有更改都已提交,因此它将创建一个新的提交。

如果您有任何疑问,请告诉我。 :)