当存储暂存的已删除或重命名的文件,然后取消存储它们时,它们将恢复为已删除和未删除状态。
在以下示例状态下:
$ git status s
A file0
D file1
R file2 -> file3
?? file4
运行git stash push -k -u
然后git stash pop --index
将让我处于以下状态:
$ git status s
A file0
D file1
R file2 -> file3
?? file1
?? file2
?? file4
我希望最终处于原始状态,而不会在pop
后将已删除的文件重新显示为未跟踪。
有什么办法吗?
编辑: 这是一个重现问题的脚本(在 Mac OS X 10.13.2 上使用 git 2.16.1 进行测试)
#!/usr/bin/env bash
echo -e "nInitializing a fresh git dir..."
mkdir gitStashIssue && cd $_
rm -rf * .*
git init
echo -e "nPreparing git state for test..."
# Create files and commit them
echo 'abc' > file1
echo 'aabbcc' > file2
echo 'aaabbbccc' > file3
echo 'aaaabbbbcccc' > file4
git add .
git commit -m 'initial commit'
# Make changes and add them to stage
echo `cat file1` >> file1
echo `cat file2` >> file2
git add .
# Make another change to a staged file without
# staging it, making it partially staged
echo `cat file1` >> file1
# Delete and rename files
git rm file3
git mv file4 fileRenamed
# Add untracked file
echo "untracked" > untrackedFile
# git status -s should now show
# MM file1
# M file2
# D file3
# R file4 -> fileREnamed
# ?? untrackedFile
echo -e "nCurrent git status is:"
git status -s
echo -e "nStasing changes..."
git stash save -u -k
# git status -s should now show
# M file1
# M file2
# D file3
# R file4 -> fileREnamed
# ?? file3
# ?? file4
echo -e "ngit status after stashing files is:"
git status -s
echo -e "ncleaning up deleted and renamed files..."
git clean ./ -f
echo -e "ngit status after cleanup:"
git status -s
echo -e "nCommiting unstashed changes..."
git commit -m 'commit unstashed changes'
# This causes a conflict in file1
# git status -s should now show
# UU file1
# ?? untrackedFile
git stash pop --index
echo -e "ngit status after unstashing:"
git status -s
请记住:git 不跟踪文件重命名。它跟踪文件内容。
当索引包含对具有相同内容的不同文件的删除和创建时,git 的重命名检测将(可能)得出结论,这是一个重命名,并有助于将其显示为重命名。不过,这实际上并没有改变索引中的内容。"真正"发生的事情确实是先删除然后创建,git 只是试图更有用地显示它。
自己试试:
$ cp file1 boink
$ rm file1
$ git add .
$ git status
具有与以下相同的效果:
$ git mv file1 boink
$ git status
此重命名检测仅适用于已添加到索引的内容。现在git reset
,你就会明白我的意思:
$ git reset
$ git status
Changes not staged for commit:
deleted: file1
Untracked files:
boink
我们可以使用 git 命令git ls-files
列出索引中存在的文件。实际上,这些是 git 认为目前存在的文件。 当我们如上所述进行重命名时,其输出为:
# git ls-files
boink
file2
file3
file4
就索引而言,file1 不再存在。我们删除了它,然后我们创建了boink
.git status
很友好,并向我们展示了重命名检测的结果,但请记住,索引并不关心这一点。
现在我们运行git stash -k -u
.-k
告诉 stash 不要碰索引,所以它不会。考虑一下手册的第一段stash
:
当您想要记录工作目录和索引的当前状态,但又想返回到干净的工作目录时,请使用 git stash。 该命令保存本地修改,并还原工作目录以匹配 HEAD 提交。
所以:我们已经要求 stash 保存我们的本地修改(不接触索引),并恢复工作目录以匹配 HEAD 提交。file1
存在于 HEAD 提交中,所以它会回来。但是file1
不再在索引中,因为我们删除了它。因此,file1
现在是一个未跟踪的文件。由于我们没有触及索引,因此新文件boink
,并且它是从file1
重命名的结果的记录保留在索引中。因此,您可以从git status
获得可能令人惊讶的输出:
Changes to be committed:
renamed: file1 -> boink
Untracked files:
file1
有脚本的输出。如您所见,解开后没有file3
和file4
。此文件显示在stash -k
之后。这是正常行为stash
恢复已删除的文件。和 -k 使其保留索引更改,这是从索引中删除file3
。所以你同时拥有D file3
和?? file3
。
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 file4
rm 'file3'
Current git status is:
MM file1
M file2
D file3
R file4 -> fileRenamed
?? untrackedFile
Stasing changes...
Saved working directory and index state WIP on master: 7e891f6 initial commit
git status after stashing files is:
M file1
M file2
D file3
R file4 -> fileRenamed
?? file3
?? file4
cleaning up deleted and renamed files...
Removing file3
Removing file4
git status after cleanup:
M file1
M file2
D file3
R file4 -> fileRenamed
Commiting unstashed changes...
[master 1156712] commit unstashed changes
4 files changed, 2 insertions(+), 1 deletion(-)
delete mode 100644 file3
rename file4 => fileRenamed (100%)
Auto-merging file1
CONFLICT (content): Merge conflict in file1
Recorded preimage for 'file1'
Index was not unstashed.
git status after unstashing:
UU file1
?? untrackedFile