git checkout< commit>.不会删除提交后添加的文件

xkftehaa  于 2023-01-19  发布在  Git
关注(0)|答案(6)|浏览(175)

使用公共repo,我想让master分支回到过去的某个提交。我已经检查了选项,对我来说最好的事情是简单地 checkout 到所需的提交,然后提交到master分支。但是,当我 checkout 时,它不会删除一些在指定提交哈希之后添加到master分支的文件。
例如,如果我想返回到提交aaa1

$ cd working-copy-top-dir
$ git checkout master
$ git checkout -- .
$ git clean -fd
$ git checkout aaa1 .
$ git clean -fd

但此时,在aaa1之后添加的一些文件仍在工作副本中。要使工作副本 data 恢复到aaa1时的状态,checkout命令是什么?

$ git --version
git version 2.7.2.windows.1
7y4bm7vi

7y4bm7vi1#

TL;DR:首先删除所有内容

当你使用git checkout aaa1 .时,你告诉Git把aaa1转换成一个提交,找到那个提交(更准确地说,它的树),然后把那个提交中的每个文件复制到你的索引/暂存区和工作树。
为了便于讨论,我们假设从master开始,其中包含两个文件READMEhello

$ git checkout master
[output snipped]
$ ls
README   hello
$ cat README
Yay, you read me!
$ cat hello
world
$

我们进一步假设提交aaa1存在并且有两个文件,READMEaddendum,它的README表示Thank you for reading.我们来 checkout :

$ git checkout aaa1 -- .
[output snipped]
$ ls
README    addendum  hello

(我添加了--:这里实际上并不需要,但这是一种很好的做法。)README的内容是更新后的README。文件addendum也已解压缩。文件hello * 未 * 删除,与master中找到的版本相比保持不变。更新后的READMEhello将暂存:

$ git status --short
M  README
A  addendum

但是hello没有被去除:

$ git ls-files --stage
100644 ac6f2cf1acbe1b6f11c7be2288fbae72b982823c 0   README
100644 7ddf1d71e0209a8512fe4862b4689d6ff542bf99 0   addendum
100644 cc628ccd10742baea8241c5924df992b5c019f71 0   hello

使用git clean,即使使用-x,也不会有任何效果:没有东西需要清洗;没有未暂存的文件(hello已暂存,只是未 * 修改 *)。
你特别想让工作树与提交aaa1匹配,为了做到这一点,你必须找到现在在索引中,但不在aaa1中的文件,并删除它们。
不过,还有一种更简单的方法:然后,使用你的git checkout aaa1 -- .aaa1中提取所有的内容。这将填充aaa1中的索引和工作树:任何需要恢复到删除前状态的文件都将恢复(恢复到aaa1中的状态,与HEAD中的状态 * 相同 *)。任何需要更改以匹配aaa1中状态的文件都将恢复(恢复到aaa1中的状态,与aaa1中的状态 * 不同 *)。

$ git rm -rf .
rm 'README'
rm 'addendum'
rm 'hello'
$ git checkout aaa1 -- .
$ git ls-files --stage
100644 ac6f2cf1acbe1b6f11c7be2288fbae72b982823c 0   README
100644 7ddf1d71e0209a8512fe4862b4689d6ff542bf99 0   addendum
$ git status --short
M  README
A  addendum
D  hello

现在你可以提交了,你将在master上有一个新的提交,不管之前有什么,它和aaa1有完全相同的树。
(这是否是一个“好主意”完全是另一回事,但它会让你达到理想的状态。)

tuwxkamq

tuwxkamq2#

你想把你的回购协议回滚到那个状态吗?或者你只是想让你的本地回购协议看起来像那样?
git重置请参见https://git-scm.com/docs/git-reset

**案例1:**如果您这样做

git reset --hard [commit hash]

它会让你的本地代码和本地历史就像它在那个提交时一样,但是如果你想把它推给其他拥有新历史的人,它会失败。

**案例2:**如果您这样做

git reset --soft [commit hash]

它将使您的本地文件更改为像他们当时,但离开您的历史等相同。
我找到了答案here。您还可以看到相关的答案here

zzwlnbp8

zzwlnbp83#

Git checkout will not remove files added since a previous commit .要完成这个操作,我需要git revert
但是,我发现git checkout thehash .更易于使用,并且不难看出自该散列之后添加了哪些文件:

git diff --name-status HEAD thehash
oug3syen

oug3syen4#

我发现这个命令同时更新了我想要的提交的索引和工作副本,在本例中由变量treeish给出:

# use with care: destroys any uncommitted changes
git read-tree "$treeish" --reset -u

要更新工作副本而不更新索引,您可能需要执行以下操作:

index_bak=$(git write-tree)
git read-tree "$treeish" --reset -u
git read-tree "$index_bak" --reset
js4nwp54

js4nwp545#

(开发工具2.22.0,2019年6月)**
运行此选项时:

git checkout --no-overlay <commit> <directory>

删除所有在<commit>之后添加到<directory>下的文件。我希望这是默认行为,但这就是生活。
选项是added by Thomas Gummerer at 091e04bc8cbb0c89c8112c4784f02a44decc257e,它进入了git v2.22.0
试验:

#!/usr/bin/env bash
set -eu

rm -rf tmp
mkdir tmp
cd tmp
git init

mkdir a
touch a/a
git add .
git commit -m a

mkdir b
touch b/b
git add .
git commit -m b

git checkout HEAD~ .
echo 'overlay'
ls -l . a b

git checkout --no-overlay HEAD~ .
echo 'no overlay'
ls -l . a b

结果:

git checkout HEAD~ .
echo 'overlay'
ls -l . a b
echo

git checkout --no-overlay HEAD~ .
echo 'no overlay'
ls -l . a b
echo

输出:

Initialized empty Git repository in /home/ciro/test/git/tmp/.git/
[master (root-commit) 216d22e] a
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 a/a
[master a36e67b] b
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 b/b
overlay
.:
total 2
drwxrwxr-x 2 ciro ciro 3 Jan 17 08:40 a
drwxrwxr-x 2 ciro ciro 3 Jan 17 08:40 b

a:
total 1
-rw-rw-r-- 1 ciro ciro 0 Jan 17 08:40 a

b:
total 1
-rw-rw-r-- 1 ciro ciro 0 Jan 17 08:40 b

no overlay
ls: cannot access 'b': No such file or directory
.:
total 1
drwxrwxr-x 2 ciro ciro 3 Jan 17 08:40 a

a:
total 1
-rw-rw-r-- 1 ciro ciro 0 Jan 17 08:40 a

所以我们看到b/b只会被--no-overlay删除,目录b也会像往常一样被git命令删除,因为git命令会让它变成空目录。
在Ubuntu 22.10和Git 2.37.2上测试。

5n0oy7gb

5n0oy7gb6#

  • git stash* 可能是清理工作树的最快方法。然后 git checkout -b $newbranch $commit-sha1-you-want 创建一个你要使用的分支。所有工作完成后,git stash pop 恢复工作树。

相关问题