git reset 修改 HEAD 和 Staging Index 状态时如何得到可视化输出?

How to get visual output when git reset modifies HEAD and Staging Index states?

出于教育目的,我正在寻找一种方法来直观地演示 git reset 如何修改 HEAD 和暂存索引。在 --mixed--hard 的情况下,我想获得分期索引的前后视图,以显示它是如何修改的。 --soft 的情况应该证明它保持不变。

我一直在使用 git status 来演示 git reset 过程,发现当 git status 在 "Changes to be committed" 中显示待处理更新时,说 "the staging index is unchanged" 会令人困惑部分。才知道git status代表的不是Staging Index的状态,而是Head和index的diff。

到目前为止,我一直在使用以下示例进行演示:

git init .
touch reset_lifecycle_file
git add reset_lifecycle_file
git commit -am"initial commit"
echo 'hello git reset' >> reset_lifecycle_file
git commit -am"update content of reset_lifecycle_file"
git log
commit be4aaa98d6976531fdd28aeff52e233087066049
Author: kevzettler <kevzettler@gmail.com>
Date:   Thu Nov 30 15:31:16 2017 -0800

update content of reset_lifecycle_file

commit 5e2d74b369f57929673d873302eb7ebd752c2a95
Author: kevzettler <kevzettler@gmail.com>
Date:   Thu Nov 30 15:20:43 2017 -0800

initial commit

git status
On branch master
nothing to commit, working tree clean

在回购生活的这一点上,如果我执行 git 重置为第一次提交 5e2d74b369f57929673d873302eb7ebd752c2a95

git reset --soft 5e2d74b369f57929673d873302eb7ebd752c2a95
git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    modified:   reset_lifecycle_file

这就是混乱的根源。我一直假设 "Changes to be committed" 输出反映了索引的状态,然后假设 --soft 一直在修改所有 Git 文档声明不会发生的索引。

我最近发现了 git showgit ls-files 命令。我想知道是否可以更好地使用这些来可视化这里的过程。

git show --full-index commit 5e2d74b369f57929673d873302eb7ebd752c2a95
Author: kevzettler <kevzettler@gmail.com> Date: Thu Nov 30 15:20:43
2017 -0800

initial commit

diff --git a/reset_lifecycle_file b/reset_lifecycle_file new file mode
100644 index
0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391

git show --full-index 似乎将一些索引对象 SHA 附加到输出的末尾。我可以用它来指示对索引的重置更改吗?

git ls-files -s
100644 d7d77c1b04b5edd5acfc85de0b592449e5303770 0   reset_lifecycle_file

git lis-files-s 有另一个对象 SHA 我可以用它来指示对索引的更改吗? 在示例的这一点上,它与 git show 的输出中的 SHA 不同,这是否表明 HEAD 位于新索引 SHA?

git ls-files 的方向是正确的。该命令的真正含义是管道。使用 --stage-s,它会列出索引中的每个条目(也称为暂存区)及其哈希 ID。

这不显示 索引的更改。索引本身只是一种状态:它是一个文件,其中包含如果您 运行 git commit 将提交的文件集,或者在某些情况下,您必须解决的持续冲突。因此,要显示 索引的更改,您必须查看一次,然后对其进行一些更改,然后再次查看。无论这两个 "look at" 步骤的两个输出有何不同,都是这两次之间索引发生的变化。

(有些索引条目git ls-files -s没有显示,因为索引也有缓存的作用。添加--debug显示文件条目的缓存信息,但仍然跳过特殊缓存与文件不对应的条目,例如那些记录扩展名,或跟踪未跟踪的文件。后者听起来像是自相矛盾,有点是:缓存至少有时会缓存未跟踪的文件 and/or 目录数据,以加快稍后 git status。由于所有这些条目都不参与提交,因此 git ls-files 直接跳过它们。)

索引内部格式复杂,仅半文档化;参见 Git 的 Documentation/technical/index-format.txt file。然而,外部视图相当简单:对于存储在索引中的每个文件,因此将在下一次提交中,索引具有:

  • 模式:100644100755 任何 blob;
  • 散列(目前为 SHA-1,有朝一日可能更大);
  • 阶段号:通常为0,合并时可能为1、2、3;1
  • 文件的路径名,包括前导目录,例如 xdiff/xprepare.c.

同时,git show 将提交与其父级进行比较:它很像 git log -p -1.2 这意味着它不查看索引。您在此处获得的 index: 行给出了正在比较的父文件和子文件的 blob 哈希值。

(此外,git status 实际上显示了 两个 git diff 命令的输出:一个用于 HEAD vs 索引,一个用于索引与工作树。)


1编号更高的阶段条目的存在阻止了任何新的提交。您只能在将所有这些问题解决为正常的零阶段条目后才能提交。

2如果当前提交是一个合并,git show 会产生一个合并的差异。所以它实际上等同于 git log -p -1 --cc.