git 的使用(3)-基础命令

来源:互联网 发布:软件学徒招聘骗局 编辑:程序博客网 时间:2024/05/09 01:52

前言:

git 基本是在用git 掌握了命令基本上也就会说自己会git了。

推荐下这2本书:特别是第一本,写的特别好,浅显易懂。

http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000

http://git.oschina.net/progit/


为什么要使用git, 而不是svn

我们平时的开发过程中,起码在国内,其实大部分还是在用svn的,第一是我们大部分的开发其实都在windows在进行,比较习惯用图形化的东西。第二是windows上的TortoiseSVN图形化软件实在太方便了, 很多人使用SVN就是因为图这个方便,所以就导致了git的不流行。但是这也并不能影响我们不去关注优秀的git。回到正题,我们为什么越来越喜欢用git,而不是svn。

1. svn是集中式的的版本管理,而git是分布式的

为了理解分布式和集中式我们来看2张图片:

svn 集中式:



git 分布式:



从上2张图我们可以很清楚看到,svn和git的工作原理。

svn就是你每次commit前都必须先将最新的别人的提交给up到本地,然后你再commit,最关键是你提交的时候必须要联网,因为你要集中commit到svn服务器上,这样才能生效。如果是局域网开发,不连外网也没关系,几台机器相连,其实也叫联网。但是如果假设你要把代码待会家里去做开发,或者出差在火车上,在宾馆里,这样就悲剧了啊,因为连不上公司的内部网,就算svn有外部的网可以提交,你能想象每次写好一段代码,就commmit一次,而且svn联网很慢,要是提交个10M的东西,估计你自己都要郁闷死了。有人又说了,我不提交不就可以了吗,我一次性全部写好,回公司再提交,这样也行。但是,如果中间出现问题,停电文件没保存,或者想回到2个小时之前的代码状态,这个时候你就知道每过10分钟commit一次代码的好处了吧。

git 就完全解决了上上诉svn的痛苦的地方。它是分布式的。也就是说我的每一台机器都是一个独立的服务器,我不用去管其他的东西。但是为了集中管理代码呢。我们通过也会选择一台服务器当作源码机器。当然了。这台机器仅仅是为了统一源码管理的左右,没有其他的作用。所以,我们用clone命令将远程的代码克隆到本地后,我们自己的机器就成了一个服务器了。所以我每次写好代码后,执行commit命令,就是我的代码提交到我自己的机器git上,而不是像svn那样提交到远程。这样我可以随时回到我之前的版本上,因为都是在本地,速度很快。当我所有的都ok了之后,那么你就可以push你的代码到源码服务器上了。其他人也可以共享。

罗嗦说了这么多,不知道我有没有讲清楚,总结下,为什么要使用git:

1. git 速度比svn 要快,且是分布式的,所有的操作初了最后一步push都是在自己本地的机子上完成,速度很快。
2. git不联网(内网,外网)也能完成代码提交等所有操作。
3. git所有的操作都是基于快照的,不像svn是基于文件的差异,这也是它快的一个原因,这点后续会讲到。


git的安装

前面2篇,我花了大量时间来讲述在Linux以及windows上的安装,这里就不再累述了,从这里开始,我们假设已经刚刚安装好了git,并且是windows平台上安装的。

安装完成后,我们要做的第一步就是配置用户名和邮箱:

$ git config --global user.name yangyi$ git config --global user.email yangyi@sina.cn

好了。我们查看下配置成功了没。我们可以使用git config -l命令,查看:

$ git config -lcore.symlinks=falsecore.autocrlf=truecolor.diff=autocolor.status=autocolor.branch=autocolor.interactive=truepack.packsizelimit=2ghelp.format=htmlhttp.sslcainfo=/bin/curl-ca-bundle.crtsendemail.smtpserver=/bin/msmtp.exediff.astextplain.textconv=astextplainrebase.autosquash=trueuser.email=yangyi@sina.cnuser.name=iyangyi

我们看到配置成功了。那么为什么要一上来就要配置这个蛋疼的玩意儿呢? 且听我慢慢道来。因为Git是分布式版本控制系统,所以,每个机器都必须自报家门:你的名字和Email地址。这样你提交代码的时候就会带上这些信息,其他人看到了也就知道是你提交得了。出了问题,也会发邮件来问候你。

创建版本库

git安装好了。config也配置好了。接下来就是初始化创建版本库了。初始化的意思就是你新建一个目录,并让git在这个目录下生效,初始化的命令是:git init

