当前位置: 首页 > article >正文

[Git] 认识 Git 的三大区域 文件的修改和提交


文章目录

    • 认识 Git 的三大区域:工作区、暂存区、版本库
        • 工作区、暂存区、版本库的关系流程图解 (概念)
    • 将文件添加到仓库进行管理:`git add` 和 `git commit`
        • 场景一:第一次添加文件到仓库
        • 查看提交历史:`git log`
        • (进阶理解)提交后的 `.git` 目录变化
        • 场景二:再次理解 `add` 和 `commit` 的配合
    • 修改文件并提交:`git status` 和 `git diff`
        • 查看工作区状态:`git status`
        • 查看具体修改内容:`git diff`
        • 提交修改后的文件
    • 总结一下 Git 的基本操作流程

在上一篇中,我们学习了如何安装 Git 并创建了第一个本地仓库。现在,我们要深入了解 Git 工作中几个非常重要的概念,并学习如何将文件真正地纳入 Git 的管理之下。

认识 Git 的三大区域:工作区、暂存区、版本库

要理解 Git 的工作流程,必须先搞清楚它在哪几个地方“存放”和“处理”你的文件。 Git 主要涉及以下三个区域:

  1. 工作区(Working Directory)
    • 是什么? 就是你在电脑里,能直接看到、直接操作的那个项目文件夹。比如你在里面新建文件、修改代码,这些操作都是在工作区进行的。简单来说,这就是你正在工作的地方,你的“办公桌”。

  1. 暂存区(Staging Area / Index)
    • 是什么? 这是 Git 中一个非常核心且独特的概念。它不像工作区那样是一个看得见的文件夹,它更像一个目录清单或者一个中间“打包区”。当你觉得工作区里的某个文件修改好了,或者某个新文件要纳入 Git 管理了,你就可以用一个命令把这些改动“放”到暂存区里,表明“我这些改动已经准备好了,待会儿要一起保存”。
    • 在哪儿? 暂存区的信息通常存放在 Git 仓库目录(那个隐藏的 .git 文件夹)下的 index 文件里(路径是 .git/index)。所以,有时候人们也把暂存区叫做“索引”(Index)。可以想象成你的“打包盒子”,你把准备好一起提交的文件放进去。
  2. 版本库(Repository)
    • 是什么? 这就是 Git 用来永久存储你的项目历史版本的地方。它包含了所有提交过的版本数据,分支信息,以及 Git 管理项目所需的一切数据。
    • 在哪儿? 就是你项目文件夹里那个隐藏的 .git 文件夹。注意,这个 .git 文件夹不属于工作区!它是独立于工作区的版本库本身。版本库就像你的“仓库”或“档案室”,所有经过 commit 保存的版本都安全地存放在这里,随时可以追溯或恢复。
工作区、暂存区、版本库的关系流程图解 (概念)

想象一下,它们之间的关系就像这样:

+--------------+       +--------------+       +--------------+
|   工作区     | ----> |    暂存区    | ----> |    版本库    |
| (Working Dir)|       | (Staging Area)|       | (Repository) |
+--------------+       +--------------+       +--------------+(你的办公桌)       (准备提交的区域)    (历史版本仓库)^                     ^                     ||                     |                     |+---------------------+---------------------+(可以从版本库或暂存区恢复到工作区)
  • 你所有的文件修改都首先发生在工作区
  • 当你觉得某一部分修改完成了,需要先 git add 把这些改动从工作区添加到暂存区
  • 当你觉得暂存区里的内容(也就是你通过 git add 累积起来的所有改动)都准备好作为一个完整的历史版本保存时,需要 git commit暂存区的内容提交版本库

重点来了!

你仅仅在工作区新建了一个文件,或者修改了工作区里的文件,对于 Git 的版本库来说,它是不知道的!这些改动没有被 Git 跟踪起来。

通过新建或粘贴进⽬录的⽂件,并不能称之为向仓库中新增⽂件,⽽只是在⼯作区新增了⽂件。必须要通过使⽤git addgit commit 命令才能将⽂件添加到仓库中进⾏管理!!

要让 Git 开始管理这些文件和改动,你必须完成从工作区 -> 暂存区 -> 版本库 的这个流程,也就是依次使用 git add 命令和 git commit 命令!

将文件添加到仓库进行管理:git addgit commit

理解了“三区”的概念,我们就知道 Git 跟踪和保存文件的基本步骤是:

  1. 在工作区对文件进行修改或新增。
  2. 使用 git add 命令将工作区的改动添加到暂存区
  3. 使用 git commit 命令将暂存区的改动提交到版本库,形成一个新的历史版本。

下面我们通过实际操作来学习这两个命令。

场景一:第一次添加文件到仓库

假设我们已经在 git init 过的项目文件夹里(也就是工作区),新建了一个 ReadMe 文件,并写了一些内容。

# 确保你在 Git 仓库目录下
zz@139-159-150-152:~/gitcode$ pwd
/home/zz/gitcode# 使用 vim 或其他编辑器创建并编辑 ReadMe 文件
# 比如输入两行内容:
# hello bit
# hello git
zz@139-159-150-152:~/gitcode$ vim ReadMe# 查看 ReadMe 的内容(确认修改已完成)
zz@139-159-150-152:~/gitcode$ cat ReadMe
hello bit
hello git

现在,ReadMe 文件在我们的工作区里。要让 Git 跟踪它,我们需要先把它加到暂存区

