gitgit-resetgit-show

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


For educational purposes, I am looking for a method to visually demonstrate how a git reset modifies HEAD and the Staging index. In the case of --mixed and maybe --hard I would like to get a before and after view of the Staging Index, to show how it has been modified. The case of --soft should demonstrate that it remains the same.

I had been using git status to demonstrate the git reset processes and found it confusing to say "the staging index is unchanged" when git status shows pending updates in the "Changes to be committed" section. I came to learn that git status is not representative of the state of the Staging Index, but the diff between Head and the index.

I have been using the following example to demonstrate so far:

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

At this point in the repos life if I execute a git reset to the first commit 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

Here is where the confusion has stemmed from. I had been assuming the "Changes to be committed" output was reflective of the state of the index, and was then assuming the --soft had been modifying the Index which all Git documentation states does not happen.

I have recently discovered the git show and git ls-files commands. I am wondering if these can be better used to visualize the process here.

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 appears to append some index Object SHA to the end of the output. Can I use that to indicate reset changes to the index?

git ls-files -s
100644 d7d77c1b04b5edd5acfc85de0b592449e5303770 0   reset_lifecycle_file

git lis-files-s has another Object SHA Can I use that to indicate changes to the index? At this point in the example it differs from the SHA in the output from git show does that indicate the HEAD is at a new index SHA?


Solution

  • You are on the right track with git ls-files. The command is really meant as plumbing. With --stage or -s, it lists each entry in the index (aka staging area), along with its hash ID.

    This does not show changes to the index. The index itself is simply a state: it's a file holding the set of files that will be committed if you run git commit, or, in some cases, the ongoing conflicts that you must resolve. Thus, to show changes to the index, you must look at it once, then make some change to it, then look at it again. Whatever is different in the two outputs from the two "look at" steps is what has changed in the index between those two times.

    (There are some index entries that git ls-files -s does not show, as the index also has a role as a cache. Adding --debug shows the cache information for file entries, but still skips special cache entries that do not correspond to files, such as those recording extensions, or tracking untracked files. The latter sounds like a self contradiction, and sort of is: the cache is, at least sometimes, caching untracked file and/or directory data, to speed up a later git status. Since all of these entries don't participate in commits, git ls-files skips right over them.)

    The internal format of the index is complicated, and only semi-documented; see Git's Documentation/technical/index-format.txt file. The external view, however, is fairly simple: for each file stored in the index, which will therefore be in the next commit, the index has:

    Meanwhile, git show compares a commit to its parent: it's a lot like git log -p -1.2 This means it does not look at the index. The index: line you get here gives the blob hashes for the parent and child files that are being diff-ed.

    (Also, git status actually shows the output of two git diff commands: one for HEAD vs index, and one for index vs work-tree.)


    1The presence of a higher-numbered stage entry prevents making any new commits. You can only commit after resolving all of these back down to normal, stage-zero entries.

    2If the current commit is a merge, git show produces a combined diff. So it's actually equivalent to git log -p -1 --cc.