git学习——Git 基础要点【转】

图片 1image.png

简介

前一节介绍了add命令–将当前工作目录的修改添加至暂存区,那么存储至暂存区后应当及时交由Git数据库进行版本管理,这时就是此篇文章需要介绍的commit命令大展身手的时候了!

简介

前两篇分别介绍Git版本控制系统和Git仓库的一些知识,从本章起将正式深入Git的使用;

在第一篇文章《Git系列–初识》中提到了文件状态的几种类型,除了已提交状态之外,Git工作目录下不外乎就两种文件状态:已跟踪或未跟踪。

  1. 已跟踪:是指那些被纳入了版本控制的文件,在上一次快照中有它们的记录,在工作一段时间后,它们的状态可能处于未修改,已修改或已放入暂存区。初次克隆某个仓库的时候,工作目录中的所有文件都属于已跟踪文件,并处于未修改状态。
  2. 未跟踪:工作目录中除已跟踪文件以外的所有其它文件都属于未跟踪文件,它们既不存在于上次快照的记录中,也没有放入暂存区。

图片 2

文件的状态变化周期

从上图中可以看出无论是Untracked或Modified状态的文件最终都需要转换成Staged状态的文件才能被Git管理,一般称Staged状态的文件为存入暂存区的文件。

转自:

git diff 提交内容比较

从https://git.oschina.net/minasia/GitTest.git
克隆一个项目或者自己手动创建一个git项目(上篇文章已讲解)

git clone https://git.oschina.net/minasia/GitTest.git
cd GitTest

进入到项目中,添加一个文件,编辑一个文件

$ echo 'abc' >> file1
$ echo 'new file ' >> newFile

查看当前git状态

$ git status
    On branch master
    Your branch is up-to-date with 'origin/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:   file1

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

        newFile

    no changes added to commit (use "git add" and/or "git commit -a")

但是git status
命令只能查看哪些文件发生了变化,无法查看具体内容的变化。如何查看修改的文件内容呢,那就需要使用git
diff
命令。git diff命令的作用是比较修改的或提交的文件内容。

diff --git a/file1 b/file1
index e4b01c6..608842c 100644
--- a/file1
+++ b/file1
@@ -3,3 +3,4 @@ file1

 aaa
 aa
+abc
~
~
~
~
~
~
~
(END)

上面的命令执行后需要使用q退出。命令输出当前工作目录中修改的内容,并不包含新加文件,请注意这些内容还没有添加到本地缓存区。

将修改内容添加到本地缓存区,通配符可以把当前目录下所有修改的新增的文件都自动添加:

$ git add *

再执行git
diff会发现没有任何内容输出,说明当前目录的修改都被添加到了缓存区,如何查看缓存区内与上次提交之间的差别呢?需要使用–cached参数:

$ git diff --cached

diff --git a/file1 b/file1
index e4b01c6..608842c 100644
--- a/file1
+++ b/file1
@@ -3,3 +3,4 @@ file1

 aaa
 aa
+abc
diff --git a/newFile b/newFile
new file mode 100644
index 0000000..fa49b07
--- /dev/null
+++ b/newFile
@@ -0,0 +1 @@
+new file

最后提交代码

$ git commit -m '提交代码' 

提交后git diff与git diff –cached都不会有任何输出了。

Git是目前世界上最先进的分布式版本控制系统,也是使用最广泛的版本控制。在大家眼里,如果公司有人连git都不会用,或者老是问题,代码都不会拉提交,合并出各种问题,那么这个人十之八九就是个新手。那么,要摆脱被视为新手的眼光,就要熟用git,github或sourcetree等。

commit提交

commit顾名思义为提交,其作用是将暂存区的内容提交至Git本地数据库,注意,每次提交都仅作用于当前分支

1.语法

git commit [options] ...(更多参数详见:git-commit)

2.提交内容

git进行提交操作时会保存一个提交对象,包含如下内容:

  • 指向暂存内容快照的指针(暂存操作会为每一个文件使用SHA-1
    哈希算法计算校验和,生成一个blob对象)
  • 作者的姓名和邮箱
  • 提交时输入的信息以及指向它的父对象的指针(首次提交产生的提交对象没有父对象,普通提交操作产生的提交对象有一个父对象,而由多个分支合并产生的提交对象有多个父对象)

status

在正式使用add命令之前,在这里先引入status命令,其作用为检查当前文件状态;一般的,Git工作目录下的文件除上述介绍的几种文件状态之外,还有一种特殊的状态,即未更改状态–代表所有已跟踪文件在上次提交后都未被更改过。

