记录每次更新到仓库 —— Git 学习笔记 10

2024-09-09 05:38

本文主要是介绍记录每次更新到仓库 —— Git 学习笔记 10,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

记录每次更新到仓库

文章目录

    • 文件的状态
    • 三个区域
    • 检查当前文件状态
    • 跟踪新文件
    • 取消跟踪(un-tracking)文件
    • 重新跟踪(re-tracking)文件
    • 暂存已修改文件
    • 忽略某些文件
    • 查看已暂存和未暂存的修改
    • 提交更新
    • 跳过暂存区
    • 删除文件
    • 移动文件
    • 参考资料

咱们接着很多天以前的 取得Git仓库 这篇文章继续说。

文件的状态

不管是通过哪种方法,现在我们已经有了一个仓库,并从这个仓库中取出了所有文件的拷贝。接下来,对这些文件作些修改,在完成了一个阶段的目标之后,提交本次更新到仓库。

需要说明的是,工作目录下面的所有文件都不外乎这两种状态:已知(已跟踪)的和未知的。已跟踪的文件是指已经被纳入版本控制的文件,未知的文件又分为两种:未跟踪和和已忽略(这个以后再说)。

已跟踪的文件可分为以下几种状态:

  1. 已提交(或未修改)
  2. 已修改
  3. 已暂存

这里写图片描述

初次克隆某个仓库时,工作目录中的所有文件都属于已跟踪文件,且状态为未修改(unmodified)。在编辑过某些文件之后,Git 将这些文件标记为已修改(modified)。然后可以用"git add"命令把这些文件添加到暂存区,这时候它们的状态就是已暂存(staged);再然后用“git commit”把这些暂存的文件提交到本地仓库后,它们的状态又变成了未修改(unmodified)。

这里写图片描述

三个区域

上面是围绕着文件状态变化来说的,也可以围绕着工作目录、暂存区、本地版本库来说明。

Git 系统跟踪的文件一般有 2 种状态,未修改(或已提交)和已修改。未修改意味着工作目录下的文件内容和最近一次提交的修订内容一致,很安全地存放在版本库中;如果工作目录下的文件和最近一次提交的版本存在差异,则被认为是已修改的文件。

不过,在 Git 系统内部,还有一个被称为索引(index)或暂存区(staging area)的区域,它用来存储将要提交的信息。git add 命令用来把已修改的文件加入索引,这将导致 Git 为其生成当前版本的快照。此时这个文件的状态就是已暂存(staged)。
这里写图片描述

检查当前文件状态

要确定哪些文件当前处于什么状态,可以用 git status 命令。如果在克隆仓库之后立即执行此命令,会看到类似这样的输出:

$ git status
On branch master
nothing to commit, working directory clean

这说明你现在的工作目录是干净的。换句话说,所有已跟踪文件在上次提交后都未被修改过。此外,上面的信息还表明,当前目录下没有任何未跟踪的新文件,否则 Git 会在这里列出来。最后,还显示了当前所在的分支是 master,这是默认的分支名称(分支以后再说,这里先不用管)。

现在让我们创建一个新文件 README,内容是什么无所谓,保存后运行 git status

$ git status
On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed)
README
nothing added to commit but untracked files present (use "git add" to track)

可以看到,新建的 README 文件出现在 “Untracked files” 下面。未跟踪的文件意味着 Git 在之前的快照(或提交)中没有找到这些文件;Git 不会自动将其纳入跟踪范围,除非你明明白白地告诉它“我需要跟踪该文件”。

跟踪新文件

使用命令 git add 开始跟踪一个新文件。所以,要跟踪 README 文件,只需运行:

$ git add README

此时再运行 git status 命令,会看到:

$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: README

只要在"Changes to be committed"这行下面列出的文件,就说明是已暂存状态。如果此时提交,那么该文件此时此刻的版本将被存入仓库。在 git add 后面可以指明要跟踪的文件或目录。如果是目录,就说明要递归跟踪该目录下的所有文件及子目录。

其实 git add 的潜台词就是把目标文件的快照放入暂存区域,同时未曾跟踪过的文件标记为已跟踪。

取消跟踪(un-tracking)文件

假如想忽略某个已经跟踪的文件,可以用命令

 git rm --cached  <file>

注意,把 <file > 替换成具体的文件名。

举例:

$ git status --ignored
On branch master
Changes to be committed:(use "git reset HEAD <file>..." to unstage)modified:   world.cUntracked files:(use "git add <file>..." to include in what will be committed)oops

