小编典典

如何 git reset --hard 一个子目录?

all

更新注册 :使用 Git 2.23(2019 年 8 月),有一个新命令git restore可以执行此操作,请参阅接受的答案

更新 :从 Git 1.8.3
开始,这将更直观地工作,请参阅我自己的答案

想象一下以下用例:我想删除 Git 工作树的特定子目录中的所有更改,而保留所有其他子目录不变。

  • 我可以git checkout .,但是git checkout 。添加稀疏结帐排除的目录

  • git reset --hard,但它不会让我为子目录这样做:

    > 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/aand
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

阅读 125

收藏
2022-05-23

共1个答案

小编典典

使用 Git 2.23(2019 年 8 月),您将拥有新命令gitrestore

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

这将用内容替换索引和工作树HEAD,就像reset --hard一个特定的路径一样。


原始答案(2013)

请注意(如Dan Fabulich所评论):

  • git checkout -- <path>不进行硬重置:它将工作树内容替换为暂存内容。
  • git checkout HEAD -- <path>对路径进行硬重置,用HEAD提交中的版本替换索引和工作树。

正如Ajedi32回答的那样,两种结帐表格都不会删除在目标修订中删除的文件** 。 如果工作树中有 HEAD
中不存在的额外文件,则不会删除它们。
git checkout HEAD --<path>

注意:使用[git checkout --overlay HEAD -- <path>(Git 2.22, Q12019),会删除出现在索引和工作树中但不在其中的<tree-ish>文件,以使它们<tree-ish>完全匹配。

但是该结帐可以尊重 a git update-index --skip-worktree(对于您想要忽略的那些目录)

2022-05-23