GIT高级使用及其原理

2,210 阅读10分钟

前言

  上一篇文章GIT 基本使用及其原理讲解了git的基本操作以及原理,这篇文章主要讲解一些git集中式开发遇到的问题以及解决方案,废话不多说,直接进入正题。

学习重点

1. git clone远程代码

  git clone远程代码的过程如下图所示:

image.png

  现在让我们在本地模拟这个过程

  • 初始化本地远程代码仓库,使用如下命令:
   git init --bare

  使用示例,在本地创建两个远程代码仓库ab,如下图所示:

image.png

  执行以上命令之后,a.remoteb.remote文件夹中将会多出以下图中所示文件:

image.png

image.png

  假设现在有两个开发者Alice以及Michael,并且Alice创建了一个iOS工程DemoApp,并且初始化了git,如下图所示:

image.png

  Alice开始编写代码了,编写的代码如下图所示:

image.png

  Alice找到了Michael,由于两人异地,所以Alice需要将代码上传到远程代码仓库,好让Michael可以下载自己编写到一半的代码,两个人可以一块进行开发维护,所以需要使用git命令添加一个远程代码仓库,如下所示:

//查看本地添加到远程代码仓库
git remote
//本地添加远程代码仓库
//-t 指定本地要track远程的哪个分支
git remote add -t 远程代码仓库分支名 远程仓库本地别名 远程仓库地址

  使用示例,如下图所示:

image.png

  将代码保存到git并提交代码

image.png

  然后将本地仓库中的代码提交到远程,需要使用如下命令:

git push 远程代码仓库本地别名 
//报错使用
git push --set-upstream origin 远程仓库分支名

  使用示例,如下图所示:

image.png

image.png

  现在Michael就可以从远程代码仓库a.remote中拉取Alice编写的代码了,如下图所示

image.png

  然后使用如下命令拉取远程仓库中的代码:

git pull

  使用示例,如下图所示:

image.png

  然后Michael就可以开始愉快的编写代码了。

2. git是如何产生冲突的

  现在AliceMichael开始一块编写代码了,Alice编写了一段代码,并提交到了本地代码仓库以及远程代码仓库,如下图所示:

image.png

image.png

image.png

  Alice又编写了一段代码,并提交到了本地代码仓库以及远程代码仓库,如下图所示:

image.png

image.png

image.png

  两次提交过后,提交记录如下所示:

//查看提交记录
git log --oneline --decorate --graph --stat

image.png

  但是Michael并不知道Alice提交了两次代码到远程代码仓库,就接着在本地编写代码了,首先Michael21行编写了一段代码并提交到了本地代码仓库,如下图所示:

image.png

image.png

  接着Michael又在22行编写了一段代码并提交到了本地代码仓库,如下图所示:

image.png

image.png

  Michael本地提交记录如下图所示:

image.png

  紧接着Michael将本地代码仓库中的代码push到远程代码仓库,如下图所示:

image.png

  由以上的错误信息可知,产生了代码冲突,你可以使用如下命令区解决冲突:

//使用以下命令查看git支持的合并工具列表
git mergetool --tool-help

//配置git mergetool,这里使用的是xcode自带的工具
git config merge.tool opendiff

//使用合并工具
git mergetool

  在Xcode中显示的冲突代码如下图所示:

image.png

  Michael觉得自己写的代码没有Alice好,于是就将Alice的代码删除了,然后接着将代码提交到了远程仓库,如下图所示:

image.png

  但Michael如此做有一点很不好,就是会使远程代码仓库master分支看起来很臃肿,产生如下图所示的很多瘤子,不容易理解以及维护。

image.png

image.png

  Michael思来想去,觉得这样很不妥当,于是就使用如下的命令回退到了合并之前的commit

//可以使用下面的命令查看如何回退合并代码之后的commit
git rev-parse --help
//回退合并代码之后的commit
git reset --hard ORIG_HEAD

  使用示例,如下图所示:

image.png

  查看回退合并之后的commit的提交记录,如下图所示:

image.png

image.png

3. 如何解决git冲突

  Michael如果想要更好的解决以上的代码冲突,就不能直接pull代码了,应该先做一个rebase操作,命令如下所示:

git pull 远程代码仓库别名 远程代码仓库分支 --rebase

  使用示例,如下图所示:

image.png

  执行这个命令之后,会报错,这是因为出现了代码冲突,如下图所示:

image.png

  以上执行过程是先将Michael这边产生冲突的commit对象b3066aa与远程代码仓库中的HEAD进行比较,直到比较到Michael的commit对象最后一个子节点结点,因此这里选择保留Alice的代码,如下图所示:

image.png

  然后保存修改的代码到git文件系统以及修改文件的关键信息到index文件中,继续执行rebase操作,需要用的如下的命令:

git rebase --continue

  

  使用示例,如下图所示:

image.png

  执行这个命令之后,会报错,这是因为出现了代码冲突,如下图所示:

image.png

  这里比较的是Michael最后的commit对象261820e,发现出现了代码冲突,因此报错,这里依旧选择保留Alice的代码,如下图所示:

image.png

  然后保存修改的代码到git文件系统以及修改文件的关键信息到index文件中,继续执行rebase操作,如下图所示:

image.png

  然后就提示我们rebase操作执行成功了,查看此时的代码提交信息,如下图所示:

image.png

  会发现rebase操作将Michael这边的提交对象追加到了远程代码分支提交对象的最后面,并没有产生一般pullmerge操作产生的肿瘤分支,这样就很容易理解以及管理代码了。