可以看到,world.c 是一个已经被跟踪的文件。

$ git rm --cached world.c
rm 'world.c'$ git status --ignored
On branch master
Changes to be committed:(use "git reset HEAD <file>..." to unstage)deleted:    world.cUntracked files:(use "git add <file>..." to include in what will be committed)oopsworld.c
$ ls
oops  world.c

当不再跟踪 world.c 后, 工作区中的 world.c 不受影响。

重新跟踪(re-tracking)文件

如果想跟踪一个已经被忽略的文件,可以用

 git add -f <file>

例如:

$ git add -f world.c
$ git status --ignored
On branch master
Changes to be committed:(use "git reset HEAD <file>..." to unstage)modified:   world.cUntracked files:(use "git add <file>..." to include in what will be committed)oops

暂存已修改文件

我们修改一个已跟踪的文件(我这里是 world.c),再运行 git status

$ echo "hello world" >>world.c$ git status
On branch master
Changes not staged for commit:(use "git add <file>..." to update what will be committed)(use "git checkout -- <file>..." to discard changes in working directory)modified:   world.cno changes added to commit (use "git add" and/or "git commit -a")

文件 world.c 出现在“Changes not staged for commit”下面,说明已跟踪文件的内容发生了变化,但还没有放到暂存区。现在让我们运行 git add 将 world.c 放到暂存区,然后再看看 git status 的输出。

注意: git add 命令是个多功能命令,根据目标文件的状态不同,此命令的效果也不同:可以用它开始跟踪新文件,或者把已跟踪的文件放到暂存区,还能用于合并时把有冲突的文件标记为已解决状态(这个以后再说)等。

$ git status
On branch master
Changes to be committed:(use "git reset HEAD <file>..." to unstage)modified:   world.c

现在 world.c 已暂存,下次提交时其快照就会永久储存在仓库。假设此时,你突然想起来world.c还需要再改一下,比如加一行注释。重新编辑保存后,准备提交。不过且慢,在提交之前再运行一遍 git status 看看。

$ echo "//this is comment" >>world.c$ git status
On branch master
Changes to be committed:(use "git reset HEAD <file>..." to unstage)modified:   world.cChanges not staged for commit:(use "git add <file>..." to update what will be committed)(use "git checkout -- <file>..." to discard changes in working directory)modified:   world.c

怎么回事?world.c 文件出现了两次!一次已暂存,一次未暂存,是不是 Git 搞错了?

实际上 Git 只不过暂存了你运行 git add 命令时的版本,如果现在提交,那么提交的是添加注释前的版本,而非当前工作目录中的版本。所以,运行了 git add 之后又作了修订的文件,需要重新运行 git add 把最新版本暂存起来

$ git status
On branch master
Changes to be committed:(use "git reset HEAD <file>..." to unstage)modified:   world.c

忽略某些文件

对于某些文件,我们不希望把它们纳入 Git 的管理,也不希望它们总出现在未跟踪文件列表。通常它们都是些自动生成的文件,比如日志文件、编译过程中创建的临时文件等。我们可以创建一个名为 .gitignore 的文件,在里面列出要忽略的文件模式。来看一个实际的例子:

$ cat .gitignore
*.[oa]
*~

*.[oa]告诉 Git 忽略所有以 .o 或 .a 结尾的文件。*~告诉 Git 忽略所有以波浪符(~)结尾的文件,许多文本编辑软件(比如 Emacs)都用这样的文件名保存副本。

文件 .gitignore 的格式规范如下:
• 所有空行或者以 # 开头的行都会被 Git 忽略。
• 可以使用标准的 glob 模式匹配。
• 匹配模式可以以(/)开头防止递归。
• 匹配模式可以以(/)结尾指定目录。
• 要忽略指定模式以外的文件或目录,可以在模式前加上惊叹号(!)取反。

所谓的 glob 模式是指 shell 所使用的简化了的正则表达式。

  1. 星号(*)匹配零个或多个任意字符;
  2. [abc] 匹配任何一个列在方括号中的字符(这个例子要么匹配一个 a,要么匹配一个 b,要么匹配一个 c);
  3. 问号(?)只匹配一个任意字符;
  4. 如果在方括号中使用短划线分隔两个字符,表示所有在这两个字符范围内的都可以匹配 (比如 [0-9] 表示匹配所有 0 到 9 的数字)。
  5. 使用两个星号(**) 表示匹配任意中间目录,比如a/**/z 可以匹配 a/z, a/b/z 或 a/b/c/z等。

