UPDATE²:在Git 2.23(2019年8月)中,有一个新的命令Git restore可以执行此操作,请参阅已接受的答案。

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

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

我可以做git结帐。,但git结帐。添加被稀疏签出排除的目录 有git重置-很难,但它不让我做一个子目录: > git重置——很难。 致命:不能对路径进行硬复位。 再次:为什么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

当前回答

Git开发人员Duy Nguyen好心地实现了该功能并进行了兼容性切换,根据他的说法,在Git 1.8.3中,以下工作正常进行:

git checkout -- a

(其中a是要硬重置的目录)。原始行为可以通过

git checkout --ignore-skip-worktree-bits -- a

其他回答

我将在这里提供一个糟糕的选择,因为我不知道如何使用Git做任何事情,除了添加提交和推送。下面是我如何“还原”子目录:

我在本地PC上启动了一个新的存储库,将所有内容还原到我想要复制代码的提交,然后将这些文件复制到我的工作目录,添加commit push等等。不要讨厌玩家;恨莱纳斯·托瓦兹先生比我们都聪明。

如果子目录的大小不是特别大,并且你希望远离CLI,这里有一个手动重置子目录的快速解决方案:

切换到主分支,复制要重置的子目录。 现在切换回你的特性分支,用你在第1步中创建的副本替换子目录。 提交更改。

欢呼。您只需手动重置您的特性分支中的子目录,使其与主分支的子目录相同!

Use:

subdir=thesubdir
for fn in $(find $subdir); do
  git ls-files --error-unmatch $fn 2>/dev/null >/dev/null;
  if [ "$?" = "1" ]; then
    continue;
  fi
  echo "Restoring $fn";
  git show HEAD:$fn > $fn;
done

对于我来说,我将使用checkout:

首先,我删除我想重置的文件夹。

然后我将简单地使用checkout:

git checkout <branch> <path>

文件夹将被正确重置为我想要的分支。

在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 checkout——<path>不做硬重置:它将工作树内容替换为阶段性内容。 >对一个路径进行了硬重置,将索引和工作树替换为HEAD提交的版本。

正如Ajedi32所回答的,这两个签出表单都不会删除在目标修订中删除的文件。 如果在工作树中有HEAD中不存在的额外文件,git签出HEAD—<path>将不会删除它们。

注意:使用git checkout——overlay HEAD——<path> (git 2.22, Q1 2019),出现在索引和工作树中,但不在<树状>中的文件将被删除,以使它们与<树状>完全匹配。

但是签出可以尊重git update-index -skip-worktree(用于那些你想忽略的目录),正如“为什么排除的文件不断出现在我的git稀疏签出中?”中提到的那样。