在软件开发中有一些是通用技能,无论从事什么项目,C、Java、前段、后台,都必须掌握的(甚至产品设计与UI设计都需要):

这些技能应当优先熟练掌握,今天聊一聊版本控制工具Git。之前一直使用的是SVN,也仅仅停留在工作中使用,甚至不会使用svn命令,只能使用SVN Tortoise,也就是拉代码,解决冲突,提交代码这三个步骤,偶尔拉一下分支(甚至都没有亲自合并过分支。。)。

对于Git使用,说来已久,从一开始在Github上面copy代码(clone),到背git命令,了解git flow开发模型,都是理论大于实践,以至于最近工作的代码使用了Git后,一脸的蒙逼。本质来说没有理解Git的核心思想。

老规矩,下面是学习的一些资料,这次没有找英文的原始资料,因为这方面国内很多资料,就不折腾翻译了:

概念理解

核心概念:分支开发

这是Git中最最重要的一个概念,也是与SVN等其他工具最核心的不同。

在Git的开发中,分支是一个轻量级的概念,因此新建分支,合并分支,删除分支在开发中十分常见,我们开发时应当遵循这样的基于分支的开发流程:

  1. 当有一个新需求、bug需要开发时,从origin/master新建一个分支,feature01/bugfix01。
  2. 切换到该分支上,开发。。修复a1,add,修复a2,add。。。
  3. 开发完成后commit(一般保持一个commit记录)
  4. git fetch origin master 从origin master更新代码(从网络更新代码到FETCH_HEAD,可以更新到master)
  5. rebase到当前分支上
  6. push

理解远程分支与本地分支

一个新的项目clone后有哪些分支:

all branch

哪些指针:

理解本地的三个工作区

1. 工作目录workspace

这个可以直接理解成普通的文件夹,文件, 这几个角度:

2. 暂存区 Stage/Index

暂存区是Git维护的,用户手动添加,暂存区只对当前分支有效,

3. 本地仓库

分支本质是n个commit的list

工作目录中文件的三种状态

几个关注点:

HEAD是一个指针,指向的是本地仓库当前分支的一个commit记录!该commit是当前正在工作的commit。
什么时机HEAD会移动:

注意:它指向的内容与工作目录和暂存区可能都不同,因此可以用HEAD来执行恢复操作。

fast-forward merge

快进模式 一个常用概念,指的是谁forward呢?是HEAD的快速向前移动

出现的情况:

总之,当前分支是master,执行git merge branch1。master分支最好的commit是目标分支branch1的祖先commit节点时,会发生Fast-forward的merge。

有时为了时每一次merge都有记录,要禁用fast-forward,需要使用git merge —no-ff命令合并。

merge/rebase/cherry-pick 区别与使用场景

顺序,先rebase orgin 再切换到主分支 merge 过去,前向合并(fast-forward merge,分支是目标分支的祖先commit节点时,会发生Fast-forward的merge)

参考这篇文章理解:http://pinkyjie.com/2014/08/10/git-notes-part-3/

reset与revert

这两个都是后悔药,区别如下

stage与stash

场景分析

commit多次,只保留一个commit,

两种方案:

保存某个文件,要跨分支使用它。

git stash 命令可以满足这个需求,相当于一个存储箱。

commit错分支

cherry-pick:
一种常见的场景就是,比如我在A分支做了几次commit以后,发现其实我并不应该在A分支上工作,应该在B分支上工作,这就需要将这些commit从A分支复制到B分支去了,这时候就需要cherry-pick命令了。

参考:http://pinkyjie.com/2014/08/10/git-notes-part-3/

各种场景恢复的使用reset

下面三种恢复的越来越多。

git reset —soft xx: 仅仅取消commit&&移动HEAD指针到xx,不修改工作目录和暂存区。这个模式的效果是,自从以来的所有改变都会显示在git status的**"Changes to be committed"**中。使用场景:取消commit,一直到某个commit(xx),但是这些修改恢复到暂存区中。
  • git reset xx:取消commit&&移动HEAD指针到xx,并且恢复暂存区,但是恢复工作目录。这个模式是默认模式,这个模式的效果是,工作目录中的文件的修改都会被保留,不会丢弃,但是也不会被标记成"Changes to be committed"。使用场景:取消commit,一直到某个commit(xx),但是这些修改恢复到工作目录中。

    对比上一个就是少了git add 的过程

  • git reset —hard xx: 取消commit&&移动HEAD指针到xx,恢复工作目录&&暂存区。使用场景:恢复到xx commit,丢弃从xx以来的所有修改。

  • 已经推送到远程分支,但是向回退某个commit

    这个使用revert命令,不要使用reset取消commit方式恢复,而是应当使用revert添加commit的方式恢复。

    原因如下

    命令分析

    我们使用的很多命令都是省略了一下参数的,而使用了默认值,有些情况我们也要认识他们,知道含义。

    git push :

    如我们常用:

    origin指定了你要push到哪个remote,master其实是一个“refspec”,正常的“refspec”的形式为”+:”,**冒号前表示local branch的名字,冒号后表示remote repository下 branch的名字。**注意,如果你省略了,git就认为你想push到remote repository下和local branch相同名字的branch。 git fetch :

    与push命令类似,但是注意:**冒号前表示remote repository下 branch的名字,冒号后表示local branch的名字。**上面第一个命令是第二个命令不是fetch到本地master分支,而是FETCH_HEAD上

    参考:

    git pull :
  • git pull ==git fetch+git merge FETCH_HEAD

  • git pull origin master 从网络获取origin分支的master,合入当前分支(没指定) git pull origin/master 本地操作,合并最后一次获取的远程master分支到当前分支(没指定:)

    参考:http://stackoverflow.com/questions/2883840/differences-between-git-pull-origin-master-git-pull-origin-master

    重难点理解