我们再看一个 .gitignore 文件的例子:

# 忽略.a文件
*.a
# 但是跟踪 lib.a
!lib.a
# 忽略当前目录下的 TODO,但是不忽略子目录下的 TODO
/TODO
# 忽略 build 目录下的所有文件
build/
# 例如忽略 doc/notes.txt, 但是不忽略 doc/server/arch.txt
doc/*.txt
# 忽略 doc 目录下的所有 .pdf 
doc/**/*.pdf

注意:Git 允许在版本库中任何目录下有.gitignore文件。每个 .gitignore 文件都只影响该目录及其所有子目录。

由于本文是针对初学者的,所以说得略简单。如果你想了解关于 Git 忽略文件的更多内容,可以参考我的博文: 忽略某些文件

查看已暂存和未暂存的修改

如果 git status 命令的输出对于你来说过于笼统,你想知道具体修改了什么地方,可以用 git diff 命令。git diff 命令可以帮我们回答两个问题:

  1. 有哪些更新未暂存?
  2. 有哪些更新已暂存?

尽管 git status 已经通过在相应栏下列出文件名的方式回答了这2个问题,但是 git diff 将通过文件补丁的格式(合并格式)显示修改了哪些行。

比如我的工作目录下有一个 README.md 文件,里面已经有一些内容了,它的状态是未修改。现在修改它,但是不暂存。

$ echo 1234 >> README.md

运行 git diff 命令

$ git diff
diff --git a/README.md b/README.md
index 26573a9..78ea874 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,2 @@my_repo
+1234

可以清楚看到,增加了一行“1234”。要了解合并格式的 diff,可以参考我的博文 diff命令输出格式解读

如果运行

$ git add README.md

也就是把修改提交到暂存区,这时候再次运行 git diff

$ git diff

什么输出都没有,也就说明工作区的更新都已经暂存了。若要查看已暂存的更新,可以用 git diff --cached 命令。(Git 1.6.1 及更高版本还允许使用 git diff --staged,效果是相同的。)

$ git diff --cached
diff --git a/README.md b/README.md
index 26573a9..78ea874 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,2 @@my_repo
+1234$ git diff --staged
diff --git a/README.md b/README.md
index 26573a9..78ea874 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,2 @@my_repo
+1234

你也许会问,能不能比较当前工作目录和最近一次提交之间的差异。当然可以,用命令git diff HEAD,这里就不举例了。

下图列出了这三个命令的区别。

这里写图片描述

提交更新

现在的暂存区已经准备妥当可以提交了。 在此之前,请一定要确认还有什么修改过的或新建的文件还没有 git add 过,否则提交的时候不会记录这些还没暂存起来的变化。 这些修改过的文件只保留在本地磁盘。所以,每次准备提交前,先用 git status 查看下,是不是都已暂存起来了,然后再运行提交命令 git commit

$ git commit

这种方式会启动文本编辑器以便输入本次提交的说明。默认会启用 shell 的环境变量 $EDITOR 所指定的软件,一般都是 vim 或 emacs。当然也可以使用 git config --global core.editor 命令设定你喜欢的编辑器。比如

$ git config --global core.editor "emacs"

我是Windows操作系统,用命令 git config --list查了一下,我的配置是

core.editor='d:\PF\Notepad++\notepad++.exe' -multiInst -notabbar -nosession -noPlugin

可见,我用的软件是 notepad++.

当我运行 git commit命令后,编辑器会显示类似下面的文本信息:

这里写图片描述

可以看到,默认的提交消息包含最后一次运行 git status 的输出,放在注释行里,另外开头还有一空行,供我们输入提交说明。退出编辑器时,Git 会丢掉注释行,用输入的信息生成一次提交。

另外,也可以在 git commit 命令后添加 -m 选项,将提交信息与命令放在同一行,如下所示:

$ git commit -m "initialize"
[master 0b6ab8c] initialize1 file changed, 1 deletion(-)delete mode 100644 hello.c

可以看到,Git 会告诉我们,当前是在哪个分支(master)提交的,本次提交的 SHA-1 校验和是什么(0b6ab8c),以及在本次提交中,有多少文件修订过,多少行添加和删改过。

请记住,提交时写入仓库的是放在暂存区的快照。任何还未暂存的修改仍然在磁盘上,可以在以后暂存并提交。