第一步:将文件添加到暂存区 (git add)

使用 git add 命令指定要添加的文件名:

# 将 ReadMe 文件添加到暂存区
zz@139-159-150-152:~/gitcode$ git add ReadMe
  • git add [文件名]:将指定文件的工作区改动添加到暂存区。
  • git add [目录名]:将指定目录(包括子目录)下的所有改动都添加到暂存区。
  • git add .:将当前目录下的所有改动(包括新增、修改、删除,但删除需要单独处理或使用特定命令)都添加到暂存区。这是最常用的方式,表示“把我当前目录下所有 Git 知道有变化的文件的改动都放进暂存区”。

执行 git add ReadMe 后,ReadMe 文件的当前状态(包括内容和存在)就被放进了暂存区,它现在正安静地躺在你的“打包盒子”里,等待被提交。

第二步:将暂存区内容提交到版本库 (git commit)

现在暂存区里有了 ReadMe 文件。我们可以用 git commit 命令把暂存区里的所有内容作为一个新的版本提交到版本库。

# 提交暂存区的所有内容到版本库
# -m 后面跟着的是本次提交的“说明信息”
zz@139-159-150-152:~/gitcode$ git commit -m "commit my first file"
  • git commit -m "你的提交信息":提交暂存区中的所有内容到版本库。-m 参数非常重要,后面跟着的是本次提交的日志消息(message)。这个消息是给你自己和未来的协作者看的,要清晰地说明这次提交“做了什么”。这部分内容绝不能省略,也务必好好描述!
  • git commit [文件名1] [文件名2] ... -m "你的提交信息":提交暂存区中指定文件的内容到版本库(但通常我们是提交暂存区的全部内容,所以第一个命令更常用)。

执行 git commit -m "commit my first file" 后,Git 会把你暂存区里所有的改动(这里就是新增的 ReadMe 文件内容)打包,生成一个唯一的版本号(commit id),然后永久地存储到版本库里。

Git 会给出提交成功的反馈信息:

[master (root-commit) c614289] commit my first file  # [分支信息] commit id 的前几位] 提交信息1 file changed, 2 insertions(+)                       # 本次提交涉及1个文件,新增了2行内容create mode 100644 ReadMe                            # ReadMe 文件被创建,权限模式是 100644

这说明你的 ReadMe 文件已经成功地作为你的第一个版本,被 Git 永久保存起来了。

理解多次 add,一次 commit

你可能会想,如果我改了好几个文件,是不是要 add 一次就 commit 一次?不是的!

你可以多次使用 git add 命令,将不同时间修改好的、准备一起提交的文件或改动,陆续地添加到暂存区。当你觉得所有这次要一起保存的改动都进了暂存区后,最后只需执行一次 git commit 命令,Git 就会把暂存区里的所有内容,作为一个完整的、单一的版本提交到版本库。

例如,我们再创建并添加三个空文件 file1, file2, file3

# 在工作区创建三个新文件
zz@139-159-150-152:~/gitcode$ touch file1 file2 file3# 逐个或批量添加到暂存区
zz@139-159-150-152:~/gitcode$ git add file1
zz@139-159-150-152:~/gitcode$ git add file2
zz@139-159-150-152:~/gitcode$ git add file3
# 或者直接 git add . 把当前目录下的所有新增文件都加进去# 一次性提交暂存区里所有待提交的内容(file1, file2, file3)
zz@139-159-150-152:~/gitcode$ git commit -m "add 3 files"
[master 23807c5] add 3 files         # Git 生成了新的 commit id3 files changed, 0 insertions(+), 0 deletions(-) # 本次提交涉及 3 个文件,没有增删行(因为是空文件)create mode 100644 file1             # file1 被创建create mode 100644 file2             # file2 被创建create mode 100644 file3             # file3 被创建

这次提交就包含了这三个文件。这再次印证了 commit 提交的是暂存区的内容。

查看提交历史:git log

每次 git commit 都会在版本库中留下一个永久的历史记录。我们可以使用 git log 命令来查看这些记录。

zz@139-159-150-152:~/gitcode$ git log
commit 23807c536969cd886c4fb624b997ca575756eed6 (HEAD -> master) # 最新提交的 commit id,以及 HEAD 和 master 分支的指向
Author: zz91 <2689241679@qq.com>                          # 作者信息
Date:   Sat May 6 11:27:32 2023 +0800                     # 提交日期和时间add 3 files                                         # 提交时填写的消息(message)commit c61428926f3853d4ec6dde904415b0e6c1dabcc6           # 上一个提交的 commit id
Author: zz91 <2689241679@qq.com>
Date:   Sat May 6 11:25:50 2023 +0800commit my first file

git log 命令会按照提交时间的倒序(最近的提交在最上面)显示所有的提交记录。你可以看到每个提交的唯一 ID、作者、时间以及提交时填写的消息。

如果觉得输出信息太多,可以加上 --pretty=oneline 参数,让信息更简洁:

zz@139-159-150-152:~/gitcode$ git log --pretty=oneline
23807c536969cd886c4fb624b997ca575756eed6 (HEAD -> master) add 3 files      # commit id 和提交信息
c61428926f3853d4ec6dde904415b0e6c1dabcc6 commit my first file             # 上一个 commit id 和提交信息

理解 Commit ID:

git log 中看到的那一长串字母和数字组合(比如 23807c5...c614289...),就是每次提交的 Commit ID(版本号)

它不是简单的 1, 2, 3 递增序号,而是 Git 使用 SHA1 这种加密算法,根据本次提交的内容(包括文件的改动、提交者、时间、父提交等信息)计算出来的一个唯一的哈希值。即使你在不同的电脑上提交相同的内容,生成的 Commit ID 也会是一样的。它是 Git 用来引用某个特定版本的“身份证号”。通常我们只需要使用它的前几位(一般是 7-8 位)就可以唯一标识一个提交了。

(进阶理解)提交后的 .git 目录变化

为了帮助你更深刻地理解 Git 是如何工作的,我们可以再次 peek 一下 .git 目录里的变化。在我们执行了几次 addcommit 后,.git 目录会变得更“丰满”。

zz@139-159-150-152:~/gitcode$ tree .git/
.git/
├── branches
├── COMMIT_EDITMSG       # 最近一次 commit 的消息
├── config               # 仓库配置文件
├── description
├── HEAD                 # 指向当前分支(如 master/main)
├── hooks                # 钩子脚本目录
├── index                # **就是暂存区的文件!git add 会修改它!**
├── info
│   └── exclude          # Git 忽略文件配置
├── logs                 # 记录 HEAD 和分支的移动历史
│   ├── HEAD
│   └── refs
│       └── heads
│           └── master
├── objects              # **Git 存放所有对象的地方(文件内容、目录树、提交等)!**
│   ├── 23               # 根据对象 ID 前两位命名的文件夹
│   │   └── 807c536969cd886c4fb624b997ca575756eed6  # 最新 commit 对象
│   ├── 83
│   │   └── 0a8c9feefbdc098bbae2cdc25e5034ce1920d7  # 一个 tree 对象 (目录树快照)
│   ├── 8f
│   │   └── add50161b6fafa53ce7e79d278dc490240c946  # 可能是一个 blob 或 tree 对象
│   ├── 9c
│   │   └── 9e1f0f6bff3015df71a0963004476f5e6cfd54  # ReadMe 文件的 blob 对象 (内容)
│   ├── c6
│   │   └── 1428926f3853d4ec6dde904415b0e6c1dabcc6  # 第一个 commit 对象
│   ├── e6
│   │   └── 9de29bb2d1d6434b8b29ae775ad8c2e48c5391  # file1/file2/file3 的 blob 对象 (内容)
│   ├── info
│   └── pack              # 优化存储的对象打包文件
└── refs                 # 存放指向 commit 的引用,如分支和标签├── heads            # 分支引用存放处│   └── master       # master 分支引用,里面存着 master 分支最新提交的 commit id└── tags             # 标签引用存放处# 注意:你的 objects 目录下的文件夹和文件可能不同,因为它们是根据你的具体提交内容生成的。

这里面有几个关键文件/目录,和我们的操作密切相关:

  1. .git/index: 这就是暂存区!每次执行 git add 命令,Git 都会更新这个文件,记录下当前暂存区的文件状态和对应的对象信息。
  2. .git/HEAD: 这是一个指针,默认情况下,它指向你当前所在的分支(比如 mastermain)。
# 查看 HEAD 指向
zz@139-159-150-152:~/gitcode$ cat .git/HEAD
ref: refs/heads/master # 表示 HEAD 指向 refs/heads/master
  1. .git/refs/heads/master: 这是一个文件,它里面保存着 master 分支最新一次提交的 commit id
# 查看 master 分支指向的 commit id
zz@139-159-150-152:~/gitcode$ cat .git/refs/heads/master
23807c536969cd886c4fb624b997ca575756eed6 # 这就是我们上面 git log 看到的最新 commit id
  1. .git/objects/: 这是 Git 的对象数据库,Git 存储所有版本数据的核心区域!每次 git add,Git 会把工作区的文件内容压缩并存入这里,生成一个 blob 对象;每次 git commit,Git 会根据暂存区的内容,生成一个 tree 对象(代表当时的目录结构)和一个 commit 对象(包含作者、时间、message,以及指向 tree 对象和父 commit 对象)。你看到的 objects 目录下以 commit id 前两位命名的文件夹里,就存放着这些对象。

所以上图实际上还有一个文件夹作为逻辑上的中间层:对象库

Git 使用 SHA1 哈希值作为对象的 ID。你可以使用 git cat-file -p [对象ID] 命令来查看 Git 对象库中某个对象的内容。

例如,查看最新的 commit 对象(使用上面 git log 或 .git/refs/heads/master 看到的 commit id):

zz@139-159-150-152:~/gitcode$ git cat-file -p 23807c536969cd886c4fb624b997ca575756eed6
tree 830a8c9feefbdc098bbae2cdc25e5034ce1920d7  # 这个 commit 对应的目录树对象 ID
parent c61428926f3853d4ec6dde904415b0e6c1dabcc6 # 这个 commit 的父提交 ID(上一个版本)
author zz91 <2689241679@qq.com> 1683343652 +0800 # 作者信息
committer zz91 <2689241679@qq.com> 1683343652 +0800 # 提交者信息
# 这是本次提交的消息
add 3 files

再查看上面 commit 对象里指向的 tree 对象(使用 tree 后面的 ID):