语法为:git status

简单地说,Git
究竟是怎样的一个系统呢?请注意,接下来的内容非常重要,若是理解了 Git
的思想和基本的工作原理,用起来就会知其所以然,游刃有余。在开始学习 Git
的时候,请不要尝试把各种概念和其他的版本控制系统诸如 Subversion 和
Perforce 等相比拟,否则容易混淆每个操作的实际意义。Git
在保存和处理各种信息的时候,虽然操作起来的命令形式非常相近,但它与其他版本控制系统的做法颇为不同。理解这些差异将有助于你准确地使用
Git 提供的各种工具。

git diff 分支比较
# 创建分支
$ git branch newBranch
# 切换分支
$ git checkout newBranch
# 修改文件
$ echo 'aaaaa' >> file1
$ echo 'new new file' >> NewFile1
# 添加到缓冲区
$ git add *
# 提交
$ git commit -m '提交'

查看master分支与newBranch分支之间的差别

$ git diff master

diff --git a/NewFile1 b/NewFile1
new file mode 100644
index 0000000..e2fbd00
--- /dev/null
+++ b/NewFile1
@@ -0,0 +1 @@
+new new file
diff --git a/file1 b/file1
index e4b01c6..f2ece01 100644
--- a/file1
+++ b/file1
@@ -3,3 +3,5 @@ file1

 aaa
 aa
+abc
+aaaaa
diff --git a/file2 b/file2
index 3213394..bc65a8d 100644
--- a/file2
+++ b/file2
@@ -1,2 +1,3 @@
 file2
 edit file2

git diff
是一个难以置信的有用的工具,可以找出你项目上任意两个提交点间的差异。可以使用git
help diff详细查看其他参数和功能。

下面,我就用一个新项目从无到有地进行各种git操作,一步一截图,可边看边自己做。

初级使用

使用add命令我们已经将当前工作目录所有的修改都已经添加进暂存区了(可用git status确认是否已经添加进暂存区),之后运行提交命令:

➜  test git:(master) ✗ git commit -m "first commit"
[master (root-commit) 6fffa3a] first commit
 1 file changed, 1 insertion(+)
 create mode 100644 test.txt
➜  test git:(master) git log
commit 6fffa3a925f1454195a297c7b5373c273eeaa5aa
Author: zouziwen <zouziwen@meituan.com>
Date:   Mon May 8 17:35:28 2017 +0800

    first commit

从commit执行后返回的信息可得出本次提交时在master分支,commit-id为6fffa3a,commit-message为first
commit,一个文件被插入;并且如上例,可通过git
log来查询当前工作目录的提交历史

add

add命令在Git版本控制中其含义是将所有Untracked和Unstaged的文件放入暂存区,暂存区的文件即可被Git跟踪管理的文件。

直接快照,而非比较差异

Git 和其他版本控制系统的主要差别在于,Git
只关心文件数据的整体是否发生变化,而大多数其他系统则只关心文件内容的具体差异。这类系统(CVS,Subversion,Perforce,Bazaar
等等)每次记录有哪些文件作了更新,以及都更新了哪些行的什么内容,请看图
1-4。

图片 3

Git 并不保存这些前后变化的差异数据。实际上,Git
更像是把变化的文件作快照后,记录在一个微型的文件系统中。每次提交更新时,它会纵览一遍所有文件的指纹信息并对文件作一快照,然后保存一个指向这次快照的索引。为提高性能,若文件没有变化,Git
不会再次保存,而只对上次保存的快照作一连接。Git 的工作方式就像图 1-5
所示。

图片 4

这是 Git
同其他系统的重要区别。它完全颠覆了传统版本控制的套路,并对各个环节的实现方式作了新的设计。Git
更像是个小型的文件系统,但它同时还提供了许多以此为基础的超强工具,而不只是一个简单的
VCS。稍后在第三章讨论 Git
分支管理的时候,我们会再看看这样的设计究竟会带来哪些好处。

集中式vs分布式

集中式版本控制系统,版本库是集中存放在中央服务器的,集中式版本控制系统最大的毛病就是必须联网才能工作。而分布式版本控制系统根本没有“中央服务器”,每个人的电脑上都是一个完整的版本库,这样,你工作的时候,就不需要联网了,因为版本库就在你自己的电脑上。和集中式版本控制系统相比,分布式版本控制系统的安全性要高很多,因为每个人电脑里都有完整的版本库,某一个人的电脑坏掉了不要紧,随便从其他人那里复制一个就可以了。而集中式版本控制系统的中央服务器要是出了问题,所有人都没法干活了。