每一次进行提交操作,都是对项目作一次快照,以后可以退回到这个状态,或者把某两个提交进行比较。

跳过暂存区

尽管使用暂存区可以精心准备每一次提交,但有时候显得麻烦。 Git 提供了一个跳过使用暂存区的方式, 只要在提交的时候,给 git commit 加上 -a 选项,Git 就会自动把所有已经跟踪过的文件暂存起来一并提交,从而跳过 git add 步骤:

例如,我修改了一个文件 change_log.md,但是没有暂存

$ git status
On branch master
Changes not staged for commit:(use "git add <file>..." to update what will be committed)(use "git checkout -- <file>..." to discard changes in working directory)modified:   change_log.mdno changes added to commit (use "git add" and/or "git commit -a")

我直接提交:

$ git commit -a -m "commit change log skip the index"
[master 32ee0ac] commit change log skip the index1 file changed, 1 insertion(+)

提交成功了。

注意,这种方法仅对已经跟踪的文件有效,如果是 untracked 的文件,是无法提交的。比如

$ touch change_log.md
$ git status
On branch master
Untracked files:(use "git add <file>..." to include in what will be committed)change_log.mdnothing added to commit but untracked files present (use "git add" to track)

这时候,我试着提交:

$ git commit -a -m "add change log"
On branch master
Untracked files:change_log.mdnothing added to commit but untracked files present

你瞧,提交失败了,Git 说没有东西可提交。

删除文件

在 Git中,删除也是一个修改操作。我们先添加一个新文件test.txt到Git并且提交:

$ touch test.txt
$ git add test.txt
$ git commit -m "add test.txt"
[master 92c6e9d] add test.txt1 file changed, 1 insertion(+)create mode 100644 test.txt

一般情况下,我们会用rm命令删除:

$ rm test.txt

这个时候,Git 知道你删除了该文件。因此,工作区和版本库就不一致了,用git status命令查看一下:

$ git status
On branch master
Changes not staged for commit:(use "git add/rm <file>..." to update what will be committed)(use "git checkout -- <file>..." to discard changes in working directory)deleted:    test.txtno changes added to commit (use "git add" and/or "git commit -a")

现在你有两个选择:

  1. 确实要从版本库中删除该文件
  2. 误删了,想把这个文件找回来

对于1,用命令git rm删掉,并且git commit

$ git rm test.txt
rm 'test.txt'$ git commit -m "rm test.txt"
[master 6c0b39a] rm test.txt1 file changed, 0 insertions(+), 0 deletions(-)delete mode 100644 test.txt

现在,文件就从版本库中被删除了。

对于2,可以用git checkout -- <file>把文件从版本库里找回来。例如:

$ git checkout -- test.txt

这里的git checkout其实是用版本库里的版本来更新索引,同时覆盖工作目录中对应的文件,无论工作区的文件是被修改还是被删除,都可以“一键还原”。

其实,如果确实要从版本库删除某个文件,只需要2个步骤。

git rm <file>
git commit

git rm表示从工作区删除文件,并且把这个变更暂存(就像 git add 一样);git commit表示在版本库实现这个变更。

需要说明的是,如果文件修改了,且修改未提交,删除就会失败。例如:

$ echo 11 >>oops
$ git status
On branch master
Changes not staged for commit:(use "git add <file>..." to update what will be committed)(use "git checkout -- <file>..." to discard changes in working directory)modified:   oopsno changes added to commit (use "git add" and/or "git commit -a")$ git rm oops
error: the following file has local modifications:oops
(use --cached to keep the file, or -f to force removal)
# 以上是未暂存的情况$ git add oops$ git rm oops
error: the following file has changes staged in the index:oops
(use --cached to keep the file, or -f to force removal)
# 以上是暂存了但是未提交的情况

这时候需要加 -f 强行删除。

$ git rm oops -f
rm 'oops'$ git status
On branch master
Changes to be committed:(use "git reset HEAD <file>..." to unstage)deleted:    oops$ ls

移动文件

在 Git 中可以执行下面的命令重命名文件:

git mv <old_file> <new_file>

例如:

$ git mv banana.c grape.c$ git status
On branch master
Changes to be committed:(use "git reset HEAD <file>..." to unstage)renamed:    banana.c -> grape.c$ git commit -m xx
[master 0c89153] xx1 file changed, 0 insertions(+), 0 deletions(-)rename banana.c => grape.c (100%)

参考资料