4. rebase使用实例

  首先定义如下图所示的目录结构,并在Alice文件夹中创建一个iOS工程:

image.png

  这个工程的目录结构如下所示:

image.png

  在a.remote文件夹中初始化远程代码仓库,如下图所示:

image.png

  回到Alice文件夹中初始化git,添加远程代码仓库a.remote以及提交项目工程代码,如下图所示:

image.png

image.png

  将本地仓库中的代码push到远程代码仓库,如下图所示:

image.png

  假设代码已经开发了很长时间,Alice主要负责主框架以及Home模块的代码编写,并且他已经提交了好几次代码,这里只将第一次提交的操作完整展示出来,如下图所示:

image.png

  ;pull远程仓库代码,push本地仓库代码到远程仓库的master分支

image.png

  ;接着Alice又多次提交代码到远程仓库,提交记录(使用命令: git log --oneline --decorate --graph --stat查看)如下所示:

image.png

  ;除了在终端查看提交记录以外,也可以使用GitUp图形化工具来查看(可以点击GitUp到官网下载),使用如下图所示:

image.png

image.png

  现在Alice又开始编写Home模块的代码了,因此创建了一个分支Alice_Home并切换过去,如下图所示:

image.png

image.png

  AliceHome模块编写了代码并提交到远程仓库,如下图所示:

image.png

image.png

  接着,Alice又多次在Alice_Home编写并提交代码,提交记录如下所示:

image.png

  然后,Alice又切换到master分支,修改了Home模块的代码并进行了提交,如下图所示:

image.png

image.png

  此时,各个分支情况如下图所示:

image.png

  然后Alice执行了合并分支的rebase操作,将Alice_Home分支的代码合并到主分支master上,使用的命令如下所示:

//将命令中的分支rebase到当前分支中
git rebase 分支名

image.png

  使用工具解决冲突,并提交代码,如下图所示:

image.png

  保存修改的代码到git文件系统以及修改文件的关键信息到index文件中,然后继续rebase,继续rebase,如图所示:

image.png

image.png

  然后我们在来查看一下分支情况,如下图所示:

image.png

  可以看到的是目前已经将Alice_Home中的提交对象rebase到了本地仓库的master分支中了,因此可以将Alice_Home分支从本地删除了,如下所示:

image.png

image.png

image.png

  删除之后,当前分支情况如下所示(左边是本地master分支,右边是远程master分支):

image.png

  但是还需要将本地仓库master分支rebase到远程仓库的master分支,执行命令如下图所示:

image.png

  首次rebase操作没有出现什么冲突,因此先执行git add .命令,再执行如下命令跳过此次rebase:

git rebase --skip

  过程如下图所示:

image.png

  接着出现了代码冲突,解决冲突后,执行git add .命令,然后继续rebase,如下图所示:

image.png

  rebase完成之后,提交代码并push本地仓库master分支代码到远程仓库master分支,如下图所示:

image.png

  最后,分支情况如下图所示:

image.png

  其实以上是以两路合并的方式显示冲突的,当解决这些冲突的时候容易照成混乱,可以使用如下的命令配置以三路合并的方式显示冲突代码:

git config merge.conflictstyle diff3

  使用示例,如下图所示:

image.png

  如果你在rebase的过程中,需要取消掉当前rebase操作,恢复到rebase之前的代码,可以使用如下的命令:

git rebase --abort

5. 编辑分支中的commit对象

  其实,在开发工程中也可以对分支上的commit对象进行修改、合并、删除等操作,在演示之前,先来看看之前的工程的commit对象信息,如下图所示:

image.png

  如果需要对某个commit对象信息进行编辑,可以使用如下的命令:

git rebase -i commit对象id

  使用示例(对id8ff1e8fcommit对象进行编辑,最好选择它之前的commit对象id作为参数),如下图所示:

image.png

image.png

5.1 修改某个commit对象的信息

  如果你想要修改id8ff1e8fcommit对象的提交信息,可以按如下的方式操作:

image.png

  保存并退出后,输入git commit --amend命令,如下图所示:

image.png

  然后在对提交信息进行编辑,如下图所示:

image.png

  保存并退出后,修改成功会提示你如下图所示信息:

image.png

  最后,还需要执行git rebase --continue命令结束本次rebase,如下图所示:

image.png

注意:修改某个commit对象其实是新创建了一个commit对象(新的提交信息)替换原来的commit对象

5.2 压缩多个commit对象

  • 如果想要压缩多个commit对象,可以按如下的方式操作:

image.png

  然后会进入到如下编辑界面:

image.png

image.png

  压缩成功之后,提示信息如下图所示:

image.png

  查看分支中的提交对象,如下图所示:

image.png

5.3 删除某个commit对象以及其之后的所有commit对象

  • 如果想要删除某个commit对象以及其之后的commit对象,可以按如下的方式操作:

image.png

image.png

  删除之后,分支中剩下的commit对象如下图所示:

image.png

5.4 amend的作用

  可以使用如下图所示命令查看amend的作用:

image.png

image.png

  使用示例如下所示:

  首先进入commit的编辑模式:

image.png

image.png

  创建并编辑一个test.txt文件,如下图所示:

image.png

image.png

  添加这个文本文件到暂缓区,如下图所示:

image.png

  在原来的commit的基础上编辑这个commit(编辑之后就成为一个新的commit对象),并替换掉原来的commit对象,如下图所示:

image.png

image.png

image.png

   查看当前分支中commit对象情况,如下图所示:

image.png