高级使用

add命令相同,Git也提供了一组高级命令来完成完成commit操作,在前一节add高级命令的基础上向下执行

➜  test git:(master) git write-tree     // 在当前目录生成树
9d223a574a4b40a55bbf02a047c042c6c0b889a9
➜  test git:(master) echo "first commit" | git commit-tree 9d223a574a4b40a55bbf02a047c042c6c0b889a9   // 提交tree
85f186d00fe88ab272053dfe0d80b1f26dec6464
➜  test git:(master) git update-ref refs/heads/master 85f186d00fe88ab272053dfe0d80b1f26dec6464  //更新当前分支的commit
➜  test git:(master) git log 
commit 85f186d00fe88ab272053dfe0d80b1f26dec6464
Author: zouziwen <zouziwen@meituan.com>
Date:   Mon May 8 18:33:45 2017 +0800

    first commit

初级使用

一般的,使用git add命令开始追踪一个文件,其语法为:git add [<options>] [--] <pathspec>...(options可通过git add -h查看,亦可查阅add)

所以如下实例:

➜  test git:(master) ✗ echo "test" > test.txt
➜  test git:(master) ✗ git status
On branch master

Initial commit

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

    test.txt

nothing added to commit but untracked files present (use "git add" to track)
➜  test git:(master) ✗ git add test.txt   (亦可为 git add . 为添加当前目录所有未跟踪或未暂存文件)
➜  test git:(master) ✗ git status
On branch master

Initial commit

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

    new file:   test.txt

上述实例中当创建一个新文件test.txt时,使用git status命令查看,Git会提示Untracked files:(use "git add <file>..." to include in what will be committed);而当执行add操作后,会提示Changes to be committed:(use "git rm --cached <file>..." to unstage),可使用git rm --cached命令将该文件移除暂存区;所以读者可勤用git status命令,Git会友好的提示一些命令。

再次修改文件test.txt使用git status查看发现修改已暂存的文件出现modified状态的文件,根据git status提示,若需要应用此次修改则使用git add,若不应用则使用git checkout --

➜  test git:(master) ✗ echo "test11" > test.txt
➜  test git:(master) ✗ git status
On branch master

Initial commit

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

    new file:   test.txt

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:   test.txt
➜  test git:(master) ✗ git add .
➜  test git:(master) ✗ git status
On branch master

Initial commit

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

    new file:   test.txt

近乎所有操作都可本地执行

在 Git 中的绝大多数操作都只需要访问本地文件和资源,不用连网。但如果用
CVCS 的话,差不多所有操作都需要连接网络。因为 Git
在本地磁盘上就保存着所有有关当前项目的历史更新,所以处理起来速度飞快。

举个例子,如果要浏览项目的历史更新摘要,Git
不用跑到外面的服务器上去取数据回来,而直接从本地数据库读取后展示给你看。所以任何时候你都可以马上翻阅,无需等待。如果想要看当前版本的文件和一个月前的版本之间有何差异,Git
会取出一个月前的快照和当前文件作一次差异运算,而不用请求远程服务器来做这件事,或是把老版本的文件拉到本地来作比较。

用 CVCS 的话,没有网络或者断开 VPN 你就无法做任何事情。但用 Git
的话,就算你在飞机或者火车上,都可以非常愉快地频繁提交更新,等到了有网络的时候再上传到远程的镜像仓库。同样,在回家的路上,不用连接
VPN
你也可以继续工作。换作其他版本控制系统,这么做几乎不可能,抑或非常麻烦。比如
Perforce,如果不连到服务器,几乎什么都做不了(译注:实际上手工修改文件权限改为可写之后是可以编辑文件的,只是其他开发者无法通过
Perforce 知道你正在对此文件进行修改。);如果是 Subversion 或
CVS,虽然可以编辑文件,但无法提交更新,因为数据库在网络上。看上去好像这些都不是什么大问题,但在实际体验过之后,你就会惊喜地发现,这其实是会带来很大不同的。

刚安装完git,需要初始化配置,进入命令行输入:表示这台机器上所有GIt仓库都是使用这个配置,否则git会提示:please tell me who you are。

$ git config –global user.name “username”$ git config –global
user.email “useremail”

Git对象

➜  test git:(master) git cat-file -t cb19826acbc17d65e6b492abf2b5b10930c184f3
blob
➜  test git:(master) git cat-file -t 9d223a574a4b40a55bbf02a047c042c6c0b889a9
tree
➜  test git:(master) git cat-file -t 85f186d00fe88ab272053dfe0d80b1f26dec6464
commit

