Git 文件状态管理:add、commit、status 和 diff
文章目录Git 文件状态管理add、commit、status 和 diff一、Git 管理的是修改而不只是文件二、文件在 Git 中的常见状态1. 未跟踪状态Untracked2. 已暂存状态Staged3. 已提交状态Committed4. 已修改但未暂存Modified三、git add 和 git commit暂存与提交1. git add 的作用2. git commit 的作用3. 多次 git add 可以对应一次 git commit四、一个容易踩坑的例子只提交了 add 过的文件五、git status看懂当前仓库状态常见状态总结六、git diff查看文件具体改了什么git status 和 git diff 的区别git diff HEAD -- file七、修改文件后的推荐提交流程1. 查看当前状态2. 查看具体差异3. 加入暂存区4. 再次查看状态5. 提交到本地仓库6. 确认工作区干净八、git log 和 commit id查看提交历史commit id 为什么不是简单数字九、从 .git 目录理解 add、commit 和对象存储1. index暂存区2. HEAD当前分支指针3. refs/heads/master当前分支最新提交4. objectsGit 对象库5. commit、tree、blob 对象总结Git 文件状态管理add、commit、status 和 diff前面已经整理了如何创建 Git 本地仓库也知道了 Git 中几个非常重要的区域工作区暂存区版本库这一篇继续往下走重点整理 Git 中最常用的几个命令git addgit commitgit statusgit diffgit log这些命令看起来简单但它们是 Git 日常使用的核心。尤其是git add和git commit很多刚开始学习 Git 的人会把它们混在一起。其实这两个命令分别对应不同阶段git add 把修改放入暂存区 git commit 把暂存区内容提交到本地仓库理解清楚这一点后面学习版本回退、撤销修改、分支合并时会轻松很多。一、Git 管理的是修改而不只是文件刚开始学习 Git 时很容易以为 Git 管理的是文件。比如创建了一个ReadMe文件然后执行gitaddReadMegitcommit-mcommit my first file看起来好像 Git 管理的是这个文件本身。但更准确地说Git 跟踪并管理的是文件的变化也就是“修改”。什么是修改下面这些都算修改新增一个文件删除一个文件修改文件中的一行内容删除文件中的一行内容修改某几个字符新增一个空文件文件改名文件权限变化。所以 Git 关注的不是“你有没有这个文件”而是和上一次提交相比当前工作区发生了哪些变化。这也是为什么git status和git diff很重要。git status用来查看当前有哪些变化git diff用来查看具体变化内容。二、文件在 Git 中的常见状态一个文件在 Git 仓库中通常会经历几个状态。最常见的有下面几类。1. 未跟踪状态Untracked新建一个文件但还没有执行git add这个文件就是未跟踪状态。比如touchfile1gitstatus可能会看到类似提示这表示 Git 发现了file1但它还没有被纳入 Git 管理。简单来说文件出现在工作区不代表它已经进入 Git 管理。2. 已暂存状态Staged当执行gitaddfile1文件就会进入暂存区。这时再查看状态gitstatus可能会看到这说明file1已经准备好进入下一次提交。也就是说暂存区保存的是下一次git commit要提交的内容。3. 已提交状态Committed执行gitcommit-madd file1暂存区中的内容就会被提交到本地仓库。提交之后这次修改就真正进入了版本库。这时再执行gitstatus如果没有新的修改通常会看到nothing to commit, working tree clean这表示当前工作区是干净的没有需要提交的新变化。4. 已修改但未暂存Modified如果一个已经被 Git 管理的文件发生了修改但还没有执行git add它就是已修改但未暂存状态。比如修改ReadMe文件后执行gitstatus可能会看到Changes not stagedforcommit:(usegit add file...to update what will be committed)modified: ReadMe这表示 Git 知道ReadMe被修改了但这个修改还没有加入暂存区。三、git add 和 git commit暂存与提交git add和git commit是 Git 本地操作中最核心的一组命令。1. git add 的作用git add的作用是把工作区中的修改添加到暂存区。常见用法有几种。添加单个文件gitaddReadMe添加多个文件gitaddfile1 file2 file3添加某个目录gitaddsrc添加当前目录下所有修改gitadd.git add .很方便但也容易把不想提交的文件一起加进去。所以在执行git add .前最好先看一下gitstatus确认当前有哪些文件发生了变化。2. git commit 的作用git commit的作用是把暂存区中的内容提交到本地仓库。最常见用法是gitcommit-m提交说明比如gitcommit-madd ReadMe file这里的-m后面是提交说明。提交说明不是给 Git 看的而是给人看的。以后查看历史记录时我们需要通过提交说明快速判断某次提交做了什么。不推荐这样写gitcommit-mupdate因为update太笼统了过几天再看根本不知道更新了什么。更推荐写成gitcommit-madd user login pagegitcommit-mfix login error messagegitcommit-madd order query api好的提交说明应该尽量做到简洁明确能说明本次提交的目的。3. 多次 git add 可以对应一次 git commit暂存区的一个重要作用是可以先收集多次修改然后一次性提交。比如创建三个文件touchfile1 file2 file3分别加入暂存区gitaddfile1gitaddfile2gitaddfile3最后一次性提交gitcommit-madd three files提交成功后可能会看到类似输出[master 23807c5]addthree files3files changed,0insertions(),0deletions(-)create mode100644file1 create mode100644file2 create mode100644file3这说明三个文件被作为同一次提交保存到了版本库中。这里要重点理解git commit提交的是暂存区里的内容而不是工作区里的全部内容。四、一个容易踩坑的例子只提交了 add 过的文件来看一个很容易踩坑的例子。先创建file4touchfile4把file4加入暂存区gitaddfile4然后再创建一个file5touchfile5此时直接提交gitcommit-madd file提交成功后可能会看到[master 3d406c0]addfile1filechanged,0insertions(),0deletions(-)create mode100644file4这里明明创建了两个文件file4和file5为什么只提交了一个文件原因很简单只有file4执行过git add进入了暂存区file5只是存在于工作区并没有进入暂存区。所以这次git commit只提交了file4。如果要提交file5还需要继续执行gitaddfile5gitcommit-madd file5这个例子非常重要因为它说明Git 不会因为文件存在于工作区就自动把它提交到版本库。五、git status看懂当前仓库状态git status是日常使用 Git 时非常重要的命令。它的作用是查看当前工作区和暂存区的状态。比如修改ReadMe文件后执行gitstatus可能会看到On branch master Changes not stagedforcommit:(usegit add file...to update what will be committed)(usegit restore file...to discard changesinworking directory)modified: ReadMe no changes added to commit(usegit addand/orgit commit -a)这段信息可以这样理解On branch master表示当前位于master分支。Changes not staged for commit表示有修改还没有加入暂存区。modified: ReadMe表示ReadMe文件被修改了。no changes added to commit表示当前暂存区没有可提交内容。所以这时如果想提交ReadMe的修改需要先执行gitaddReadMe然后再提交gitcommit-mmodify ReadMe常见状态总结如果看到nothing to commit, working tree clean表示当前没有需要提交的修改。如果看到Untracked files: file1表示file1是新文件但还没有被 Git 跟踪。如果看到Changes not stagedforcommit: modified: ReadMe表示文件已修改但还没有加入暂存区。如果看到Changes to be committed: modified: ReadMe表示修改已经进入暂存区可以提交。六、git diff查看文件具体改了什么git status只能告诉我们哪些文件发生了变化但不能告诉我们具体改了哪里。如果想查看具体修改内容就需要使用gitdiff或者查看某个文件gitdiffReadMe注意git diff 只能对比已经被 git跟踪的文件的修改。对于全新的文件git没有旧版本可以对比所以 git diff 什么都不显示。解决方法 先把文件添加到 git 跟踪之后你再修改 ReadMegit diff 就能看到变化了。假设ReadMe原来是hello bit hello bit现在修改成hello bit hello git hello world执行gitdiffReadMe可能会看到类似输出diff --git a/ReadMe b/ReadMe index 9c9e1f0..4a97140 100644 --- a/ReadMe b/ReadMe -1,2 1,3 hello bit -hello bit hello git hello world这段 diff 信息可以这样理解-hello bit前面带-表示这一行被删除了。hello git hello world前面带表示这些行是新增的。所以这次修改可以总结为删除了一行hello bit新增了一行hello git新增了一行hello world。git status 和 git diff 的区别它们的区别可以简单理解为git status告诉你哪些文件变了 git diff 告诉你文件具体怎么变了真实开发中一般建议提交前至少执行一次gitstatus如果发现有修改再执行gitdiff确认修改内容没问题后再提交gitadd.gitcommit-mxxx提交前检查差异可以避免把调试代码、临时文件、错误修改一起提交进去。git diff HEAD – file除了普通的git diff还有一种常见写法gitdiffHEAD -- ReadMe它表示查看当前工作区文件和版本库中最新版本之间的差异。这里先简单理解HEAD可以先理解为当前版本ReadMe是要比较的文件--用来分隔版本和文件路径避免歧义。刚开始不需要把所有细节都记死可以先记住如果想看某个文件相对于当前版本到底改了什么可以用git diff HEAD -- 文件名。七、修改文件后的推荐提交流程修改文件后比较推荐的完整提交流程是gitstatusgitdiffReadMegitaddReadMegitstatusgitcommit-mmodify ReadMe filegitstatus逐步来看1. 查看当前状态gitstatus确认有哪些文件发生变化。2. 查看具体差异gitdiffReadMe确认这次修改是否符合预期。3. 加入暂存区gitaddReadMe把修改加入暂存区。4. 再次查看状态gitstatus此时可能会看到Changes to be committed:(usegit restore --staged file...to unstage)modified: ReadMe表示修改已经进入暂存区等待提交。5. 提交到本地仓库gitcommit-mmodify ReadMe file提交成功后可能会看到[master 94da695]modify ReadMefile1filechanged,2insertions(),1deletion(-)这表示1 个文件发生变化新增了 2 行删除了 1 行。6. 确认工作区干净gitstatus如果看到nothing to commit, working tree clean说明当前没有待提交修改。八、git log 和 commit id查看提交历史提交完成后可以使用gitlog查看历史提交。示例commit 23807c536969cd886c4fb624b997ca575756eed6(HEAD -master)Author: zhangsanzhangsanexample.comDate: Sat May611:27:3220230800addthree files commit c61428926f3853d4ec6dde904415b0e6c1dabcc6 Author: zhangsanzhangsanexample.comDate: Sat May611:25:5020230800 commit my firstfilegit log默认会按时间从近到远显示提交历史。每条提交通常包含commit id作者提交时间提交说明其中commit id是 Git 为每次提交生成的唯一标识。它不是简单的1、2、3递增数字而是一个很长的哈希值。比如23807c536969cd886c4fb624b997ca575756eed6后面做版本回退时经常会用到commit id。如果觉得git log输出太长可以使用gitlog--prettyoneline输出会更加简洁commit id 为什么不是简单数字Git 的commit id是通过哈希算法计算出来的一个非常大的十六进制数字。这么设计有几个好处几乎可以保证每次提交的 ID 唯一适合分布式协作场景不依赖一个中心服务器来分配版本号可以通过内容生成标识。现在不需要深入哈希算法只要先知道每次提交都会生成一个唯一的 commit id它是后面定位历史版本的重要依据。九、从 .git 目录理解 add、commit 和对象存储如果只停留在命令层面Git 可能会显得有点抽象。其实可以通过.git目录理解这些命令背后的变化。本地仓库中有几个比较关键的文件或目录.git/ ├── HEAD ├── index ├── objects └── refs/ └── heads/ └── master1. index暂存区.git/index可以简单理解为暂存区。当执行gitaddReadMe暂存区会被更新。也就是说git add会影响.git/index。2. HEAD当前分支指针查看.git/HEADcat.git/HEAD可能会看到ref: refs/heads/master这表示当前HEAD指向master分支。现在不需要深入分支只要先理解HEAD 和当前所在分支、当前版本有关。3. refs/heads/master当前分支最新提交查看cat.git/refs/heads/master可能会看到23807c536969cd886c4fb624b997ca575756eed6这表示master分支当前指向这个提交 ID。4. objectsGit 对象库.git/objects保存 Git 的对象数据。提交、目录树、文件内容最终都会以对象形式保存在这里。可以简单理解为objects 目录保存了 Git 维护版本历史所需的底层数据。5. commit、tree、blob 对象Git 对象一般不能直接打开看因为它们是经过 Git 特殊方式存储的。不过可以使用gitcat-file-pcommit_id查看某个对象内容。比如gitcat-file-p23807c536969cd886c4fb624b997ca575756eed6可能会看到tree 830a8c9feefbdc098bbae2cdc25e5034ce1920d7 parent c61428926f3853d4ec6dde904415b0e6c1dabcc6 author zhangsanzhangsanexample.com16833436520800 committer zhangsanzhangsanexample.com16833436520800addthree files这里可以看到几个信息tree这次提交对应的目录树对象parent上一次提交author作者committer提交者最后一行是提交说明。继续查看tree对象gitcat-file-p830a8c9feefbdc098bbae2cdc25e5034ce1920d7可能会看到100644blob 9c9e1f0f6bff3015df71a0963004476f5e6cfd54 ReadMe100644blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 file1100644blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 file2100644blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 file3这里的blob可以理解为文件内容对象。继续查看ReadMe对应的blobgitcat-file-p9c9e1f0f6bff3015df71a0963004476f5e6cfd54可能会看到hello bit hello bit这说明 Git 确实把文件内容记录到了对象库中。入门阶段不需要把 Git 对象模型完全吃透但这个例子能帮助我们建立一个重要认识Git 的提交并不是简单复制文件而是通过 commit、tree、blob 等对象组织项目快照。总结这一篇主要整理了 Git 文件状态管理相关内容。重点包括Git 管理的是修改而不仅仅是文件文件在 Git 中常见的几种状态git add的作用git commit的作用多次git add可以对应一次git commit没有进入暂存区的文件不会被提交git status如何查看仓库状态git diff如何查看具体差异修改文件后的推荐提交流程git log如何查看历史提交commit id的作用.git/index、.git/HEAD、.git/refs、.git/objects的基本作用commit、tree、blob对象之间的关系。总结先用 git status 看状态再用 git diff 看具体修改确认无误后 git add最后 git commit。这个流程是以后每天都会用到的基础操作。下一篇会继续整理 Git 中非常重要的能力版本回退与撤销修改。重点会包括git reset是什么--soft、--mixed、--hard有什么区别HEAD、HEAD^、HEAD~n怎么理解如何回退到历史版本如何撤销工作区和暂存区的修改删除文件后如何恢复。