Git笔记-续

背景

早之前在使用Git也做过一些浅浅的笔记,但是随着后来对层次和节奏的更高追求,也对Git工作流有了更高的要求。只是简单的add和commit很难满足这项要求,实质上,缺乏了对分支功能的深入挖掘,Git其实和svn相比优势也不大,毕竟如果只是比较速度,svn在局域网下速度并不慢。

Git简单操作&简单流程

初始化和添加远程仓库

1
2
3
4
#初始化
git init
#添加远程仓库
git remote add origin <url>

常用的git操作

添加数据到暂存区

1
2
git add <fileName> //指定文件添加
git add . //添加所有修改文件到暂存区

从暂存区撤回

1
git checkout <fileName>

提交文件

提交文件分为两种

  • 提交到本地版本库

    1
    git commit -m "提交说明"
  • 提交到中央仓库

    1
    2
    3
    4
    #提交本地master分支到远程仓库origin
    git push origin master
    #提交本地master分支到远程仓库t
    git push test master

所以提交到远程仓库的语法是: git push <远程仓库> <本地仓库>

比较文件

所有操作中我觉得最重要的是比较操作了,这是一个,非常常用且非常重要的操作。
对比操作根据对比对象的不同,分为以下几种:

  1. 工作目录同暂存区对比
  2. 工作目录同版本库对比
  3. 暂存区同版本库对比
  4. 同分支不同提交之间对比
  5. 不同分支之间文件对比
  • 工作目录同暂存区对比

    1
    2
    3
    4
    #指定对比文件
    git diff <fileName>
    #对比全部
    git diff
  • 工作目录同版本库对比

    1
    2
    3
    4
    5
    6
    #对比工作区和最近提交版本库1.txt文件变化
    git diff HEAD -- 1.txt
    #对比工作区和最近提交版本库a文件夹变化
    git diff HEAD -- ./a
    #对比全部变化
    git diff HEAD
  • 暂存区同版本库对比

    1
    2
    3
    4
    5
    6
    #对比暂存区和最近提交版本库1.txt文件变化
    git diff --cache HEAD -- 1.txt
    #对比暂存区和最近提交版本库a文件夹变化
    git diff --cache HEAD -- ./a
    #对比全部变化
    git diff --cache HEAD
  • 同分支不同提交之间对比

  • 不同分支之间文件对比

    1
    2
    3
    4
    #比较master分支和foo分支文件差异
    git diff master..test
    #比较master分支和test分支上1.txt不同
    git diff master test 1.txt

分支操作

语法:

1
2
3
4
5
6
7
8
9
10
'git branch' [--color[=<when>] | --no-color] [-r | -a]
[--list] [-v [--abbrev=<length> | --no-abbrev]]
[--column[=<options>] | --no-column]
[(--merged | --no-merged | --contains) [<commit>]] [<pattern>...]
'git branch' [--set-upstream | --track | --no-track] [-l] [-f] <branchname> [<start-point>]
'git branch' (--set-upstream-to=<upstream> | -u <upstream>) [<branchname>]
'git branch' --unset-upstream [<branchname>]
'git branch' (-m | -M) [<oldbranch>] <newbranch>
'git branch' (-d | -D) [-r] <branchname>...
'git branch' --edit-description [<branchname>]

查看分支,查看分支有几种方式:

  • 只看本地

    1
    git branch
  • 只看远程

    1
    git branch -r
  • 查看全部

    1
    git branch -a

其他常见的的分支操作:

  • 添加新分支

    1
    2
    #创建test分支
    git branch test
  • 切换分支

    1
    2
    #切换到test分支
    git checkout test
  • 删除分支

    1
    2
    #删除test分支
    git checkout -d test
  • 复合操作:新建并切换过去

    1
    git checkout -b foo
  • 分支映射

    1
    2
    #设置abc分支提交到远程test分支
    git branch --set-upstream abc origin/test

改变历史

最常见的改变历史情况是:当提交完一个修改之后让同事更新去看结果,然后瞬间发现有个文件没有提交
这种修改相对简单,使用 –amend命令即可

1
2
3
git commit -m "这是一个有遗漏的提交"
git add -u
git commit --amend -m "修正刚才的错误"

除了这种最常见的,还有两种非常常用的改变历史:

  1. 删除提交历史中的某次提交记录
  2. 融合过去若干次提交的变为一个

删除体检提交历史中的某次提交记录

第一种方式(拣选):

做个简单例子,假如有一下提交记录:A-B-C-D,其中,A,B,C,D都指代对应提交的tag,假设我们需要改变历史,使其变成A-B-D,也就是从提交历史中删除C:

1
2
3
4
5
6
7
8
9
10
#首先,跑到B位置去,使用checkout
git checkout B
#使用git cherry-pick命令,这个是干嘛用的呢:help有写:
#Apply the changes introduced by some existing commits 应用改变到已存在提交
#此时:D为master,C为master^,B为mster^^,我们执行一次git cherry-pick即可:
git cherry-pick master
#这里再假设要删除B,这样操作:
git checkout A
git cherry-pick master^
git chery-pick master

第二种方式(变基)

变基(rebase)是个相对高级的命令,执行之前需要知道发生了什么:
语法:

1
git reset --onto <newbase> <since> <till>

这里声明一下 since不含since,而till包含till(这个不说了,懂的自然会懂…)

执行细节:

  1. 执行git checkout
  2. 产生临时文件,存放版本范围
  3. git reset –hard
  4. 根据临时文件中版本范围,逐一提交到
    4.1 如果该提交已经包含,跳过
    4.2 如果文件冲突,变基暂停
    4.3 冲突解决后执行git rebase –continue继续或者git rebase –skip跳过此提交
    4.3 执行git rebase –abort可以终止变基并返回变基前位置

因此,第二种方法更快:

1
2
3
4
git rebase --onto B C D
#开始重置master指向 这是一个很常用的操作,需要记下来
git checkout master
git reset --hard master@{1}

融合过去若干次提交的变为一个

融合也可以使用git cherry-pick,不同的是不用checkout,而使用reset来操作,reset和checkout不同的地方在于它会更改HEAD指向
例子:假如有一下提交记录:A-B-C-D,其中,A,B,C,D都指代对应提交的tag,我们要将BC两个融合到一起

第一种方式(拣选):
1
2
3
4
5
6
7
8
9
10
11
git reset --soft C//不对暂存和工作区做操作,仅变更HEAD,为C
# 此时A为HEAD,而D为HEAD@{1}
# 然后使用git commit -C ,这个是什么呢,看help:Take an existing commit object, and reuse the log
# message and the authorship information (including the timestamp) when creating the commit.
# 这里使用这个-C来使用B的提交对象,提交到C上
git commmit -C B
# 拣选D的变化
git cherry-pick D
#开始重置master指向 这是一个很常用的操作,需要记下来
git checkout master
git reset --hard master@{1}
第二种方式(变基):

第二种方式实际上仅仅是省略了可能的若干git cherry-pick,实际上步骤依然是三步走:

  1. git commit -C
  2. git rebase
  3. 重置master

具体步骤不再重复了。

git工作流&git-flow

更加详细的git-flow我就不献丑了,这里是中文翻译地址:传送门
这里仅仅介绍一下工作流程:

  1. develop作为常用分支,所有开发流程都在develop上进行操作
  2. git flow feature start MYFEATURE开始一项功能开发,git flow feature finish MYFEATURE结束一项功能开发
  3. git flow release start MYFEATURE创建一个发型版本,finish用法同2结束版本
  4. git flow hotfix start VERSION [BASENAME]紧急修复,跳过release

这个过程中的分支变化:

  • git flow feature start MYFEATURE

    –新建分支develop/MYFEATURE

  • git flow feature finish MYFEATURE

    –mergedevelop/MYFEATURE到develop分支

  • git flow release start MYFEATURE

    – 创建release/MYFEATURE分支
    – 从develop当前位置记录发型版本起点

  • git flow release finish MYFEATURE

    –从develop当前位置记录发型版本结尾
    –归并到develop&master分支
    –删除release/MYFEATURE分支

  • git flow hotfix start VERSION

    –创建hotfix/VERSION分支

  • git flow hotfix finish VERSION

    –merge hotfix/VERSION分支到master和develop
    –删除hotfix/VERSION

git和svn的合奏

不管怎么说,svn还是在更多的企业环境发挥着重要的作用,这种状况作为打工仔其实也无力去改变它。
但是这并不意味这不能拥抱git的魅力,因为,我们还有一个工具叫做git-svn

安装碎碎念

window平台安装时候要安装两个软件,一个是git,另一个往往就是乌龟svn了,这里安装乌龟svn时候要自定义一下安装选项,将command line选起来
mac平台的话, brew install git svn搞定一切
ubuntu平台的话, sudo apt-get install git git-svn subversion

git和svn的合并使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
#先检出svn库
git svn clone <svn-url> --username=<youname>
cd repoDir
#git-flow 初始化,一路enter
git flow init
#更新数据(仅仅到git-svn分支)
git svn fetch
#提交数据(从master)
git svn dcommit
#svn数据更新到master
git svn fetch
git checktout master
git svn rebase

恩,这就是这段时间用到的全部了,收尾!