如上命令分别得出Git对象存储的内容,如下图:

图片 5

Git对象

Git会为每个文件都生成一个数据对象(blob-object),而为了解决文件名保存的问题,还提供了一个树对象(tree-object)。Git以一种类似于
UNIX 文件系统的方式存储内容,但作了些许简化。
所有内容均以树对象和数据对象的形式存储,其中树对象对应了 UNIX
中的目录项,数据对象则大致上对应了 inodes 或文件内容。
一个树对象包含了一条或多条树对象记录(tree
entry),每条记录含有一个指向数据对象或者子树对象的 SHA-1
指针,以及相应的模式、类型、文件名信息。

Git会为每次commit生成一个commit对象,每个commit对象对应一个tree,而此tree对象相当于当前目录根目录;

图片 6

根目录的所有对象

高级使用

前文中使用git add命令可将文件放入暂存区进行追踪,那么Git还提供了一套高级命令来完成git add操作;

Git是一个内容寻址文件系统,其核心部分是一个简单的键值对数据库(key-value
data store)。它会为每一个暂存区的文件使用SHA-1
哈希算法计算校验和,生成一个blob对象。你可以向该数据库插入任意类型的内容,它会返回一个键值,通过该键值可以在任意时刻再次检索(retrieve)该内容。
可以通过底层命令 hash-object 来演示上述效果——该命令可将任意数据保存于
.git 目录,并返回相应的键值。

➜  test git:(master) ✗ ls
test.txt
➜  test git:(master) ✗ git hash-object -w test.txt
cb19826acbc17d65e6b492abf2b5b10930c184f3
➜  test git:(master) ✗  git cat-file -p cb19826acbc17d65e6b492abf2b5b10930c184f3
test11
➜  test git:(master) ✗ git cat-file -t cb19826acbc17d65e6b492abf2b5b10930c184f3
blob
➜  test git:(master) ✗ git update-index --add --cacheinfo 100644 cb19826acbc17d65e6b492abf2b5b10930c184f3 test.txt
➜  test git:(master) ✗ git st
On branch master

Initial commit

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

    new file:   test.txt
  1. git hash-object -w 数据来源(stdin或文件) :
    输出长度为 40
    个字符的校验和(一个将待存储的数据外加一个头部信息(header)一起做
    SHA-1 校验运算而得的校验和)
  2. git cat-file -p SHA-1 :
    输出校验值对应的内容,-p是判断其值并显示其内容 ,
    -t为输出该hash的类型,取值有blob,tree,commit
  3. git update-index –add –cacheinfo 文件模式 SHA-1 文件名 :
    必须为上述命令指定 –add
    选项,因为此前该文件并不在暂存区中;同样必需的还有 –cacheinfo
    选项,因为将要添加的文件位于 Git 数据库中,而不是位于当前目录下。
    文件模式:

    • 100644:普通文件
    • 100755:可执行文件
    • 120000:符号链接
    • 三种模式即是 Git
      文件(即数据对象)的所有合法模式(当然,还有其他一些模式,但用于目录项和子模块)。

此时可查看.git目录下的objects内容(根据SHA-1的hash值存储的文件):

图片 7

objects内容

从上述的实例中我们再次能感受到Git其内部原理是键值对数据库(key-value
data store),通过文件的hash值来定位文件的修改。

时刻保持数据完整性

在保存到 Git
之前,所有数据都要进行内容的校验和(checksum)计算,并将此结果作为数据的唯一标识和索引。换句话说,不可能在你修改了文件或目录之后,Git
一无所知。这项特性作为 Git
的设计哲学,建在整体架构的最底层。所以如果文件在传输时变得不完整,或者磁盘损坏导致文件数据缺失,Git
都能立即察觉。

Git 使用 SHA-1
算法计算数据的校验和,通过对文件的内容或目录的结构计算出一个 SHA-1
哈希值,作为指纹字符串。该字串由 40 个十六进制字符(0-9 及
a-f)组成,看起来就像是:

24b9da6552252987aa493b52f8696cd6d3b00373

Git
的工作完全依赖于这类指纹字串,所以你会经常看到这样的哈希值。实际上,所有保存在
Git 数据库中的东西都是用此哈希值来作索引的,而不是靠文件名。

新创建一个项目GitTest

图片 8image.png

git log

