`git checkout -- .` 的管道等价物
Plumbing equivalent for `git checkout -- .`
我正在寻找等同于高级瓷器命令的适用于脚本的管道命令(或命令)git checkout -- .
我最初的想法是使用 git checkout-index --all --force
,但是在 core.autocrlf = input
的情况下,这并不能完全恢复工作目录:
#!/bin/bash
set -ex
rm -rf repo
git init repo
cd repo
git config --local core.autocrlf input
python3 -c 'open("foo", "wb").write(b"1\r\n2\r\n")'
git add foo
python3 -c 'open("foo", "wb").write(b"3\r\n4\r\n")'
git checkout-index --all --force
echo 'I expect this `git status` to have no modifications'
git status
这会产生以下输出:
+ rm -rf repo
+ git init repo
Initialized empty Git repository in /tmp/foo/repo/.git/
+ cd repo
+ git config --local core.autocrlf input
+ python3 -c 'open("foo", "wb").write(b"1\r\n2\r\n")'
+ git add foo
warning: CRLF will be replaced by LF in foo.
The file will have its original line endings in your working directory.
+ python3 -c 'open("foo", "wb").write(b"3\r\n4\r\n")'
+ git checkout-index --all --force
+ echo 'I expect this `git status` to have no modifications'
I expect this `git status` to have no modifications
+ git status
On branch master
Initial commit
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: foo
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: foo
请注意 git checkout -- .
正确地将工作目录恢复为 index
的内容,即使在这种情况下也是如此。
这似乎是 git checkout-index
中的一个错误:它不知道如何处理工作树毕竟与索引匹配的事实。
如果我们添加git ls-files --stage --debug
,我们看到在第一个git add
之后,索引包含:
100644 1191247b6d9a206f6ba3d8ac79e26d041dd86941 0 foo
ctime: <ct>
mtime: <mt>
dev: <d> ino: <i>
uid: <u> gid: <g>
size: 6 flags: 0
(我在这里用 <...>
替换了不相关的变量值)。请注意,列出的大小是 6,而不是 4:这是工作树文件的大小,实际上是 6 个字节长,因为它包含 \r\n
行结尾。
接下来,我们做:
python3 -c 'open("foo", "wb").write(b"3\r\n4\r\n")'
替换文件,用新的时间戳和新的内容重写现有的 inode。新内容有 6 个字节长。
然后我们做:
git checkout-index [arguments]
它用索引内容覆盖工作树文件,就像 git checkout
一样。该文件现在是 4 个字节长...但是索引仍然显示该文件是 6 个字节长。
如果我们重命名 foo
,那么git checkout-index
必须用不同的inode编号重新创建foo
,我们发现索引中的 stat
信息仍然 已过时。换句话说,即使 git checkout-index
正在重写 foo
,它也不会更新缓存的统计信息。因此 git status
的内部索引与工作树差异使用快速路径(将缓存的统计数据与实际文件系统内文件的统计数据进行比较)并假设它必须被修改。
(奇怪的是,git update-index --refresh -q
也不会触及缓存信息,我不确定为什么不。)
解决方案似乎是直接使用 git checkout
,至少在修复 git checkout-index
之前。
我正在寻找等同于高级瓷器命令的适用于脚本的管道命令(或命令)git checkout -- .
我最初的想法是使用 git checkout-index --all --force
,但是在 core.autocrlf = input
的情况下,这并不能完全恢复工作目录:
#!/bin/bash
set -ex
rm -rf repo
git init repo
cd repo
git config --local core.autocrlf input
python3 -c 'open("foo", "wb").write(b"1\r\n2\r\n")'
git add foo
python3 -c 'open("foo", "wb").write(b"3\r\n4\r\n")'
git checkout-index --all --force
echo 'I expect this `git status` to have no modifications'
git status
这会产生以下输出:
+ rm -rf repo
+ git init repo
Initialized empty Git repository in /tmp/foo/repo/.git/
+ cd repo
+ git config --local core.autocrlf input
+ python3 -c 'open("foo", "wb").write(b"1\r\n2\r\n")'
+ git add foo
warning: CRLF will be replaced by LF in foo.
The file will have its original line endings in your working directory.
+ python3 -c 'open("foo", "wb").write(b"3\r\n4\r\n")'
+ git checkout-index --all --force
+ echo 'I expect this `git status` to have no modifications'
I expect this `git status` to have no modifications
+ git status
On branch master
Initial commit
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: foo
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: foo
请注意 git checkout -- .
正确地将工作目录恢复为 index
的内容,即使在这种情况下也是如此。
这似乎是 git checkout-index
中的一个错误:它不知道如何处理工作树毕竟与索引匹配的事实。
如果我们添加git ls-files --stage --debug
,我们看到在第一个git add
之后,索引包含:
100644 1191247b6d9a206f6ba3d8ac79e26d041dd86941 0 foo
ctime: <ct>
mtime: <mt>
dev: <d> ino: <i>
uid: <u> gid: <g>
size: 6 flags: 0
(我在这里用 <...>
替换了不相关的变量值)。请注意,列出的大小是 6,而不是 4:这是工作树文件的大小,实际上是 6 个字节长,因为它包含 \r\n
行结尾。
接下来,我们做:
python3 -c 'open("foo", "wb").write(b"3\r\n4\r\n")'
替换文件,用新的时间戳和新的内容重写现有的 inode。新内容有 6 个字节长。
然后我们做:
git checkout-index [arguments]
它用索引内容覆盖工作树文件,就像 git checkout
一样。该文件现在是 4 个字节长...但是索引仍然显示该文件是 6 个字节长。
如果我们重命名 foo
,那么git checkout-index
必须用不同的inode编号重新创建foo
,我们发现索引中的 stat
信息仍然 已过时。换句话说,即使 git checkout-index
正在重写 foo
,它也不会更新缓存的统计信息。因此 git status
的内部索引与工作树差异使用快速路径(将缓存的统计数据与实际文件系统内文件的统计数据进行比较)并假设它必须被修改。
(奇怪的是,git update-index --refresh -q
也不会触及缓存信息,我不确定为什么不。)
解决方案似乎是直接使用 git checkout
,至少在修复 git checkout-index
之前。