git详解(一)git的介绍与基本使用
摘要: 从本文开始会介绍git的相关内容,同时也是我学习git的历程,可以一边和大家分享,一边自己也加深印象。作为第一篇,先介绍下git的用处与基本设置。通过本文,我们可以知道为什么在大型项目中git必不可少,至少目前是必不可少,以及关于git的一些简单设置。
关键字 git , 用处,基本设置
1.git的用处
我们采用下蒙太奇手法来介绍git,这儿开始不介绍git如何强大,而是切身处地考虑几个场景,看看在下面几个场景下,你会怎么做?或者有啥好想法?
- 写了一段很长的代码,已经验证通过,为了新加一些功能,对代码各处都改动了一下,发现代码奔溃了,想看下修改了哪些地方,看看哪儿可能导致奔溃,你会怎么办?
- 你反复调试以后,发现增加的代码不可避免地会导致奔溃,想把刚才的改动回退掉,你会怎么办?
- 你在编写代码的时候,没有验证代码,只是简单地看下编译能否通过,在你反复改动又编译了n次以后,运行代码,发现奔溃了,想知道这个奔溃是哪一次改动引起的,你会怎么办?
- 你发现你要写的代码太复杂了,一个人可能搞不定,想要和小伙伴们一块写,你会怎么管理?
- 小伙伴儿们都有一套代码,然后在现在的代码基础上修改,然后需要合并起来,你会怎么合并?
- 你想用一个服务器来管理共同的代码,然后各自的修改以差分文件的形式提交,这样巧妙地解决了合并问题,那你会怎么预防服务器突然挂掉导致代码丢失的情况?
- 你发现服务器上的代码在某一次合并之后出问题了,想知道是谁的修改引起的,你会怎么办?
- 你找到出问题的原因了,发现是自己引起的,可是你现在手头还有其它代码没写完,你会怎么修改你的bug?
- 你终于修改好bug了,发现可能和现在的代码有点冲突,你会怎么把你的修改合并进去?
- 你和小伙伴们终于把代码写好了,想要在代码的各个进展阶段做个标记,记录你们的成果,你会怎么办?
如果你能在上面的那些场景下都有自己觉得满意的方法,那我觉得你可以不用看git了,把你的方法分享给别人吧,你是真正的牛人。如果你发现自己应付上面的场景有点吃力,那么可以和我一块学一下git,看看git为什么这么受欢迎。
git是linus Trovalds 在管理linux时写的一个版本管理工具,专门用于解决上面的问题,而且它的功能太远远不止上面提到的,可以说,一旦你学会了git,发现很难离开git了,现在全球大多数的开源代码都是由git管理的。
2 git的基本设置
2.1 git的下载与安装
linux上面自带有git,windows上面的话需要找一个安装包,安装流程和普通软件一样,这儿就不做详细的介绍,可以自行下载安装。
2.2 git的设置
在我们第一次使用git的时候,一般都需要设置自己的用户名和邮箱,如果不设置的话,在提交代码的时候也会要求设置。
首先我们先初始化一个git工作区
mkdir demo
cd demo
git init
设置用户名信息都是写到git的配置文件中,一般是~/.gitconfig ,我们可以用下面的命令写:
git config --global user.name "lihaoran"
git config --global user.email "leehaoran111@163.com"
当然上面是我自己的设置方式,你在设置的时候需要改成你的名字和email地址。
由于git中我们经常会用一些比较长的命令,为了方便,可以像alias一样设置缩写,一般常用到的设置如下:
git config --global alias.st status
git config --global alias.ci commit
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.cp cherry-pick
至于为啥加global,不加会怎么样,我们可以用实际操作看一下。
首先选择一个工作目录并执行git init
,发现多处了一个.git的文件夹,要会用git的话,那么可以不管该文件夹,不过要了解git的话,那么一定得看看该文件夹了。该文件夹涉及东西比较多,我们接下来会慢慢介绍,直到全部介绍完。
现在看下git config
加不同参数的影响,我们首先执行
git config -e --local
发现打开了当前目录下.git中的config文件,可以看到这是INI(Initialization File)格式,这里面就是一些git的配置。
接下来看下
git config -e --global
这时打开了home目录下的.gitconfig文件,这里面也是git的配置
然后是
git config -e --system
这时打开了/etc/gitconfig中的git配置文件,那现在问题来了,这三个git配置文件有啥区别?最后使用时哪个的优先级高?
我们思考下的话,可以得出下面的结论:
1. –system是针对所有用户的,–global是针对单个用户的,–local是针对当前工作区的
2. 优先级顺序是local > global > systen
因为如果system优先级最高的话,那么我们为了让git的某些设置生效,很容易修改system下的配置文件,如果每个人,每个人的每个工程配置都往system中写的话,system中的配置会影响到所有用户git的使用,造成混乱。如果是system最低的话,我们很容易倾向于把个性化的设置写到当前工程或用户home目录的配置文件中,也就是越共性的设置可以写到优先级越低的配置文件中,结果是用户之间,项目之间互相的影响也小。
知道这些以后,我们设置git就自然而然变得很容易了,
git config <section>.<key> value
这就是设置所有参数的套路,后面在system.global.还是local,相信看过上面之后,这儿也不难做出判断。
3 git 的基本使用
这一块介绍git的简单使用,作为对git工作的初步了解。
首先切到一个目录下
mkdir demo
cd demo
git init
echo "hello world" > test.txt
这样我们就在当前工作区新增加了一个文件,首先查看一下状态
git status
output:
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)
这时我们可以看到git比较友好的一面,不仅会显示当前目录下的变化,也会提供操作提示。
上面说test.txt没有被跟踪,那我们跟踪一下,也就是讲改动文件加到暂存区。至于啥是暂存区,下面会介绍。
git add .
我们再次看下状态
git status
output:
fox@fox:~/Documents/demo$ git st
On branch master
Initial commit
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: test.txt
这是说,改动已经加到暂存区,接下来要不是提交,要不是从暂存区移除。我们先提交下:
git commit -m "add test.txt"
output:
fox@fox:~/Documents/demo$ git st
On branch master
Initial commit
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: test.txt
再次看下状态
On branch master
nothing to commit, working directory clean
接下来我们看下提交记录
git log
output:
fox@fox:~/Documents/demo$ git log
commit 0e94145e01eb5da2420dd8a47d103aeab1dff44b
Author: fox <leehaoran111@163.com>
Date: Wed Oct 19 00:01:59 2016 +0800
add test.txt
可以看到提交者,提交的改动,时间等。commit id是40位16进制的数字,每个人的都不一样,用于标识一次提交。
现在我们介绍完了最最基础的git命令,下面总结一下:
git init 初始化一个git工作区
git status 查看当前的文件改动状态
git add <file name> 将一个文件加入暂存区
git commit -m "submit message" 提交一个改动
git log 查看提交记录
这几个命令差不多涵盖了我们使用git 70%以上的工作。
当然这几个命令也不仅仅是这么简单,具体可以执行命令下面查看
git help <command>
其实,git help才是最好的老师
3 暂存区(stage)
前面我们已经提到了暂存区,也就是stage,后文将一直使用stage。那究竟啥是stage? 理解stage对于理解git的工作过程十分重要,可以说,如果理解了stage,那么相当于理解了git的80%
在介绍stage之前,先介绍一个很重要的命令,git diff,这是我们在使用git时一定会经常使用的命令,用来比较文件的差异,好,我们下面用例子来演示一下:
继续上面的目录与内容
echo "git diff demo" >>test.txt
git diff
output
@@ -1 +1,2 @@
hello world
+git diff demo
----------
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: test.txt
no changes added to commit (use "git add" and/or "git commit -a")
这儿忍不住要介绍下git diff的输出格式
@@-a,b, +c,d@@
- 表示改动前的文件,+表示改动后的文件,-/+之后的第一个数字表示从那一行显示,第二个数字表示显示多少行。
现在我们继续执行
git status -s
output
fox@fox:~/Documents/demo$ git status -s
M test.txt
----------
git add *
echo "amend some to test" > test.txt
git status
output
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: 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
----------
git status -s
MM test.txt
现在我们的test.txt有三种版本,工作区的,stage的,版本库的。
用git diff 分别比较下:
工作区与stage:
fox@fox:~/Documents/demo$ git diff
diff --git a/test.txt b/test.txt
index f7ee34c..7aeee4f 100644
--- a/test.txt
+++ b/test.txt
@@ -1,2 +1,3 @@
hello world
git diff demo
+amend some to test
----------
工作区与版本库
fox@fox:~/Documents/demo$ git diff HEAD
diff --git a/test.txt b/test.txt
index 3b18e51..7aeee4f 100644
--- a/test.txt
+++ b/test.txt
@@ -1 +1,3 @@
hello world
+git diff demo
+amend some to test
----------
stage与版本库:
fox@fox:~/Documents/demo$ git diff --cached
diff --git a/test.txt b/test.txt
index 3b18e51..f7ee34c 100644
--- a/test.txt
+++ b/test.txt
@@ -1 +1,2 @@
hello world
+git diff demo
现在可以体会到stage其实就是处于工作区与版本库的一个中间状态,类似于待入库状态,执行git status -s时,有两个MM,第一个表示stage与版本库的差异,第二个表示工作区与stage的差异。
那现在我们可以看下stage究竟是啥
stage也就是.git/index,是一个包含文件索引的目录树,记录了文件名和文件的状态信息,包括时间戳和文件长度,文件的内容存储在了.git/objects中,index建立了文件和对象库中对象的对应。
下面通过例子演示一下:
git reset --hard HEAD
git status
On branch master
nothing to commit, working directory clean
ll .git/index --full-time
fox@fox:~/Documents/demo$ ll .git/index --full-time
-rw-rw-r-- 1 fox fox 137 2016-11-06 20:26:50.206788916 +0800 .git/index
fox@fox:~/Documents/demo$ ll test.txt
-rw-rw-r-- 1 fox fox 45 11月 6 20:26 test.txt
时间一样,然后我们更新下工作区的文件修改时间
fox@fox:~/Documents/demo$ touch test.txt
fox@fox:~/Documents/demo$ ll test.txt
-rw-rw-r-- 1 fox fox 45 11月 6 21:18 test.txt
fox@fox:~/Documents/demo$ ll --full-time .git/index
-rw-rw-r-- 1 fox fox 137 2016-11-06 21:17:29.945232956 +0800 .git/index
fox@fox:~/Documents/demo$ git st
On branch master
nothing to commit, working directory clean
fox@fox:~/Documents/demo$ ll --full-time .git/index
-rw-rw-r-- 1 fox fox 137 2016-11-06 21:18:52.140866166 +0800 .git/index
这也就是说index中记录了文件的修改时间,当我们只修改文件的修改时间时,然后执行git status,会发现index的修改时间也变了,这是因为我们在执行git status的时候,git会先用index中记录的文件的修改时间和长度对比工作区的修改文件和长度,如果发现有改动再去比较内容,反之就不去比较内容,这也是git高效的一个原因。
那我们能不能看看stage中记录的目录树?这时我们需要新建一个文件,并提交:
fox@fox:~/Documents/demo$ touch hran/test.c
fox@fox:~/Documents/demo$ git add *
fox@fox:~/Documents/demo$ git commit -m "add dic"
fox@fox:~/Documents/demo$ git ls-files -s
100644 be932f84e9104853c0dcf2088c60442320fff6ce 0 hran/test.c
100644 7aeee4f72cc77cc564fcc3aa7fd03caea3542fcb 0 test.txt
fox@fox:~/Documents/demo$ git write-tree
fb090206bb44349ff5fc52d85fb94107f1d0ce92
fox@fox:~/Documents/demo$ git ls-tree fb090206bb443
040000 tree 151ae54e1d0d34303df4d59ace2c023d0ef5278a hran
100644 blob 7aeee4f72cc77cc564fcc3aa7fd03caea3542fcb test.txt
看一下版本库中的目录树:
fox@fox:~/Documents/demo$ git ls-tree -l HEAD
040000 tree 151ae54e1d0d34303df4d59ace2c023d0ef5278a - hran
100644 blob 7aeee4f72cc77cc564fcc3aa7fd03caea3542fcb 45 test.txt
可以发现stage和版本库一样的时候,所对应的目录树一样
好的,stage的介绍也就结束了,如果工作区还有修改的话
git stash save -a "save reason"
4 总结
本文介绍了以下git的来源与基本使用,但git的内容还远远不止这些,接下来我会继续介绍.