Git重要命令回顾

摘要

最近正在重新学习Git版本控制系统,以前对Git的了解不太深入,这次基于对张龙老师的Git实战视频课程的学习,对Git又有了进一步的认识。对于Git的深入学习过程,将通过多篇文章来记录。也分享给正在学习的同学。

Git is a free and open source distributed version control system designed to handle everything from small to very large projects with speed and efficiency.

这句话来自于Git的官网,大致意思就是说Git是一个开源免费的分布式的版本控制系统,它可以帮助我们处理不论是小项目还是大项目。最重要的是Git的速度和效率非常优秀。

从官网的介绍我们还可以看到全球知名的互联网公司都在使用Git管理项目,特别是GitHub上,众多的全世界的顶级项目都托管在GitHub上。

  • jquery
  • spring
  • apache

作为程序员来说,如果我们不能很好的掌握Git的操作和使用,我们就不能很好的利用开源世界给我们的帮助,做一些重复造轮子的工作,更何况GitHub上的开源项目都经历了实际生产中的考验。拥有全世界的开发者的pull request。就像张龙老师说的那样。如果你还不会使用Git,那么你就不要写代码了!

其实说了这么多,大多数程序员对Git还是有所了解,日常工作中也会使用sourcetree等图形化工具来协助代码的拉取和推送。知道一些常用的命令:

  • git init
  • git add
  • git commit
  • git pull
  • git push
  • git branch

但是,对Git不了解的同学只是在使用命令,如果一旦出现问题,并不知道如何去解决。所以这也是我们为什么要深入去学习Git原理的部分,让Git真正成为工作的利器,而不是畔脚石

从现在开始,我将从最基础的命令介绍,一步步触及Git的本质。

创建仓库

在Git中创建一个版本库使用命令
git init
在终端中输入如下命令

mkdir mygit
cd mygit
git init
initialized empty Git repository in /Users/liuhao/Desktop/mygit/.git/

上述命令表示创建一个名为mygit文件夹并进入,使用命令git init,这样这个普通的文件夹就被Git来管理了。从Git的反馈来理解也是这个意思,初始化了一个空了Git仓库指向了我们刚才创建的mygit文件夹。

从提示来看,Git还帮我们创建了一个名为.git隐藏文件夹。从感觉上讲,我们会很自然的想到这个.git文件夹就是Git管理的当前这个仓库的版本信息。既然Git告诉了我们有这个文件夹的存在,那么我们索性进去看看到底有些啥东西。

cd .git
ls -al
total 24
drwxr-xr-x  10 liuhao  staff  340 12 29 11:25 .
drwxr-xr-x   3 liuhao  staff  102 12 29 11:17 ..
-rw-r--r--   1 liuhao  staff   23 12 29 11:17 HEAD
drwxr-xr-x   2 liuhao  staff   68 12 29 11:17 branches
-rw-r--r--   1 liuhao  staff  137 12 29 11:17 config
-rw-r--r--   1 liuhao  staff   73 12 29 11:17 description
drwxr-xr-x  11 liuhao  staff  374 12 29 11:17 hooks
drwxr-xr-x   3 liuhao  staff  102 12 29 11:17 info
drwxr-xr-x   4 liuhao  staff  136 12 29 11:17 objects
drwxr-xr-x   4 liuhao  staff  136 12 29 11:17 refs

这么多,我们先搂两个瞧瞧,其他的目前还不需要了解。

