git stash restoring index state of deleted and renamed files git stash restoring index state of deleted and renamed files git git

git stash restoring index state of deleted and renamed files


Remember: git does not track file renames. It tracks file contents.

When the index contains a deletion and a creation for different files with the same contents, git's rename detection will (probably) conclude that's a rename, and helpfully display it as such. This doesn't actually change what's in the index, though. What "really" happened was indeed a deletion-then-creation, git is just trying to display it more helpfully.

Try it yourself:

$ cp file1 boink$ rm file1$ git add .$ git status

Has the same effect as:

$ git mv file1 boink$ git status

This rename detection only works on things that have been added to the index. Do git reset now and you'll see what I mean:

$ git reset$ git statusChanges not staged for commit:        deleted:    file1Untracked files:        boink

We can use the git command git ls-files to list the files present in the index. In effect, these are the files git considers existent at the moment.When we have a rename staged as above, the output from this is:

# git ls-filesboinkfile2file3file4

As far as the index is concerned, file1 no longer exists. We deleted it, and then we created boink. git status is friendly and shows us the results of rename detection, but remember that the index doesn't care about that.

Now we run git stash -k -u. -k tells stash not to touch the index, so it doesn't. Consider for a moment the first paragraph of the manpage for stash:

Use git stash when you want to record the current state of the working directory and the index, but want to go back to a clean working directory. The command saves your local modifications away and reverts the working directory to match the HEAD commit.

So: we have asked stash to save our local modifications (without touching the index), and revert the working directory to match the HEAD commit.file1 exists in the HEAD commit, so it comes back. But file1 is no longer in the index, because we deleted it. Hence, file1 is now an untracked file. Since we're not touching the index, the new file boink and the record that it was the result of a rename from file1 remains in the index. Hence you get the potentially surprising output from git status:

Changes to be committed:            renamed:    file1 -> boinkUntracked files:        file1


There is output of your script. As you can see there is no file3 and file4 after unstash. This files appear after stash -k. Which is normal behaviour becouse stash restores deleted files. And -k make it keep index changes which is deletion file3 from index. So you have both D file3 and ?? file3 at same time.

Initializing a fresh git dir...rm: refusing to remove '.' or '..' directory: skipping '.'rm: refusing to remove '.' or '..' directory: skipping '..'Initialized empty Git repository in /home/azzel/projects/test/bash/gitstash/gitStashIssue/.git/Preparing git state for test...[master (root-commit) 7e891f6] initial commit 4 files changed, 4 insertions(+) create mode 100644 file1 create mode 100644 file2 create mode 100644 file3 create mode 100644 file4rm 'file3'Current git status is:MM file1M  file2D  file3R  file4 -> fileRenamed?? untrackedFileStasing changes...Saved working directory and index state WIP on master: 7e891f6 initial commitgit status after stashing files is:M  file1M  file2D  file3R  file4 -> fileRenamed?? file3?? file4cleaning up deleted and renamed files...Removing file3Removing file4git status after cleanup:M  file1M  file2D  file3R  file4 -> fileRenamedCommiting unstashed changes...[master 1156712] commit unstashed changes 4 files changed, 2 insertions(+), 1 deletion(-) delete mode 100644 file3 rename file4 => fileRenamed (100%)Auto-merging file1CONFLICT (content): Merge conflict in file1Recorded preimage for 'file1'Index was not unstashed.git status after unstashing:UU file1?? untrackedFile