【1】《精通Git(第2版)》,Scott Chacon & Ben Straub,人民邮电出版社

【2】 https://www.liaoxuefeng.com/

这篇关于记录每次更新到仓库 —— Git 学习笔记 10的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1150317

相关文章

IDEA中Git版本回退的两种实现方案

《IDEA中Git版本回退的两种实现方案》作为开发者,代码版本回退是日常高频操作,IntelliJIDEA集成了强大的Git工具链,但面对reset和revert两种核心回退方案,许多开发者仍存在选择... 目录一、版本回退前置知识二、Reset方案:整体改写历史1、IDEA图形化操作(推荐)1.1、查看提

一文详解SQL Server如何跟踪自动统计信息更新

《一文详解SQLServer如何跟踪自动统计信息更新》SQLServer数据库中,我们都清楚统计信息对于优化器来说非常重要,所以本文就来和大家简单聊一聊SQLServer如何跟踪自动统计信息更新吧... SQL Server数据库中,我们都清楚统计信息对于优化器来说非常重要。一般情况下,我们会开启"自动更新

Spring Boot中定时任务Cron表达式的终极指南最佳实践记录

《SpringBoot中定时任务Cron表达式的终极指南最佳实践记录》本文详细介绍了SpringBoot中定时任务的实现方法,特别是Cron表达式的使用技巧和高级用法,从基础语法到复杂场景,从快速启... 目录一、Cron表达式基础1.1 Cron表达式结构1.2 核心语法规则二、Spring Boot中定

Java进阶学习之如何开启远程调式

《Java进阶学习之如何开启远程调式》Java开发中的远程调试是一项至关重要的技能,特别是在处理生产环境的问题或者协作开发时,:本文主要介绍Java进阶学习之如何开启远程调式的相关资料,需要的朋友... 目录概述Java远程调试的开启与底层原理开启Java远程调试底层原理JVM参数总结&nbsMbKKXJx

国内环境搭建私有知识问答库踩坑记录(ollama+deepseek+ragflow)

《国内环境搭建私有知识问答库踩坑记录(ollama+deepseek+ragflow)》本文给大家利用deepseek模型搭建私有知识问答库的详细步骤和遇到的问题及解决办法,感兴趣的朋友一起看看吧... 目录1. 第1步大家在安装完ollama后,需要到系统环境变量中添加两个变量2. 第3步 “在cmd中

Git如何修改已提交人的用户名和邮箱

《Git如何修改已提交人的用户名和邮箱》文章介绍了如何修改Git已提交人的用户名和邮箱,包括注意事项和具体步骤,确保操作正确无误... 目录git修改已提交人的用户名和邮箱前言第一步第二步总结git修改已提交人的用户名和邮箱前言需注意以下两点内容:需要在顶层目录下(php就是 .git 文件夹所在的目

Spring Retry 实现乐观锁重试实践记录

《SpringRetry实现乐观锁重试实践记录》本文介绍了在秒杀商品SKU表中使用乐观锁和MybatisPlus配置乐观锁的方法,并分析了测试环境和生产环境的隔离级别对乐观锁的影响,通过简单验证,... 目录一、场景分析 二、简单验证 2.1、可重复读 2.2、读已提交 三、最佳实践 3.1、配置重试模板

在 Spring Boot 中使用异步线程时的 HttpServletRequest 复用问题记录

《在SpringBoot中使用异步线程时的HttpServletRequest复用问题记录》文章讨论了在SpringBoot中使用异步线程时,由于HttpServletRequest复用导致... 目录一、问题描述:异步线程操作导致请求复用时 Cookie 解析失败1. 场景背景2. 问题根源二、问题详细分

Java深度学习库DJL实现Python的NumPy方式

《Java深度学习库DJL实现Python的NumPy方式》本文介绍了DJL库的背景和基本功能,包括NDArray的创建、数学运算、数据获取和设置等,同时,还展示了如何使用NDArray进行数据预处理... 目录1 NDArray 的背景介绍1.1 架构2 JavaDJL使用2.1 安装DJL2.2 基本操

关于Spring @Bean 相同加载顺序不同结果不同的问题记录

《关于Spring@Bean相同加载顺序不同结果不同的问题记录》本文主要探讨了在Spring5.1.3.RELEASE版本下,当有两个全注解类定义相同类型的Bean时,由于加载顺序不同,最终生成的... 目录问题说明测试输出1测试输出2@Bean注解的BeanDefiChina编程nition加入时机总结问题说明