git log命令输出了当前工作分支的提交历史,默认不用任何参数的话,git log会按提交时间列出所有的更新,最近的更新排在最上面。这个命令会列出每个提交的
SHA-1 校验和、作者的名字和电子邮件地址、提交时间以及提交说明。

至于使用在官网文档中介绍的很清楚,这里就不多余举出。传送门:git-log

上一篇:Git系列之基础篇–add

下一篇:Git系列之基础篇–push、pull、fetch

总结

git add命令是将未暂存的文件存入暂存区,其内部原理是计算出该文件对应的hash值,并存储至objects目录下,以通过其内容来管理变更。

多数操作仅添加数据

常用的 Git
操作大多仅仅是把数据添加到数据库。因为任何一种不可逆的操作,比如删除数据,要回退或重现都会非常困难。在别的
VCS 中,若还未提交更新,就有可能丢失或者混淆一些修改的内容,但在 Git
里,一旦提交快照之后就完全不用担心丢失数据,特别是在养成了定期推送至其他镜像仓库的习惯的话。

这种高可靠性令我们的开发工作安心不少,尽管去做各种试验性的尝试好了,再怎样也不会弄丢数据。至于
Git
内部究竟是如何保存和恢复数据的,我们会在第九章的“幕后细节”部分再作详述。

进入到项目路径就可以进行git操作

图片 9image.png

SHA-1 哈希算法

Git 中所有数据在存储前都计算校验和,然后以校验和来引用。
Git 用以计算校验和的机制叫做 SHA-1 散列(hash,哈希)。 这是一个由 40
个十六进制字符(0-9 和 a-f)组成字符串,基于 Git
中文件的内容或目录结构计算出来。

上一篇:Git系列–Git仓库

下一篇:Git系列之基础篇–commit

三种状态

好,现在请注意,接下来要讲的概念非常重要。对于任何一个文件,在 Git
内都只有三种状态:已提交(committed),已修改(modified)和已暂存(staged)。已提交表示该文件已经被安全地保存在本地数据库中了;已修改表示修改了某个文件,但还没有提交保存;已暂存表示把已修改的文件放在下次提交时要保存的清单中。

由此我们看到 Git 管理项目时,文件流转的三个工作区域:Git
的本地数据目录,工作目录以及暂存区域。

图片 10

每个项目都有一个 git 目录,它是 Git
用来保存元数据和对象数据库的地方。该目录非常重要,每次克隆镜像仓库的时候,实际拷贝的就是这个目录里面的数据。

从项目中取出某个版本的所有文件和目录,用以开始后续工作的叫做工作目录。这些文件实际上都是从
git
目录中的压缩对象数据库中提取出来的,接下来就可以在工作目录中对这些文件进行编辑。

所谓的暂存区域只不过是个简单的文件,一般都放在 git
目录中。有时候人们会把这个文件叫做索引文件,不过标准说法还是叫暂存区域。

基本的 Git 工作流程如下所示:

  1. 在工作目录中修改某些文件。
  2. 对这些修改了的文件作快照,并保存到暂存区域。
  3. 提交更新,将保存在暂存区域的文件快照转储到 git 目录中。

所以,我们可以从文件所处的位置来判断状态:如果是 git
目录中保存着的特定版本文件,就属于已提交状态;如果作了修改并已放入暂存区域,就属于已暂存状态;如果自上次取出后,作了修改但还没有放到暂存区域,就是已修改状态。到第二章的时候,我们会进一步了解个中细节,并学会如何善用这些状态,以及如何跳过暂存环节。

使用git init创建仓库,这个目录下所有文件都会由Git管理起来,所有增删改都有记录,都可还原

图片 11image.png

然后打开项目目录,多的一个隐藏.git文件就是用来管理该项目的。

图片 12image.png

.git文件夹下都是什么文件呢?

hooks:这个目录存放一些shell脚本,可以设置特定的git命令后触发相应的脚本info:包含仓库的一些信息logs:保存所有更新的引用记录,比如每次commit的哈希值和commit备注objects:该目录存放所有的Git对象,对象的SHA1哈希值的前两位是文件夹名称,后38位作为对象文件名refs:具体的引用,Reference
Specification,这个目录一般包括三个子文件夹,heads、remotes和tags.gitignore:提交需要忽略的文件config:这个是GIt仓库的配置文件description:仓库的描述信息,主要给gitweb等git托管系统使用HEAD:这个文件包含了一个分支的引用,通过这个文件Git可以得到下一次commit的parent

发表评论

电子邮件地址不会被公开。 必填项已用*标注