一尘不染

如何将git重置为硬子目录?

git

UPDATE²:在Git 2.23(2019年8月)中,有一个新命令Git restore可以做到这一点,请参阅公认的答案。
更新:从Git 1.8.3开始,这将更加直观,请参见我自己的答案。
想象一下下面的用例:我想去掉Git工作树中特定子目录中的所有更改,保留所有其他子目录不变。
我可以做git结账,但是git结账。添加稀疏签出排除的目录
git重置很难,但它不允许我对子目录进行重置:

> git reset --hard .
fatal: Cannot do hard reset with paths.

再说一遍:为什么git不能按路径进行硬/软重置?
我可以使用git diff subdir | patch-p1-R反向修补当前状态,但这是一种相当奇怪的方法。
此操作的正确Git命令是什么?
下面的脚本说明了该问题。在How to make files注释下面插入适当的命令——当前命令将恢复稀疏签出应该排除的文件a/c/ac。请注意,我不想显式还原a/a和a/b,我只“知道”a,并希望还原下面的所有内容。编辑:我也不“知道”b,或者哪些其他目录与a位于同一级别。

#!/bin/sh

rm -rf repo; git init repo; cd repo
for f in a b; do
  for g in a b c; do
    mkdir -p $f/$g
    touch $f/$g/$f$g
    git add $f/$g
    git commit -m "added $f/$g"
  done
done
git config core.sparsecheckout true
echo a/a > .git/info/sparse-checkout
echo a/b >> .git/info/sparse-checkout
echo b/a >> .git/info/sparse-checkout
git read-tree -m -u HEAD
echo "After read-tree:"
find * -type f

rm a/a/aa
rm a/b/ab
echo >> b/a/ba
echo "After modifying:"
find * -type f
git status

# How to make files a/* reappear without changing b and without recreating a/c?
git checkout -- a

echo "After checkout:"
git status
find * -type f

阅读 110

收藏
2022-05-23

共2个答案

一尘不染

有了Git 2.23(2019年8月),您就有了新的命令Git restore(此处也有介绍)

git restore --source=HEAD --staged --worktree -- aDirectory
# or, shorter
git restore -s@ -SW  -- aDirectory

这将用HEAD内容替换索引树和工作树,就像重置一样——很难,但对于特定的路径。
原始答案(2013年)
请注意(如Dan Fabulich所述):
git签出–不会进行硬重置:它将工作树内容替换为分段内容。
git checkout HEAD–对路径进行硬重置,用HEAD提交的版本替换索引和工作树。
正如Ajedi32所回答的那样,两个签出表单都不会删除目标修订版中删除的文件。
如果您在工作树中有额外的文件,而这些文件在HEAD中不存在,那么git签出头–将不会删除它们。
注意:使用git checkout-overlay HEAD–(git 2.22,2019年第1季度),将删除索引树和工作树中出现的文件,但不在中的文件,以使它们精确匹配
但这种签出可以遵循git更新索引——跳过worktree(对于那些您想要忽略的目录)

2022-05-23
一尘不染

根据 Git 开发人员 Duy Nguyen 的说法,他善意地实现了该功能和兼容性开关,从Git 1.8.3 开始,以下工作按预期工作:

git checkout -- a

a您要硬重置的目录在哪里)。可以通过以下方式访问原始行为

git checkout --ignore-skip-worktree-bits -- a
2022-05-23