zz@139-15 Confusion - git diff vs git diff --staged? (added, modified, deleted files) - Stack Overflow https://stackoverflow.com/questions/3878338/git-diff-vs-git-diff-staged-added-modified-deleted-files```git diff` shows the difference between the *working directory* and the *staging area*.`git diff --staged` shows the differences between the *staging area* and the *last commit*.`The provided text *only* mentions `git diff [file]` (which compares working dir to staging) and `git diff HEAD -- [file]` (which compares working dir to last commit). It *doesn't* mention `git diff --staged`.To stick strictly to the text, I should *only* explain `git diff [file]` (WD vs Stage) and `git diff HEAD -- [file]` (WD vs HEAD/Repo). However, for beginner understanding, clearly explaining the three comparisons (`WD vs Stage`, `Stage vs Repo`, `WD vs Repo`) is very helpful.Let's clarify based on standard Git usage and the provided text:
* `git diff` (without file): By default, compares Working Dir and Staging Area.
* `git diff [file]`: Compares the *specific file* in the Working Dir and Staging Area. (This matches the text's example).
* `git diff --staged` (or `--cached`): Compares Staging Area and the last commit. (Not in text, but a crucial comparison).
* `git diff HEAD` (without file): Compares Working Dir and the last commit.
* `git diff HEAD -- [file]`: Compares the *specific file* in the Working Dir and the last commit. (This matches the text).Okay, I will explain `git diff [file]` as comparing Working Dir and Staging Area (as the text implies by the context of needing `git add` afterwards). I will also explain `git diff HEAD -- [file]` as comparing Working Dir and the last commit (as the text states). I will *not* introduce `git diff --staged` as it's not in the provided content, even if it's conceptually useful. I need to explain what the diff output format means simply.Let's refine the "修改文件" section based on this.**Refined Drafting - Modifying Files:*** Start with modifying ReadMe.
* Introduce `git status` - explain it shows the state relative to Staging and Repository. Show output "Changes not staged for commit". Explain this means "Working Dir has changes compared to Staging Area".
* Introduce `git diff [file]` - explain it shows *what* those unstaged changes are. Show output. Explain the `+` (added lines) and `-` (removed lines). State it compares Working Dir and Staging Area.
* Mention `git diff HEAD -- [file]` as another diff command, comparing Working Dir and the *last commit* in the Repository. Explain why you might use it (see differences since the *last saved version*).
* Show `git add ReadMe` - explain it moves the *modified* `ReadMe` from Working Dir to Staging Area.
* Show `git status` again - output should be "Changes to be committed". Explain this means "Staging Area has changes ready to be committed".
* Show `git commit -m "..."` - explain it saves the Staging Area to the Repository.
* Show final `git status` - output "nothing to commit, working tree clean". Explain this means Working Dir and Staging Area match the last commit.This flow directly uses the provided commands and explanations while clearly linking them back to the three areas and the state changes.Let's integrate this refined section into the overall structure.59-150-152:~/gitcode$ git cat-file -p 830a8c9feefbdc098bbae2cdc25e5034ce1920d7
100644 blob 9c9e1f0f6bff3015df71a0963004476f5e6cfd54 ReadMe   # ReadMe 文件,类型是 blob,这是它的对象 ID
100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 file1   # file1 文件,类型是 blob,这是它的对象 ID
100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 file2   # file2 文件
100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 file3   # file3 文件

这个 tree 对象记录了在 23807c5... 那个提交时,项目根目录下有哪些文件和文件夹,以及它们各自对应的对象 ID。这里可以看到 ReadMe, file1, file2, file3 都指向了各自的内容对象。

最后,我们查看 ReadMe 文件对应的 blob 对象(使用上面看到的 9c9e1f0f6bff3015df71a0963004476f5e6cfd54 ID):

zz@139-159-150-152:~/gitcode$ git cat-file -p 9c9e1f0f6bff3015df71a0963004476f5e6cfd54
hello bit
hello git
# 这就是 ReadMe 文件在那个提交时的实际内容!

通过这个探索,我们可以看到 Git 如何在 objects 目录下存储文件的实际内容(blob 对象)、目录结构(tree 对象)以及提交信息(commit 对象),并且通过 Commit ID 将它们关联起来。每次 git addgit commit 都会在这个对象库中创建新的对象。这有助于我们理解 Git 是如何保存项目历史的。

总结 .git 内部的几个重要部分:

  • index: 暂存区的实际文件,git add 的结果保存在这里。
  • HEAD: 指向当前所在分支(默认是 mastermain)的指针
  • refs/heads/master: 一个文件,里面存储着 master 分支最新提交的 commit id
  • objects: Git 的对象数据库,存放所有 Git 管理的对象(文件内容、目录树、提交等)。

在今后的学习中,试着将常用的 Git 命令和 .git 目录内部的变化联系起来,每次操作后都进行回想“这时候目录内部的操作”,可以帮助你更深刻地理解 Git 的工作原理。

场景二:再次理解 addcommit 的配合

为了加深对工作区、暂存区、版本库以及 addcommit 命令关系的理解,我们再看一个例子:

# 1. 在工作区新增 file4 文件
zz@139-159-150-152:~/gitcode$ touch file4# 2. 将 file4 添加到暂存区(它现在进入了打包盒子)
zz@139-159-150-152:~/gitcode$ git add file4# 3. 紧接着,在工作区又新增了 file5 文件(它还在办公桌上)
zz@139-159-150-152:~/gitcode$ touch file5# 4. 提交修改(Git 会提交暂存区的内容)
zz@139-159-150-152:~/gitcode$ git commit -m"add file"
[master 3d406c0] add file1 file changed, 0 insertions(+), 0 deletions(-)create mode 100644 file4

看提交结果,Git 告诉我们只有 1 file changed (file4)!这是怎么回事?我们明明新增了两个文件 (file4file5) 啊?

原因: 回忆一下我们前面说的,git commit 提交的是暂存区里的内容。在执行 git commit 命令时:

  • file4 已经通过 git add file4 被添加到了暂存区。
  • file5 虽然在工作区被创建了,但我们没有对它执行 git add file5,所以它还在工作区,没有进入暂存区。

因此,git commit 时只看到了暂存区里的 file4,就把 file4 提交了,而完全忽略了还在工作区的 file5

如何提交 file5 呢? 非常简单,按照流程来:先 git add file5file5 加到暂存区,然后再 git commit 一次。

这个例子再次强调用 commit 提交的是暂存区,而不是工作区!在你 commit 之前,一定要确保所有想提交的改动都已经通过 git add 进入了暂存区。

修改文件并提交:git statusgit diff

除了新增文件,修改已有文件是更常见的操作。Git 在这方面设计得非常高效,因为它跟踪并管理的是文件的修改,而不是整个文件。

“修改”可以有很多种:在你文件中新增一行、删除一行、更改几个字符、甚至改变文件名等等,Git 都能识别为“修改”。

让我们来修改一下之前创建的 ReadMe 文件:

# 查看 ReadMe 的当前内容
zz@139-159-150-152:~/gitcode$ cat ReadMe
hello bit
hello git
# 修改 ReadMe 文件,比如增加一行
# hello bit
# hello git
# hello world
zz@139-159-150-152:~/gitcode$ vim ReadMe
# 再次查看修改后的内容
zz@139-159-150-152:~/gitcode$ cat ReadMe
hello bit
hello git
hello world

现在,工作区里的 ReadMe 文件内容和版本库中最新提交的 ReadMe 内容已经不一样了。Git 怎么知道哪些文件被修改了呢?

查看工作区状态:git status

git status 命令是使用 Git 过程中最最常用的命令之一!它用于查看你当前工作区暂存区的状态,告诉你哪些文件有改动,这些改动处于哪个阶段(在工作区还是暂存区)。

# 查看 Git 仓库状态
zz@139-159-150-152:~/gitcode$ git status
On branch master
Changes not staged for commit:(use "git add <file>..." to update what will be committed)(use "git restore <file>..." to discard changes in working directory)modified: ReadMeno changes added to commit (use "git add" and/or "git commit -a")

git status 的输出信息告诉我们:

  • On branch master: 你当前在 master 分支上(分支概念后面会讲)。
  • Changes not staged for commit:: 工作区有改动,但这些改动还没有添加到暂存区(还没有 add)。
  • modified: ReadMe: ReadMe 文件被修改了。
  • no changes added to commit: 暂存区是空的,没有任何准备要提交的内容。

这个状态说明:你修改了 ReadMe 文件,但 Git 只是知道它被改了,还没有把这个改动记录到暂存区,更没有提交到版本库。它还在你的“办公桌”上。

查看具体修改内容:git diff

git status 告诉我们文件被修改了,但具体改了哪些地方呢?这就需要用到 git diff 命令。

git diff 命令默认情况下,是用来查看工作区暂存区之间文件差异的。

# 查看 ReadMe 文件在工作区和暂存区之间的差异
zz@139-159-150-152:~/gitcode$ git diff ReadMe
diff --git a/ReadMe b/ReadMe
index 9c9e1f0..4a97140 100644
--- a/ReadMe         # Diff 比较的“旧”文件(暂存区或最新提交的版本)
+++ b/ReadMe         # Diff 比较的“新”文件(工作区的文件)
@@ -1,2 +1,3 @@     # 表示在原文件的第1行开始的2行,和新文件的第1行开始的3行之间有差异hello bit
-hello git           # 减号开头的行表示在旧版本有,在新版本被删除了
+hello git           # 加号开头的行表示在旧版本没有,在新版本被增加了
+hello world         # 加号开头的行表示在新版本被增加了

git diff 的输出使用了标准的 diff 格式:

  • --- a/ 开头表示比较的“旧”文件(通常是暂存区或上一个版本的)。
  • +++ b/ 开头表示比较的“新”文件(通常是工作区当前的)。
  • @@ ... @@ 之间的信息表示差异发生的位置。
  • - 开头的行表示这行在旧版本有,但在新版本被删除了
  • + 开头的行表示这行在旧版本没有,但在新版本被新增了

通过 git diff ReadMe,我们清楚地看到在工作区,我们在 hello git 后面新增了一行 hello world,并且虽然 hello git 本身内容没变,但因为上面的行删除了,这里显示好像是删了又加了(Git 认为行号变了也算改动,或者这里的 diff 算法是按行匹配)。但重点是,你能清晰地看到 hello world 是新增的。

另一个常用的 diff 比较:工作区与版本库最新提交的差异

如果你想直接看工作区的文件和版本库里最新提交的版本有什么不同,可以使用 git diff HEAD -- [文件名] 命令:

# 查看工作区 ReadMe 文件和版本库最新提交版本 ReadMe 文件的差异
git diff HEAD -- ReadMe

这个命令会比较你当前工作区的状态和 HEAD 指针指向的那个提交(也就是当前分支的最新版本)的文件状态。了解这个有助于你区分工作区和暂存区在 diff 命令中的不同作用。

提交修改后的文件

现在我们知道了 ReadMe 被修改了,并且通过 git diff 确认了修改内容。接下来,按照流程,把这个修改也保存到版本库中。

第一步:将修改添加到暂存区 (git add)

虽然文件是修改,不是新增,但流程一样,还是要先 add 到暂存区:

zz@139-159-150-152:~/gitcode$ git add ReadMe

执行 git add ReadMe 后,ReadMe 文件在工作区里的修改就被添加到了暂存区。暂存区里现在包含了 ReadMe 文件修改后的新内容。

再次查看状态 (git status):

现在 ReadMe 的修改已经在暂存区了,我们再看看状态:

zz@139-159-150-152:~/gitcode$ git status
On branch master
Changes to be committed:(use "git restore --staged <file>..." to unstage)modified: ReadMe

这次的输出变了!ReadMe 文件出现在了 Changes to be committed: 这个区域下,并且前面显示 modified: ReadMe。这表明 ReadMe 文件在暂存区里有改动,这些改动已经准备好被提交到版本库了。

第二步:将暂存区内容提交到版本库 (git commit)

暂存区里有内容了,我们就可以执行 commit 命令来保存这个修改版本了:

# 提交暂存区的修改到版本库,并写上提交信息
zz@139-159-150-152:~/gitcode$ git commit -m "add modify ReadMe file"
[master 94da695] add modify ReadMe file1 file changed, 2 insertions(+), 1 deletion(-) # 这次修改的结果:1 个文件改动,增加了 2 行,删除了 1 行

提交成功!ReadMe 文件的这次修改已经被作为一个新的版本永久保存在版本库里了。

最后查看状态 (git status):

提交完成后,工作区和暂存区都应该是干净的(和版本库最新提交的状态一致)。

zz@139-159-150-152:~/gitcode$ git status
On branch master
nothing to commit, working tree clean

nothing to commit, working tree clean:这说明当前工作区和暂存区都没有任何需要提交的改动,它们的状态是干净的,和版本库里最新的版本是同步的。这是一个很好的状态!

总结一下 Git 的基本操作流程

通过上面的学习,我们现在对 Git 的基本操作流程有了清晰的认识:

  1. 在工作区里工作: 新建、编辑、删除文件。
  2. 查看状态: 经常使用 git status 查看工作区和暂存区的状态,了解哪些文件有改动,它们处于哪个阶段。
  3. 查看具体改动: 使用 git diff [文件名] 查看工作区里的文件相对于暂存区的具体修改内容。
  4. 将改动添加到暂存区: 使用 git add [文件名]git add . 将工作区中准备提交的改动放入暂存区。
  5. 提交暂存区的改动: 使用 git commit -m "有意义的提交信息" 将暂存区的内容作为一个新版本提交到版本库。
  6. 查看历史: 使用 git log 查看已经提交的版本历史。

理解工作区 -> 暂存区 -> 版本库 这个流程,以及 git addgit commit 在其中扮演的角色,是掌握 Git 的关键。每次改动都需要经过 addcommit 两步(或类似操作)才能真正被 Git 永久记录下来。

接下来,我们将继续学习 Git 的其他常用操作,比如如何回退版本,如何忽略文件等等。

相关文章:

[Git] 认识 Git 的三大区域 文件的修改和提交

文章目录 认识 Git 的三大区域&#xff1a;工作区、暂存区、版本库工作区、暂存区、版本库的关系流程图解 (概念) 将文件添加到仓库进行管理&#xff1a;git add 和 git commit场景一&#xff1a;第一次添加文件到仓库查看提交历史&#xff1a;git log&#xff08;进阶理解&…...

RISC-V 开发板 MUSE Pi Pro USB 测试(3.0 U盘,2.0 UVC摄像头)

视频讲解&#xff1a; RISC-V 开发板 MUSE Pi Pro USB 测试&#xff08;3.0 U盘&#xff0c;2.0 UVC摄像头&#xff09; 总共开发板有4个USB的A口&#xff0c;1个USB的TypeC口&#xff0c;我们插上两个USB3.0的U盘和一个USB2.0的UVC摄像头来进行测试 lsusb -tv 可以看到有3个US…...

【520 特辑】用 HTML/CSS/JavaScript 打造浪漫炫酷的表白网页

一、前言 在 520 这个充满爱意的日子里&#xff0c;程序员该如何用代码表达浪漫&#xff1f;本文将分享一个结合动画特效与交互设计的 520 表白网页案例&#xff0c;通过 HTML/CSS/JavaScript 实现动态爱心、渐变背景、浮动文字等炫酷效果&#xff0c;手把手教你用技术传递心意…...

小米2025年校招笔试真题手撕(二)

一、题目 给一个长度为n的序列和一个整数x&#xff0c;每次操作可以选择序列中的一个元素&#xff0c;将其从序列中删去&#xff0c;或者将其值加一。 问至少操作多少次&#xff0c;可以使操作后的序列&#xff08;可以为空&#xff09;中数字之和是x的倍数。 输入描述&#…...

弱网服务器群到底有什么用

在当今数字化的时代&#xff0c;大家都在追求高速、稳定的网络体验&#xff0c;但你是否想过&#xff0c;弱网服务器群其实也有着不可小觑的作用。让我们来聊聊什么是弱网服务器群。简单来说&#xff0c;它是一组在网络条件相对较差情况下运行的服务器集合。 弱网服务器群组是一…...

部署Gitlab-CE with Docker私有云环境

应用环境 Ubuntu 20.04.6 LTS (GNU/Linux 5.15.0-139-generic x86_64) Docker version 28.1.1, build 4eba377 文章目录 拉取容器镜像生成Run脚本参数解读实例脚本环境配置管理员密码遗忘服务邮箱配置邮件测试 运维问题集锦(1) 端口映射关系(2) 服务日志(3) 分支受保护 项目操作…...

拉普拉斯高斯(LoG)滤波器掩模的注意事项

目录 问题&#xff1a; 解答&#xff1a; 一、高斯函数归一化&#xff1a;消除幅度偏差 1. 归一化的定义 2. 为何必须归一化&#xff1f; 二、拉普拉斯系数和为零&#xff1a;抑制直流项干扰 1. 拉普拉斯算子的特性 2. 系数和不为零的后果 三、直流项如何影响零交叉点&…...

铠大师:让用户畅享多元应用,助力鸿蒙生态发展

在全球信息技术产业格局加速重构的背景下&#xff0c;中国科技力量正以开放包容的姿态重塑操作系统生态范式。 5月19日&#xff0c;华为在成都举办的nova14系列及鸿蒙电脑新品发布会上&#xff0c;正式对外发布搭载了鸿蒙系统的笔记本电脑HUAWEI MateBook Pro与HUAWEI MateBoo…...

RocketMQ核心特性与最佳实践

目录 1. 引言 2. RocketMQ核心特性 2.1 架构演进 2.2 核心组件 2.3 消息模型 2.4 高级特性 3. RocketMQ与其他MQ产品选型对比 3.1 功能特性对比 3.2 适用场景对比 3.3 选型建议 4. RocketMQ部署最佳实践 4.1 部署模式选择 4.2 硬件配置建议 4.3 操作系统优化 4.4…...

springboot配置redis lettuce连接池,以及连接池参数解释

文章目录 前置基本配置参数解释 前置 javaspringbootredislettuce 连接池 有很多连接池&#xff0c;比如 jedis&#xff0c;lettuce&#xff0c;redission&#xff0c;springboot 默认使用 lettuce 连接池 lettuce 连接池的特点是&#xff1a;一个 lettuce 连接可以被多个线…...

基于aspnet,微信小程序,mysql数据库,在线微信小程序汽车故障预约系统

详细视频:【基于aspnet,微信小程序,mysql数据库,在线微信小程序汽车故障预约系统。-哔哩哔哩】 https://b23.tv/zfqLWPV...

如何使用AI搭建WordPress网站

人工智能正迅速成为包括网页设计在内的许多行业在其功能设置中添加的一种工具。在数字设计和营销领域&#xff0c;许多成熟的工具都在其产品中添加了人工智能功能。WordPress 也是如此。作为目前最流行的网站建设工具之一&#xff0c;WordPress 的人工智能插件越来越多也就不足…...

打破双亲委派模型的实践:JDBC与Tomcat的深度解析

一、JDBC如何打破双亲委派模型 1. JDBC SPI机制的核心矛盾 Java数据库连接(JDBC)是打破双亲委派模型的经典案例&#xff0c;其根本原因在于基础类库需要加载实现类的矛盾&#xff1a; 核心接口位置&#xff1a;java.sql.Driver等接口位于rt.jar中&#xff0c;由启动类加载器…...

《打破枷锁:Python多线程GIL困境突围指南》

GIL&#xff0c;这个Python解释器层面的独特机制&#xff0c;虽在一定程度上守护了内存管理的秩序&#xff0c;却也成为了多线程并行的紧箍咒&#xff0c;限制了Python在多核处理器上的性能发挥。今天&#xff0c;让我们深入剖析GIL的本质&#xff0c;探寻突破这一枷锁的有效策…...

Java并发编程:全面解析锁策略、CAS与synchronized优化机制

一、六种锁策略场景化解析 1. 乐观锁 vs 悲观锁&#xff1a;图书馆借书的两种策略 核心差异&#xff1a;对资源是否会被抢占的预期不同。 乐观锁&#xff08;假设冲突概率低&#xff09; → 行为&#xff1a;直接去书架上拿书&#xff08;围绕加锁要做的工作更少&#xff09…...

2025第三届黄河流域网络安全技能挑战赛--Crypto--WriteUp

2025第三届黄河流域网络安全技能挑战赛–Crypto–WriteUp Crypto sandwitch task from Crypto.Util.number import * import gmpy2 flag bflag{fake_flag} assert len(flag) 39 p getPrime(512) q getPrime(512) n p * q e 0x3 pad1 beasy_problem pad2 bHow_to_so…...

[爬虫知识] IP代理

相关实战案例&#xff1a;[爬虫实战] 代理爬取&#xff1a;小白也能看懂怎么用代理 相关爬虫专栏&#xff1a;JS逆向爬虫实战 爬虫知识点合集 爬虫实战案例 引言&#xff1a;爬虫与IP封锁的攻防战 对网络爬虫而言&#xff0c;遇到的一个较棘手的问题就是封IP&#xff1a;请…...

6个月Python学习计划 Day 1 - Python 基础入门 开发环境搭建

6个月Python学习计划&#xff1a;从入门到AI实战&#xff08;前端开发者进阶指南&#xff09; &#x1f3af; 今日目标 理解 Python 的背景和用途安装 Python 开发环境熟悉基本语法&#xff1a;变量、数据类型、打印输出动手编写第一个 Python 程序 &#x1f9e0; 学习内容详…...

GraphPad Prism工作表的基本操作

《2025新书现货 GraphPad Prism图表可视化与统计数据分析&#xff08;视频教学版&#xff09;雍杨 康巧昆 清华大学出版社教材书籍 9787302686460 GraphPadPrism图表可视化 无规格》【摘要 书评 试读】- 京东图书 GraphPad Prism中包含5种工作表&#xff0c;每种工作表的基本操…...

Maven插件之docker-maven-plugin

介绍 在持续集成过程中&#xff0c;项目工程一般使用 Maven 编译打包&#xff0c;然后生成镜像&#xff0c;通过镜像上线&#xff0c;能够大大提供上线效率&#xff0c;同时能够快速动态扩容&#xff0c;快速回滚&#xff0c;着实很方便。docker-maven-plugin 插件就是为了实现…...

成年后还能学习多少知识,由大脑的这个数量决定

撰文&#xff5c;Anne Trafton 编译&#xff5c;郑添惺 审校&#xff5c;clefable 麻省理工学院&#xff08;MIT&#xff09;的一些神经科学家发现&#xff0c;成年的大脑中含有数百万个“静默突触”&#xff08;silent synapses&#xff09;。它们是神经元之间未成熟的神经突…...

Flask 会话管理:从原理到实战,深度解析 session 机制

1、Flask中session 的实现原理&#xff1a;服务器与客户端的协作 HTTP 协议是无状态的——服务器无法区分两次请求是否来自同一用户。这意味着&#xff0c;用户登录后跳转到其他页面时&#xff0c;服务器会“忘记”用户身份。 为解决这一问题&#xff0c;Web 开发中引入了会话…...

MySQL连接错误解决方案:Can‘t connect to MySQL server on ‘localhost‘ (10038)

错误描述 当您尝试连接MySQL数据库时&#xff0c;可能会遇到以下错误提示&#xff1a; 这个错误表明客户端无法连接到本地MySQL服务器。 可能的原因 MySQL服务未启动 MySQL配置问题 防火墙或安全软件阻止连接 端口被占用或未正确配置 网络连接问题 解决方案 方法一&am…...

【跨端框架检测】使用adb logcat检测Android APP使用的跨端框架方法总结

目录 Weex 跨端框架使用了uni-app的情况区分使用了uni-app还是Weex 判断使用了Xamarin判断使用了KMM框架判断使用了 ​​Ionic 框架判断使用了Cordova框架判断使用了Capacitor 框架使用了React Native框架使用了QT框架使用了Cocos框架使用了Electron 框架使用了flutter 框架使用…...

lua脚本实战—— Redis并发原子性陷阱

需求分析 对于内容类网站&#xff0c;比如用户浏览题目的答案&#xff0c;需要先登录才能追溯&#xff0c;那么可以统计用户访问频率来限制数据的爬取。 可采用分级反爬虫策略&#xff0c;先告警、再采取强制措施&#xff1a; 如果每分钟超过 10 道题&#xff0c;给管理员发…...

【MySQL】第10节|MySQL全局优化与Mysql 8.0新增特性详解

全局优化 mysql server参数 1. max_connections&#xff08;最大连接数&#xff09; 含义&#xff1a;MySQL 服务允许的最大并发连接数&#xff08;包括正在使用和空闲的连接&#xff09;。超过此限制时&#xff0c;新连接会被拒绝&#xff08;报错 Too many connections&am…...

CSS相关知识

1.清除浮动的方法 2.定位 静态定位相当于标准流 相对定位不脱离文档流&#xff0c;仍然占据原来的位置&#xff08;最频繁的作用是给绝对定位当爹&#xff09; 绝对定位脱离文档标准流&#xff0c;不再占有原来位置 3.BFC 1. 解决浮动元素导致的父容器高度塌陷 2. 阻止相邻元…...

AI扫描王APP:高效便捷的手机扫描工具,让生活更智能

AI扫描王APP是一款功能强大的手机扫描软件&#xff0c;专为追求高效、便捷的用户设计。它不仅支持文字提取和扫描翻译&#xff0c;还能进行测量&#xff0c;满足用户在不同场景下的需求。无论是办公、学习还是日常使用&#xff0c;AI扫描王都能帮助你快速完成任务&#xff0c;节…...

《仿盒马》app开发技术分享-- 原生地图展示(端云一体)

开发准备 上一节我们实现了获取当前用户的位置&#xff0c;并且成功的拿到了经纬度&#xff0c;这一节我们就要根据拿到的经纬度&#xff0c;结合我们其他的知识点来实现地图的展示。 功能分析 地图的展示&#xff0c;我们需要在管理中心先给我们对应的应用开启地图api功能&…...

Linux 操作文本文件列数据的常用命令

文章目录 Linux 操作文本文件列数据的常用命令基本列处理命令高级列处理列数据转换和排序列数据统计和分析 Linux 操作文本文件列数据的常用命令 Linux 提供了多种强大的命令来处理文本文件中的列数据&#xff0c;以下是一些最常用的命令和工具&#xff1a; 基本列处理命令 c…...