3

我正在寻找与高级瓷器命令等效的适合脚本的管道命令(或命令)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

4

1 回答 1

1

这似乎是一个错误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 个字节长。

如果我们rename foo,这样git checkout-index就不得不用不同的 inode 号重新创建foo,我们发现statindex 中的信息仍然是过时的。换句话说,即使git checkout-index是 re-writing foo,它也永远不会更新缓存的 stat 信息。Sogit status的内部 index-vs-work-tree diff 使用快速路径(将缓存的统计数据与实际文件系统内文件的统计数据进行比较)并假定必须对其进行修改。

(奇怪的是,git update-index --refresh -q也不会触及缓存信息,我不知道为什么不。)

解决方案似乎是git checkout直接使用,至少在git checkout-index修复之前是这样。

于 2017-07-31T19:07:46.730 回答