如何使用 git rm --cached 从 Git 索引中移除文件

GitGitBeginner
立即练习

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

介绍

Git 是一个强大的版本控制系统,可以帮助开发者有效地管理他们的代码库。Git 中一个常见的任务是从索引(index,即更改的暂存区)中移除文件。在本教程中,我们将探讨如何使用 git rm --cached 命令从 Git 索引中移除文件,而不会从你的本地文件系统中删除它。

通过一个实际例子理解 Git 索引

Git 索引,也称为暂存区,是 Git 版本控制系统中的一个关键组件。它充当你的工作目录和 Git 仓库之间的中间存储区域。当你对文件进行更改时,Git 不会自动提交这些更改。相反,你需要显式地将更改添加到索引中,然后才能提交它们。

让我们创建一个简单的例子来理解 Git 索引的工作原理:

  1. 首先,让我们为我们的项目创建一个新目录并初始化一个 Git 仓库:
mkdir git-index-demo
cd git-index-demo
git init

你应该看到类似这样的输出:

Initialized empty Git repository in /home/labex/project/git-index-demo/.git/
  1. 现在,让我们创建一个简单的文本文件:
echo "Hello, Git!" > hello.txt
  1. 检查你的仓库的状态:
git status

你应该看到输出表明 hello.txt 未被跟踪:

On branch master

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        hello.txt

nothing added to commit but untracked files present (use "git add" to track)
  1. 将文件添加到 Git 索引:
git add hello.txt
  1. 再次检查状态:
git status

现在你应该看到该文件已暂存以供提交:

On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
        new file:   hello.txt

恭喜你!你刚刚将一个文件添加到了 Git 索引。请注意,Git 告诉你你可以使用 git rm --cached <file> 来取消暂存该文件,这正是我们将在下一步学习的内容。

Git 索引提供了几个好处:

  • 它允许你选择性地选择哪些更改包含在你的下一次提交中
  • 你可以暂存文件的特定部分
  • 它提供了你的下一次提交将包含内容的预览

在下一步中,我们将学习如何使用 git rm --cached 命令从 Git 索引中移除一个文件。

使用 git rm --cached 从索引中移除文件

现在我们已经有一个文件在 Git 索引中,让我们学习如何使用 git rm --cached 命令将其移除。此命令从 Git 索引(暂存区)中移除一个文件,而不会从你的本地文件系统中删除它。

让我们继续使用上一步的例子:

  1. 确保你仍在 git-index-demo 目录中:
cd ~/project/git-index-demo
  1. 让我们检查一下我们仓库的当前状态:
git status

你应该看到 hello.txt 已暂存以供提交(在索引中):

On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
        new file:   hello.txt
  1. 现在,让我们使用 git rm --cached 命令从 Git 索引中移除该文件:
git rm --cached hello.txt

你应该看到类似这样的输出:

rm 'hello.txt'
  1. 再次检查状态:
git status

你会注意到该文件现在未被跟踪:

On branch master

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        hello.txt

nothing added to commit but untracked files present (use "git add" to track)
  1. 确认该文件仍然存在于你的本地文件系统中:
ls -l

你应该在输出中看到 hello.txt

total 4
-rw-r--r-- 1 labex labex 11 [date] hello.txt

这证实了 git rm --cached 仅从 Git 索引中移除了该文件,而不是从你的本地文件系统中移除。

  1. 让我们创建另一个文件来理解如何从索引中移除多个文件:
echo "Another file" > another.txt
git add another.txt
  1. 检查状态:
git status

你应该看到:

On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
        new file:   another.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        hello.txt
  1. 现在,让我们将 hello.txt 重新添加到索引中,看看如何移除多个文件:
git add hello.txt
git status

你应该在索引中看到这两个文件:

On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
        new file:   another.txt
        new file:   hello.txt
  1. 要一次从索引中移除这两个文件:
git rm --cached hello.txt another.txt
  1. 再次检查状态:
git status

这两个文件现在都应该未被跟踪:

On branch master

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        another.txt
        hello.txt

nothing added to commit but untracked files present (use "git add" to track)

git rm --cached 命令特别有用,当:

  • 你不小心将一个文件添加到了 Git 索引
  • 你想停止跟踪一个文件,而又不想从你的系统中删除它
  • 你准备将一个文件模式添加到 .gitignore,但需要首先从索引中移除现有文件

在下一步中,我们将探讨此命令的一些实际用例。

.gitignore 的实际用例

git rm --cached 最常见的用例之一是当你想要停止跟踪应该被忽略的文件时。让我们通过一个实际的例子来探讨这一点。

创建和提交文件

首先,让我们创建一个我们不应该跟踪的文件,并模拟我们不小心提交了应该被忽略的文件的情况:

  1. 确保你仍在 git-index-demo 目录中:
cd ~/project/git-index-demo
  1. 让我们将现有的文件添加到索引中:
git add hello.txt another.txt
  1. 现在,让我们提交这些文件:
git commit -m "Initial commit"

你应该看到确认提交的输出:

[master (root-commit) xxxxxxx] Initial commit
 2 files changed, 2 insertions(+)
 create mode 100644 another.txt
 create mode 100644 hello.txt
  1. 创建一个日志文件,模拟一个我们不想跟踪的生成文件:
echo "Some log data" > application.log
  1. 让我们不小心添加并提交这个日志文件:
git add application.log
git commit -m "Add log file by mistake"

你应该看到确认提交的输出:

[master xxxxxxx] Add log file by mistake
 1 file changed, 1 insertion(+)
 create mode 100644 application.log

使用 .gitignore 和 git rm --cached