什么是版本库呢?版本库又名仓库,英文名repository,你可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。

我们新建一个目录learngit

$ mkdir learngit$ cd learngit$ pwd/d/learngit$ git initInitialized empty Git repository in d:/learngit/.git/

瞬间Git就把仓库建好了,而且告诉你是一个空的仓库(empty Git repository),细心的读者可以发现当前目录下多了一个.git的目录,这个目录是Git来跟踪管理版本库的,没事千万不要手动修改这个目录里面的文件,不然改乱了,就把Git仓库给破坏了。

把文件添加到版本库

我们刚才已经创建了一个版本库learngit 文件夹,现在呢,我们开始新建一个文件。README.md。很熟悉对不对,一般我们开源的github项目,都会默认生成这样一个文件,用来说明我们的项目的一些东西。

$ touch README.md$ vi README.mdGit is a version control system.Git is free software.

好了。我们往README.md文件里加了2行内容。下面我们如何将这个文件加入到git版本库中呢?首选我们看svn只怎么做的,是先add这个文件,再commit吧。git中也一样,只不过git中的commit只是提交到本地的版本库中,你看不需要联网就能操作,svn没网不行了吧。

第一步:添加到版本库,用git add命令

$ git add README.md

哎,命令执行完,怎么没有任何的输出啊。没有任何显示,这就对了,Unix的哲学是“没有消息就是好消息”,说明添加成功。

第二步,提交到版本库,用git commit -m "some msg"命令

$ git commit -m "write a new readme.md file"[master (root-commit) e2b9781] write a new readme.md file 1 file changed, 2 insertions(+) create mode 100644 README.md

我们看到成功了。返回的信息告诉我们,1个文件修改,2行添加,并且显示了我们刚才的message信息。-m 这个参数是提交的注释说明,简单说明一下我们本次提交的一些信息,便于查看。所以这个参数一定要加,不加会报错。

为什么Git添加文件需要add,commit一共两步呢?因为commit可以一次提交很多文件,所以你可以多次add不同的文件,比如:
$ git add file1.txt$ git add file2.txt$ git add file3.txt$ git commit -m "add 3 files."


查看状态

在git中我们随时随地可以用 git status命令来查看当前分支的状态,比如查看当前分支是否提交,增加了哪些东西还没提交等。由于上一步,我们已经commit过,所以现在现在看一下这个命令:

$ git statusOn branch masternothing to commit, working directory clean

我们可以通过这个命令知道,我们现在在很master分支上(为什么会是master分支,我们后续会讲),没有东西需要提交,而且工作目录是干净的。很清楚明了。

现在我们修改一下README.md文件,修改成为:

Git is a distributed version control system.Git is free software.

我们再次 git status命令看看:

$ git statusOn branch masterChanges 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:   README.mdno changes added to commit (use "git add" and/or "git commit -a")
git 提示非常友善,让我们清楚的知道,README.md文件已经被修改过了,Changes not staged for commit表示还没被添加到暂缓区(后续会讲到)并提示我们可以用git add命令添加。那我们仅仅知道这个文件被修改了,我们也想知道修改了哪些地方呢?这个时候,我们可以用git diff命令,diff就是difficult的意思,就是差异不同,让我们知道哪些地方存在被修改了,我们试一下这个命令:

$ git diffdiff --git a/README.md b/README.mdindex 46d49bf..9247db6 100644--- a/README.md+++ b/README.md@@ -1,2 +1,2 @@-Git is a version control system.+Git is a distributed version control system. Git is free software.
显示的格式是Unix通用的diff格式,可以百度下这种格式的具体用法。我们能清楚的知道了README.md文件被修改了哪些地方,如果有很多文件,会分段显示这种效果。我们知道了哪些地方被修改了,这个时候就可以放心的提交修改了,提交也同样是两部,先提交修改,再提交commit。

提交修改

修改一个文件和新添加一个文件,命令是一样的,都是:git add命令。这时候,我们提交修改:

$ git add readme.txt
同样,也是没输出任何东西,我们就知道修改成功了。那这时候,我们再看看状态是啥样呢? 我们再次使用 git status命令看看:

$ git statusOn branch masterChanges to be committed:  (use "git reset HEAD <file>..." to unstage)        modified:   README.md
这个时候提示就不是Changes not staged for commit,而是Changes to be committed,表示已经添加到暂缓区了,正在准备被提交(commit)。那我们再试一下git diff命令呢?还能看到各文件的差异吗?

