在使用中思考git哲学

371 阅读5分钟

[TOC]

一、理解git很重要

其实 git 与 编程语言差不多,它们都要求使用者能够知道自己在干什么

1.1、.git目录

它是git的核心,由以下几个构成

构成说明
config项目的配置文件
description无需理会
info无需理会
hooks放置钩子脚本
HEAD指向当前所在分支
objects内容数据库(所有的内容都在这里)
refs存储提交对象的指针

在这里我们重点讲解一下objects目录,这个目录存储3种数据类型,分别是数据对象(blob)树对象(tree)提交对象(commit)

blob
这个是objects目录里最基础的数据类型,eg一个例子:

   git init
   touch new1.js
   vim new1.js
   git add new1.js                             // 执行后可以看一看objects目录
   find .git/objects -type f                   // 查看objects目录下所有的文件
   git cat-file -t yourselfHash                // 查看特定文件的数据类型(blob)

如果你是跟着上面操作来的,那么此时你应该会在终端里看到blob; 这说明我们add等一些操作是会把我们的工作目录下的相应文件转变为objects的blob类型进行存储。此时我们就可以简单的对一个文件进行版本控制了,你不妨编辑一下new1.js文件,然后执行下面的命令:

   vim new1.js                                 // 再次编辑new1文件
   git add new1.js                             // 添加至暂存区(下面会有讲)
   git cat-file -p [上一个hash] > new1.js      // 将文件内容恢复至上一个hash值的内容

走到这里想必大家已经发现一些端倪,虽然说可以进行版本控制,但是代价有些大(需要记住每一个hash值),并且我们不知道hash对应的是哪个文件,所以tree它带着骄傲的步伐走来了.....

tree
作用:让每个hash值与工作目录里的文件名对应。
请执行下面的命令:

   git add new1.js                             // 此时假设hash: a1...9860
   git cat-file -p a1...9860                   // 此时只会输出blob的内容
   git commit -m "first commit"                // 生成a1...9860的树对象(hash: a2...9860)

执行完上述命令,在objects目录下会生成3个文件,其中包括a1...9860a2...9860;剩下一个假设为a3...9860文件。现在我们来看一下这三个文件夹:

   git cat-file -t a1...9860                  // blob
   git cat-file -t a2...9860                  // tree
   git cat-file -t a3...9860                  // commit
   
   git cat-file -p a1...9860                  // new1.js文件的内容
   git cat-file -p a2...9860                  // 10064 blob a1...9860 new1.js
   git cat-file -p a3...9860                  // 见下面commit
   
   git cat-file -p master^{tree}              // 查看master分支上最新的提交所指向的树对象 

commit
下面列出了commit新的结构,注意一下里面包含了上一次提交的信息(parent)

commit信息.png

1.2、git查看当前状态

最常用的命令:git status

1.2.1、三棵树之间的状态

git三棵树之间的状态.png

解释如下

工作区里的文件通过git add 命令被保存在索引区中(此时的文件被被打上了stage暂存的状态),再通过git commit命令让HEAD指针指向索引区里最新的地址所对应的树指针。

1.2.2、文件的状态

git文件的状态.png

解释如下

  • 我们在本地创建一个项目,这个项目里有3个文件,分贝时index1.js、index2.js、index3.js;
  • 运行git add命令,此时所有的文件的状态都是staged(暂存)。
  • 运行git commit命令,此时所有文件的状态都是unmodified(未修改)。
  • 此时修改index1.js文件,index1.js的文件状态变更为Modified(修改)。
  • 运行git add 命令,此时所有文件的状态又变为staged(暂存)。

二、切换分支前思考一下

新分支的内容是基于谁的?会产生commit吗?

如果你当前所在的分支是A,此时你 git checkout -b C, 那么C分支上的内容就是A分支上最后一次commit的代码;并不会产生新的commit。

如果A分支一直没有commit,会发生什么情况?

1、要小心,会丢代码的。2、这种情况下分支就没有意义了。

三、合并分支前思考一下

3.1、对本地的分支要有清晰的认知

这个要求使用者能够了解git合并策略以及知道自己的本地分支都有什么特色,这样在你合并的时候出现了问题你才能知道为什么会出错以及解决的方案。

3.2、认真权衡一下commit与stash

这两种方式都能够达到存储代码的作用,不过它俩各有千秋,commit描述的好,回滚的代价就越小;stash能够在任何时候任何分支下被pop出来,在使用上你一定要思考一下即将被stash的代码是否被add过,否则你的代码会出错的。

四、做好回滚的准备

reflog有时也是一个比较好的选择,这就要求我们的commit信息必须要规范,才能让我们的代价最小化。最常见的情形就是push了不该push的东西。

五、修改commit信息的几种情况

5.1、修改最后一次push的commit信息

   git commit --amend
   git push origin branch -f

5.2、修改最后一次commit,但没push的信息

   git commit -am "描述的信息"

六、总结

写文章一定要一气呵成,这篇文章在我的草稿箱里搁置了很长时间,以至于我自己都忘记了当时要写的一些,以后想起来再补充吧。