cat HEAD
ref: refs/heads/master
cat config
[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
    ignorecase = true
    precomposeunicode = true

我们可以看到,HEAD文件里面保存的是一个字符串ref: refs/heads/master
对Git稍有了解的同学都知道,在Git中master指的是主分支,在Git中,当我们创建版本库之后提交文件至版本控制系统,就天生活动在master分支,所以HEAD里面的内容也就不难理解。它指的就是当前所处的分支

对于config文件,内容是一些参数键值对,也就是说这些参数开用户是可以配置的,我们暂且不去管这些参数,我们来学习Git中第二条命令,在终端中执行如下命令:

git config --local user.name 'test'
git config --local user.email '[email protected]'

通过上诉命令,我们就给当前仓库配置了用户名和用户邮箱。我们再回到config文件中,

[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
    ignorecase = true
    precomposeunicode = true
[user]
    name = test
    email = [email protected]

可以清楚的看到config文件中多了三行,我们着重来看最后三行

[user]
    name = test
    email = [email protected]

[user]表示的是用户相关的配置
name表示的是当前使用这个仓库的人,一般在开发中我们写上自己的姓名。
email表示的是这样仓库的人的邮箱,一般在工作项目中,写上自己的企业邮箱。

配置这两个参数的原因我们等会介绍,至少我们现在可以知道这个仓库属于我们自己。

文件状态

说了这么多,现在我们的mygit文件夹中除了.git自动生成的文件。还没有其他文件,我们赶快自己创建一个文件来实验吧,毕竟我们都知道Git给我们最直观的体验,就是用来管理文件的

cd mygit
echo 'hello 1.txt' > 1.txt
cat 1.txt
hello 1.txt

我们在mygit中创建了一个1.txt并查看其内容为hello 1.txt,至此我们完成了文件的创建,那么我们如何把1.txt提交到版本库中呢?说道这里,我们就要介绍Git中最为重要的三个概念了,它们分别是:

  • 工作区
  • 暂存区
  • 版本库

它们又分别对应三种状态:

  • 已修改
  • 已暂存
  • 已提交

以上三种状态可以用来描述文件的生命周期。当我们新增或修改文件之后,这个文件就处于已修改的状态,你可以选择将其添加到暂存区,使其文件变成已暂存的状态,需要特别注意的是,此时虽然处于暂存区,但是还没有被纳入版本库,要想把文件纳入版本库,必须在暂存区的基础上将其提交到版本库,此时,文件才属于已提交状态。获取文件的状态,我们可以使用git status命令,下面我们来演示这个过程。

git status
On branch master
Untracked files:
  (use "git add ..." to include in what will be committed)

    1.txt

nothing added to commit but untracked files present (use "git add" to track)

git add 1.txt

当我们输入git status命令之后,Git告诉我们了如下信息:

  • 当前处于主分支。
  • 还没有被版本控制系统追踪的文件 1.txt。
  • 提示我们可以使用git add来暂存1.txt。
  • 当前暂存区没有文件,所以没有可以被提交的文件。
  • 现在出现了一个文件可以被暂存,以致被提交。

此时输入git add命令,Git并没有反馈,如果没有提示,就说明操作成功,这点Linux的行为。此时我们再次输入git status

git status
On branch master
Changes to be committed:
  (use "git reset HEAD ..." to unstage)

    new file:   1.txt

此时反馈的内容与git add之前相比,出现了一些变化:

  • 目前依然处于主分支。
  • 有了一些改变可以被提交。
  • 你也可以使用git reset HEAD 将文件从暂存区撤掉,重置为已修改的状态。

我们按照一条路走到底的思路,利用git commit命令将其提交。

git commit -m 'init 1.txt'
master 48a1eb6] 1.txt
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 1.txt

提交文件,使用git commit命令,-m参数为message,填写此次提交信息,需要注意的是,Git推荐也是强制要求我们必须填写message,并且是有用有意义的内容。我们再来摘取提交之后比较重要信息:

  • master 48a1eb6] 1.txt

其中的一串数字表示的是commit id,为了区分每一次不同的提交,Git会给我们生产一个不唯一的id。这个commit id非常有用,我们在版本回退的时候会使用它。

此时,我们就走通了一个文件的生命周期的流程。我们使用如下命令来查看当前场景:

git status
On branch master
nothing to commit, working tree clean
git log
commit 48a1eb6b7262d68e28b93d51251c750801b76a24
Author: test 
Date:   Fri Dec 29 13:18:49 2017 +0800

    1.txt

此时,Git首先告诉我们没有可以被提交的内容,也就是说暂存区没有内容,工作区也是干净的,也就是说当前没有修改任何内容。

再往下,我们来认识一个常用的命令git log,它会告诉我们历史提交记录,这里我们看见了比较熟悉的内容,那就是commid id,author,email。这里的commit id是完整的,我们之前看到的是它的前面几位。需要了解的是,commit id非常不唯一,只需要前面几位就能确定是哪一次提交。其它两个信息是我们自己使用git config命令设置的,它会在git log中记录下来。这时我们就大概能体会到之前设置user的好处了。他告诉了Git是谁在提交。

版本回滚

我们知道在Git中,总是有后悔药可以吃的。版本回滚就是一个方面,使用版本回滚,我们可以回到之前的任意一次提交时的状态。
此时我们做如下修改:

vi 1.txt
add 'text'
cat 1.txt
hello 1.txt
text  
git commit -a -f 'second commit'

此时我们重新修改了文件并做了一次提交,文件变成了两行内容。需要注意的是,这里使用了添加和提交合一的命令:
git commit -a -m
使用这条简短命令的前提是,待提交的文件已经被版本控制系统追踪过。
这时我们查看这次提交:

git log
commit 055c5e79b408721a0129d515baa6dd6ad9f8fe27
Author: test 
Date:   Fri Dec 29 14:01:33 2017 +0800

    secode commit

