从GIT存储库中删除文件但保留本地文件
1. 概述
Git 已经成为一个广泛使用的分布式版本控制系统。在本教程中,让我们探讨如何从 Git 存储库中删除文件或目录,但保留其本地副本。
2. 问题介绍
像往常一样,让我们通过一个例子来理解这个问题。假设我们正在开发一个 Git 存储库 myRepo:
$ ls -l
total 12
drwxr-xr-x 2 kent kent 60 May 12 23:00 logs/
-rw-r--r-- 1 kent kent 26 May 11 13:22 README.md
-rw-r--r-- 1 kent kent 21 May 11 13:22 some-file.txt
-rw-r--r-- 1 kent kent 16 May 12 22:40 user-list.txt
我们已经将存储库克隆到本地,并且如ls输出所示,存储库中有三个文件和一个 logs目录。
现在,假设我们要从 Git 存储库中删除文件user-list.txt和*日志目录。*但是,我们不想将它们从本地工作副本中删除。
一个常见的场景是我们提交了一些文件或目录,然后意识到我们应该忽略一些文件。因此,我们将从存储库中删除相关文件,保留本地副本,并将相应的模式添加到.gitignore*文件中,以便 Git 不再跟踪这些文件。*
我们知道git rm user-list.txt 命令将从存储库中删除文件。但是,它也会删除本地文件。
当然,我们可以将文件和目录移动到另一个目录,提交一个提交,然后将它们复制回本地工作目录。它解决了这个问题。但是,这种方法效率低下,尤其是当文件或目录很大时。
接下来,让我们看看如何更有效地解决这个问题。
3. 使用 git rm –cached命令
我们已经提到git rm FILE默认会从索引和本地工作树中删除文件。
但是,git rm命令提供了*–cached*选项,只允许我们从存储库的索引中删除文件并保持本地文件不变。
接下来,让我们尝试一下 user-list.txt文件:
$ git rm --cached user-list.txt
rm 'user-list.txt'
如上面的输出所示,user-list.txt文件已被删除。所以现在,让我们执行git status命令来验证一下:
$ git status
On branch master
Your branch is up to date with 'origin/master'.
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
deleted: user-list.txt
Untracked files:
(use "git add <file>..." to include in what will be committed)
user-list.txt
我们可以看到,user-list.txt被“deleted”了。此外,由于其本地副本仍然存在,因此已将其标记为“untracked”。
我们可以类似地删除logs目录。但是,由于它是一个目录,我们需要另外将*-r (递归)* 选项传递给 git rm命令:
$ git rm --cached -r logs
rm 'logs/server.log'
现在,让我们提交我们的更改:
$ git commit -m 'remove user-list.txt and logs'
[master ee8cfe8] remove user-list.txt and logs
2 files changed, 4 deletions(-)
delete mode 100644 logs/server.log
delete mode 100644 user-list.txt
然后,让我们使用*git ls-files *命令检查当前暂存 的文件:
$ git ls-files -c
.gitignore
README.md
some-file.txt
如输出所示,目标文件和目录不再存在。此外,还会保留本地副本。因此,我们解决了这个问题。
如果我们愿意,我们可以将它们添加到*.gitignore*文件中,以防止 Git 再次跟踪它们。
4. 删除*.gitignore*中定义的所有文件
有时,我们想检查 Git 的索引并删除*.gitignore中定义的所有文件。假设我们已经完成了.gitignore*的定义。然后,一个简单的方法将是一个三步过程:
- 首先,从索引中删除所有文件:git rm -r –cached
- 然后,再次暂存所有文件。.gitignore中定义的文件将被自动忽略:git add
- 提交我们的更改:git commit -m “a proper commit message”
或者,我们可以只查找和删除当前跟踪但应该被忽略的文件。git ls-files命令可以帮助我们找到文件。
让我们恢复之前的提交并再次删除 user-list.txt文件和logs目录。这一次,让我们先将它们添加到 .gitignore文件中:
$ cat .gitignore
user-list.txt
logs/
接下来,让我们找出要从 Git 索引中删除的文件:
$ git ls-files -i -c -X .gitignore
logs/server.log
user-list.txt
如我们所见,上面的命令列出了我们要删除的暂存文件。
现在,让我们结合 git rm –cached和 git ls-files命令一次性删除它们:
$ git rm --cached $(git ls-files -i -c -X .gitignore)
rm 'logs/server.log'
rm 'user-list.txt'
值得一提的是,该命令会删除logs目录下的所有文件,所以最后会从索引中删除空的logs目录。所以,在这个例子中,我们在logs目录下只有一个文件。
现在,如果我们检查暂存文件,删除的文件就消失了:
$ git ls-files -c
.gitignore
README.md
some-file.txt
当然,user-list.txt和*logs/*仍然在我们的本地工作树中:
$ ls -l
total 12
drwxr-xr-x 2 kent kent 60 May 13 00:45 logs/
-rw-r--r-- 1 kent kent 26 May 11 13:22 README.md
-rw-r--r-- 1 kent kent 21 May 11 13:22 some-file.txt
-rw-r--r-- 1 kent kent 16 May 13 00:45 user-list.txt
5. 被删除的文件还在 Git 历史中
我们已经使用git rm –cached命令解决了我们的问题。但是,我们应该记住,我们只是从 Git 的跟踪索引中删除了该文件。我们仍然可以在 Git 的提交历史中看到该文件及其内容。例如,我们仍然可以通过检查以前的提交来查看user-list.txt的内容:
$ git show 668fa2f user-list.txt
commit 668fa2f...
Author: ...
Date: ...
add user-list.txt and some-file.txt
diff --git a/user-list.txt b/user-list.txt
new file mode 100644
index 0000000..3da7fab
--- /dev/null
+++ b/user-list.txt
@@ -0,0 +1,3 @@
+kent
+eric
+kevin
了解这一点很重要,因为有时我们会忘记在*.gitingore*文件中添加一些敏感文件,例如凭据。但是我们已经提交了它们并将更改推送到远程存储库。在我们意识到这一点之后,我们可能希望从 Git 历史记录中彻底清除敏感文件。 如果是这种情况,我们需要从 Git 的提交历史 中删除这些文件。