现在,让我们通过创建一个 .gitignore 文件并使用 git rm --cached 来修复我们的错误:

  1. 创建一个 .gitignore 文件来指定我们想要忽略所有 .log 文件:
echo "*.log" > .gitignore
  1. 检查状态:
git status

你应该看到:

On branch master
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        .gitignore

nothing added to commit but untracked files present (use "git add" to track)

请注意,即使我们有包含 *.log 模式的 .gitignore 文件,application.log 文件也没有被列为已修改。这是因为 .gitignore 仅阻止未跟踪的文件被添加到索引中。已经跟踪的文件将继续被跟踪。

  1. 让我们添加并提交 .gitignore 文件:
git add .gitignore
git commit -m "Add .gitignore file"
  1. 现在,让我们从 Git 索引中移除日志文件,同时将其保留在我们的文件系统中:
git rm --cached application.log

你应该看到:

rm 'application.log'
  1. 检查状态:
git status

你应该看到:

On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        deleted:    application.log

这表明从 Git 的跟踪系统中删除该文件将被包含在下一次提交中。

  1. 让我们提交此更改:
git commit -m "Stop tracking application.log"
  1. 再次检查状态:
git status

你应该看到:

On branch master
nothing to commit, working tree clean
  1. 现在让我们验证该文件是否仍然存在于我们的文件系统中:
ls -l

你应该看到 application.log 仍然存在,以及我们的其他文件:

total 16
-rw-r--r-- 1 labex labex 13 [date] another.txt
-rw-r--r-- 1 labex labex 13 [date] application.log
-rw-r--r-- 1 labex labex 6  [date] .gitignore
-rw-r--r-- 1 labex labex 11 [date] hello.txt
  1. 让我们尝试修改日志文件,看看 Git 是否跟踪这些更改:
echo "More log data" >> application.log
git status

你应该看到:

On branch master
nothing to commit, working tree clean

即使我们修改了日志文件,Git 也没有检测到任何更改,因为该文件现在由于 .gitignore 模式而被忽略。

当你意外提交应该被忽略的文件时,这是一个非常常见的工作流程,例如:

  • 构建工件
  • 日志文件
  • 包含敏感信息的配置文件
  • 依赖目录(例如 JavaScript 项目中的 node_modules

通过将 git rm --cached.gitignore 结合使用,你可以:

  1. 停止跟踪应该被忽略的文件
  2. 将文件保留在你的本地文件系统中
  3. 阻止它们在将来被添加到仓库中

高级示例:移除敏感信息

git rm --cached 的另一个重要用例是从你的仓库历史记录中移除敏感信息。虽然 Git 旨在跟踪更改,但有时你可能会不小心提交包含密码、API 密钥或其他敏感数据的文件。

让我们看看如何处理这种情况:

  1. 确保你仍在 git-index-demo 目录中:
cd ~/project/git-index-demo
  1. 创建一个文件,模拟一个包含敏感信息的配置文件:
echo "API_KEY=1234567890abcdef" > config.properties
echo "DATABASE_PASSWORD=supersecretpassword" >> config.properties
  1. 添加并提交此文件:
git add config.properties
git commit -m "Add configuration file"
  1. 现在,假设你意识到你已经提交了敏感信息,并希望在保留本地副本的同时将其从跟踪中移除:
git rm --cached config.properties
  1. 创建一个不包含实际敏感信息的模板文件:
echo "API_KEY=your_api_key_here" > config.properties.template
echo "DATABASE_PASSWORD=your_password_here" >> config.properties.template
  1. 更新 .gitignore 文件以忽略真实配置文件,但跟踪模板:
echo "config.properties" >> .gitignore
  1. 添加并提交这些更改:
git add .gitignore config.properties.template
git commit -m "Remove sensitive config from tracking, add template instead"
  1. 让我们检查我们的仓库状态:
git status

你应该看到:

On branch master
nothing to commit, working tree clean
  1. 验证这两个文件都存在于文件系统中:
ls -l config*

你应该看到:

-rw-r--r-- 1 labex labex 60 [date] config.properties
-rw-r--r-- 1 labex labex 60 [date] config.properties.template
  1. 检查正在跟踪哪些文件:
git ls-files | grep config

你应该只看到:

config.properties.template

这种模式通常用于项目,以:

  • 将敏感配置排除在版本控制之外
  • 为其他贡献者提供创建自己配置文件的模板
  • 避免意外提交敏感信息

请记住,虽然 git rm --cached 从未来的提交中移除了该文件,但它并没有从 Git 历史记录中移除该文件。如果你已经将敏感信息推送到远程仓库,你可能需要采取额外的步骤才能将其从历史记录中完全删除。

在实际的项目场景中,你可能需要考虑:

  • 立即轮换任何泄露的凭据
  • 使用环境变量而不是配置文件来存储敏感信息
  • 为生产环境使用专用的密钥管理解决方案

这完成了我们对 git rm --cached 命令的实际用例的探索!

总结

在本教程中,你学习了如何使用 git rm --cached 命令从 Git 索引中移除文件,而不会从你的本地文件系统中删除它们。以下是我们涵盖的内容:

  • 了解 Git 索引(暂存区)及其在 Git 工作流程中的作用
  • 使用 git rm --cached 从索引中移除单个和多个文件
  • git rm --cached.gitignore 集成,以停止跟踪应该被忽略的文件
  • 将这些概念应用于实际场景,例如移除意外提交的文件和处理敏感信息

这些技能对于维护一个干净的 Git 仓库以及正确管理提交到你的版本控制历史记录的内容至关重要。通过利用 git rm --cached,你可以更好地控制 Git 跟踪哪些文件,同时保持你的本地工作目录完好无损。