commit 48a1eb6b7262d68e28b93d51251c750801b76a24
Author: test 
Date:   Fri Dec 29 13:18:49 2017 +0800

    1.txt

此时如果我们对当前版本修改的内容不满意,就可以切换到之前的版本,使用命令:

git reset --hard HEAD~n
git reset --hard HEAD^
git reset --hard 48a1e

其中后面两种比较常用。但是推荐使用最后一种方式,给定commit id的一部分,就可以任意的切换到对应的分支。
第一种是将n换成哪一次提交,第二种一个^代表往前推一个版本,在实际使用中,都不太友好。

需要注意的是,有时候我们希望又切回最新的版本,使用git log又看不到较新版本的commit id,可以使用git reflog命令。

git reflog
055c5e7 HEAD@{0}: reset: moving to 055c
4f01813 HEAD@{1}: reset: moving to HEAD~4
055c5e7 HEAD@{2}: commit: secode commit
f52fa35 HEAD@{3}: commit: add
48a1eb6 HEAD@{4}: commit: 1.txt
d2cf225 HEAD@{5}: commit: del
4f01813 HEAD@{6}: commit (initial): init commit

这样会得到每一次版本的commit id,无论当前处于哪个版本。

后悔药

介绍两条可以用来恢复操作的命令

  • 将暂存区中的文件回退到已修改状态

    git rm --cached 
    
  • 将已修改的文件恢复成上次提交后的内容,也就是把上一次提交后的修改丢弃

     git checkout -- 
    

需要注意的是要将文件的修改丢弃,该文件必须被版本控制系统追踪过。

分支

以上,我们已经学习了很多命令,这些命令非常基础,需要我们信手拈来。要做到烂熟于心,只有去不断练习,设计场景
之所以说基础,因为这些命令只需要死记后就能拿来使用,还没有涉及到太多原理性的内容,但是分支却是Git中最重要且核心的概念,其重要性怎么强调也不为过,正是因为有了分支,我们才有了工程化中最佳Git实践。这一切,都来源于分支的支持。

分支中的命令

介绍分支中的命令之前,先将分支涉及的命令做一下概括。

  • git branch
  • git branch *
  • git checkout *
  • git checkout -b *
  • git merge *
  • git merge -d *

这些命令涉及到

  • 查看分支
  • 创建分支
  • 切换分支
  • 创建并进入该分支
  • 合并分支
  • 删除分支

介绍分支,我们重新创建一个仓库来实验,终端中输入如下命令:

mkdir mygit2
touch 1.txt
git add .
git commit -m 'first commit'
git branch
* master
git branch new
git branch
* master
new
git checkout new
master
* new

在介绍以上命令含义时,我们需要明确master分支到底是什么时候被创建的?

master分支的创建时机是当我们在创建版本库之后,完成一次完整的add,commit操作之后才创建的,并不是版本库一创建就天生存在。也就是说,master分支的创建其实也是懒加载。

明白了上述这个问题,我们就很清晰理解我们为什么完成一次提交后,再创建其他分支。
这样,上诉代码的含义就清晰可见了

git add
git commit
// 此时master被创建
git branch 
* master
//此时有且只有一个分支,并且处于master分支
git branch new 
* master
 new
//创建了一个分支名称为new,目前依然处于master分支
git checkout new
master
* new
//切换到new分支

从以上注释也能理解命令的含义。

分支的合并操作

命令 git merge
分支的合并操作决定了多分支的作用。我们在开发中,除了master分支以外,还会自定义创建其他分支,比如开发新功能的分支,解决Bug的分支,测试分支,线上发布分支等等。正因为有分支合并,我们可以把主分支的代码轻松copy一份,也可以在其他分支进行修改后把差异部分合并到master分支。

ls -al
1.txt

可以发现,在new分支上也有了1.txt,这是因为我们创建new分支时,就是基于master分支,也就拥有了和master分支一样的版本库。这时我们增加一行内容:

vi 1.txt
'hello'
git add .
git commit
cat 1.txt
hello

修改文件并提交到new分支的仓库

git checkout master
cat 1.txt
empty
git merge new
Updating c6fdc17..c542424
Fast-forward
 1.txt | 1 +
 1 file changed, 1 insertion(+)
cat 1.txt            
hello

特别需要注意的是,这里出现了一个概念Fast-forward。中文翻译叫快速前进,这个概念比较重要,它的背后隐藏着分支合并的原理,这一部分,内容比较多。下次再进行讲解。

至此我们就完成对new分支修改的内容的合并。

你可能感兴趣的:(Git重要命令回顾)