$ git diff
唉。居然是空的,啥都没输出。因为我们已经将代码提交到暂缓区了,已经不能再追溯到差异了。所以我们在修改提交之前,使用这个命令。

好了。已经添加好了,那我们就commit提交吧,还记得什么命令吗?对,是这个:git commit -m "some msg"

$ git commit -m "modify a line"[master 4b86146] modify a line 1 file changed, 1 insertion(+), 1 deletion(-)
我们就能清楚的看到,1个文件改变了,新加了一行,删除了一行。正是我们刚才所做的。

提交了后,我们再次看一下,status状态:

$ git statusOn branch masternothing to commit, working directory clean
恩。又回到了刚开始的状态了,没有需要提交的,目录是干净的。


版本回退

上面呢,我们搞明白了如何添加新文件到版本库,以及提交修改,查看状态,查看差异,现在呢。我们来看看如何回退,回退是也我们必不可少的常用操作。

我们先尝试着对README.md做几次修改,然后回退到某一次修改上去:

第一次:加上,“it is a good tool”,依次进行add 和commit操作
$ vi README.mdGit is a distributed version control system.Git is free software. it is a good tool$ git add README.md$ git commit -m 'it is a good tool'[master 0e87e34] it is a good tool 1 file changed, 1 insertion(+), 1 deletion(-)

第二次:加上这句"distributed under the GPL."。依次进行add 和commit操作
$ vi README.mdGit is a distributed version control system.Git is free software. it is a good tool. distributed under the GPL.$ git add README.md$ git commit -m 'add GPL'[master c790395] add GPL 1 file changed, 1 insertion(+), 1 deletion(-)

好,修改完毕,现在我们来捋一捋,我们对这个文件做过多少次修改,我算了下,应该是4次,包括刚才的2次,以及新建这个文件算一次,和上一篇我们查看status命令时的“modify a line”。所以,应该是有4次,当然我们是为了把关系给说清楚,并不是说我们真正开发的时候,去手动去数,没意义。

恩。回到主题,我们要想回到哪一步,我们首先要清楚我们做了多少次操作,也就是历史记录,在Git中,我们用git log来查看我们的提交记录。

我现在来试一下:

$ git logcommit c790395ac6e65457f32f06dcc170a5a3597dcaaeAuthor: iyangyi <yangyi@sina.cn>Date:   Thu Sep 4 14:37:43 2014 +0800    add GPLcommit 0e87e34eec1fb358d0d38374e69276ae93fb8c96Author: iyangyi <yangyi@sina.cn>Date:   Thu Sep 4 14:34:57 2014 +0800    it is a good toolcommit 4b86146be5fc04ea70770181a198debd568772d7Author: iyangyi <yangyi@sina.cn>Date:   Wed Sep 3 11:47:19 2014 +0800    modify a linecommit c96a8e5a54d4476c300438b8aa17dfbca4d55214Author: iyangyi <yangyi@sina.cn>Date:   Wed Sep 3 11:01:44 2014 +0800    write a new readme.md file
果然显示了每一次提交,正是四次。如果嫌输出信息太多,看得眼花缭乱的,可以试试加上
--pretty=oneline参数:
$ git log --pretty=onelinec790395ac6e65457f32f06dcc170a5a3597dcaae add GPL0e87e34eec1fb358d0d38374e69276ae93fb8c96 it is a good tool4b86146be5fc04ea70770181a198debd568772d7 modify a linec96a8e5a54d4476c300438b8aa17dfbca4d55214 write a new readme.md file

这样就看的比较清楚了,我们看到的这一大串类似"c790395.....caae"是commit id,版本号,和SVN不一样,Git的commit id不是1,2,3递增的数字,而是一个SHA1计算出来的一个非常大的数字,用十六进制表示。为什么commit id需要用这么一大串数字表示呢?因为Git是分布式的版本控制系统,后面我们还要研究多人在同一个版本库里,因为都是本地工作,如果大家都用1,2,3作为版本号,一push到代码库,那肯定就冲突了。

ok,到现在我们知道了我们提交的文件的版本号了,那现在我想回到上一步,也就是“it is a good tool” 这一步,我们如何做呢?

当当当当!我们新的命令又来了。就是git reset --hard commit_id(id前7位)这个命令了。或者使用git reset --hard HEAD^快速回到上一次提交。

我们先来说说HEAD吧,在Git中,用HEAD表示当前版本,也就是最新的提交 "add GPL" 的commit id "c790395.....caae", 上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100

再次回到正题,我们要用HEAD^回到上一个版本,也就是“it is a good tool” 这一步:
$ git reset --hard HEAD^HEAD is now at 0e87e34 it is a good tool
我们看到提示了,说HEAD已经在it is a good tool上了。不错。很好。当然我们也可以用git reset --hard 0e87e34,也可达到效果
$ git reset --hard 0e87e34HEAD is now at 0e87e34 it is a good tool
好了,现在理论上讲,我们想回到之前的哪一步都ok的。用了git reset --hard commit_id

别高兴太早,我们现在再来看一看,之前提到的git log命令,还记得是干嘛用的嘛,就是记录我们所有的提交,我们再次看下:
$ git log --pretty=oneline0e87e34eec1fb358d0d38374e69276ae93fb8c96 it is a good tool4b86146be5fc04ea70770181a198debd568772d7 modify a linec96a8e5a54d4476c300438b8aa17dfbca4d55214 write a new readme.md file
看到结果我惊呆了。我擦。我回退把最近一次的"add GPL"给搞掉了啊。悲剧啊。我想回到过去怎么办啊?少年,莫急莫急。我们首先来分析一下为毛一回退,回退到的版本之后的版本都没了:

git 中的回退这么快的原因之一,是因为内部有个指向当前版本的HEAD指针,当你回退版本的时候,Git仅仅是把HEAD从指向"append GPL":(下图所示)



改为指向"add distributed":(下图所示)

看图就很清楚了。图是书中的配图,回到我们这里,就是HEAD指针从"add GPL" 移动到了“it is a good tool” ,所以很快。那么这个时候HEAD 就指向“it is a good tool”了,也就是说它现在就是头了。git log命令永远记录的是从HEAD开始往上的提交记录,HEAD都变了,当然最近一次的"add GPL"就没了。

那你又说了。我虽然懂了没有了的原因,但是我还是得回到"add GPL" 这一步,怎么办,亚麻跌,求求你啦~`(*∩_∩*)′。

当当当当当,解决办法再次降临,这个命令就是 git reflog命令,这个命令记录着我们的每一个命令,不管是回退的还是没有回退的。看,是不是很高端,那帅哥,我们赶紧回到被干掉的"add GPL" 这一步吧。

$ git reflog0e87e34 HEAD@{2}: reset: moving to HEAD^c790395 HEAD@{3}: commit: add GPL0e87e34 HEAD@{4}: commit: it is a good tool4b86146 HEAD@{5}: commit: modify a linec96a8e5 HEAD@{6}: commit (initial): write a new readme.md file
果然,你看,它记录着我们刚才的每一步操作。我们赶紧找到"add GPL"的commit id 是多少,ok,看到了。是c790395 。好。我们再次可以使用git reset --hard c790395:
$ git reset --hard c790395HEAD is now at c790395 add GPL
哈哈,我们看到add GPL注释了。果真回来了。我们再用git log命令看下,有我们的add GPL这个记录了没?
$ git log --pretty=onelinec790395ac6e65457f32f06dcc170a5a3597dcaae add GPL0e87e34eec1fb358d0d38374e69276ae93fb8c96 it is a good tool4b86146be5fc04ea70770181a198debd568772d7 modify a linec96a8e5a54d4476c300438b8aa17dfbca4d55214 write a new readme.md file
哈哈哈哈哈哈。该有的。都有啦。

本节总结

由于篇幅太多,来是这样改,很容易把样式给改掉,处女座的我觉得很不美观。我决定另写一篇。这里先总结一下这一篇。(抱歉我直接照搬书的过来了)
1. 初始化一个Git仓库,使用git init命令。
2. 添加文件到Git仓库,分两步:
第一步,使用命令git add ,注意,可反复多次使用,添加多个文件;
第二步,使用命令git commit -m "some message",完成。
3. 要随时掌握工作区的状态,使用git status命令。
4. 如果git status告诉你有文件被修改过,用git diff可以查看修改内容。
5. HEAD指向的版本就是当前版本,因此,Git允许我们在版本的历史之间穿梭,使用命令git reset --hard commit_id。
6. 穿梭前,用git log可以查看提交历史,以便确定要回退到哪个版本。
7. 要重返未来,用git reflog查看命令历史,以便确定要回到未来的哪个版本。

 

0 0
原创粉丝点击