工作中我是怎么使用git的--git教程 中

本篇为中篇,介绍git在多人协同开发中的使用

上篇

下篇

中篇

节点树

在上篇中,我们了解到commit会生成一个提交记录,每一个提交记录均有一串唯一编码。将每一次的提交记录看作是一个节点,节点和节点相连形成图中的节点树。

这里我使用的是来自Sourcetree软件的截图,这里我们重点关注右侧表格。每一行为一个节点,按时间降序排列在表中。我们来认识这里每一列的含义。

  • 图谱,图谱中便是节点树本树了,节点下方的线条表示这个节点是从哪个节点变化而来的,一个节点下方最多只会有两条线,表示这个节点最多由两个节点变化而来。一般这类git工具都会选用不同的颜色来区分每一个分支。
  • 描述,描述中的文字很简单,就是这一次提交时输入的文字,左侧会有两种标记,分支名和标签。
    • 分支,如果分支出现在这一行,则表示这个分支最新的提交记录就在这了。带有origin/前缀的为远程分支,这个origin是对远程分支的默认前缀,可自定义成其他名称。
    • 标签,和分支名一样,如果出现在这一行,则表示在这个节点上有一个标签。
  • 日期,这个节点的提交日期和时间。
  • 作者,提交人。
  • 提交,每一个节点的唯一编码,此处展示的是前6位,可以直接使用这个来代替整串编码进行操作,如果项目提交数过多的话位数会有所增加。

另外图中的第一行是有未提交的更改,这其中便是我们正在修改的内容。其他git工具对节点树的展现方式也基本时这样的形式。

先来热热身

在进入下面教程之前让我们在上篇教程中的test项目上做一个小小的热身。

  1. 来到我们的test项目, 确保当前分支是master。如果不是的话,请切换到master分支。

  2. 先创建一个文件编程书籍.txt,输入以下三行内容并保存。

    1. Java
    2. 代码质量
    3. Linux
    
  3. 执行addcommitpush,将本次提交推送到远程。

  4. 新建三个分支book-javabook-code以及book-linux

  5. 切换到分支book-java上,修改编程书籍.txt,在Java下增加几本书,并执行提交。

  6. 切换到分支book-code上,修改编程书籍.txt,在代码质量下增加几本书,并执行提交。

  7. 切换换到分支book-linux上,修改编程书籍.txt,在Linux下增加几本书,并执行提交。

  8. 最后切回到分支master执行以下命令。

    git merge book-java
    git merge book-code
    

    在执行第二个命令的时候我们的git bash会弹出一串提示信息,我们暂且略过,按下shift+;后再输入q,回车。(这里的操作类似于linux系统的vim。)

  9. 恭喜你,热身结束,可能有小伙伴发现我们创建了三个分支,还有一个呢?这个嘛,剩下的分支book-linux我们一会就会操作到了。

分支合并和冲突

在上篇中我们已经学习到了merge的使用,为什么当我们进行第二次merge命令时会出现提示信息呢?这里我们就要来看到合并之后的节点树了。

当把执行git merge book-java时,由于分支book-java可以通过下方的连接线找到分支master,所以不会有弹出框;而执行git merge book-code时,分支book-code无法通过下方的连接线找到分支master,所以需要合并形成一个新的提交节点,弹出框中输入的内容就是我们这一次merge的提交内容。

冲突

现在让我们执行git merge book-linux,可以看到提示和之前的merge又不一样了,这次又是什么问题呢?

CONFLICT (content): Merge conflict in 编程书籍.txt
Automatic merge failed; fix conflicts and then commit the result.

可以看到我们的文件出现了CONFLICT,也就是文件内容冲突。这是在协同开发中常见的问题之一。在执行merge时,如果两个分支对一个文件的修改有重叠的时候,git便无法判断需要保留哪个分支的修改内容,因此需要我们进行解决。

解决冲突

打开编程书籍.txt,我们可以看到文件内容变成了以下情况。

1. Java
《Java核心技术 卷I》
《Java核心技术 卷II》
2. 代码质量
<<<<<<< HEAD
《图解设计模式》
《重构 改善既有代码的设计》
3. Linux
=======
3. Linux
《鸟哥的Linux私房菜 基础学习篇》
《鸟哥的Linux私房菜 服务器架设篇》
>>>>>>> book-linux

<<<<<<< HEAD=======>>>>>>> book-linux便是冲突标记,从<<<<<<< HEAD=======就是当前master分支的内容,从=======>>>>>>> book-linux就是book-linux分支的内容。我们解决冲突,需要做的就是将冲突标记全部移除。通常我们有3种方式。

  1. 选择两个中的一个。

  2. 自行选择两者的内容进行合并。

  3. 也可以把冲突的内容全部删掉,换上一个全新的内容。

    1. Java
    《Java核心技术 卷I》
    《Java核心技术 卷II》
    2. 代码质量
    我就是要来个新的
    

现在我们来操作一下解决冲突,

  1. 把文件内容改成下面的样子。

    1. Java
    《Java核心技术 卷I》
    《Java核心技术 卷II》
    2. 代码质量
    《图解设计模式》
    《重构 改善既有代码的设计》
    3. Linux
    《鸟哥的Linux私房菜 基础学习篇》
    《鸟哥的Linux私房菜 服务器架设篇》
    
  2. 执行git add "编程书籍.txt"

  3. 执行git commit -m "Merge branch 'book-linux'

  4. 执行git push,把我们写的书籍推送到远程仓库。

  5. 执行git tag v2.0标记一个新版本。

这样冲突就被我们成功解决了。通常在工作中解决冲突时候,需要联系到冲突内容的提交者。双方进行协商得到最后的合并内容。另外也会使用git工具,或者在开发工具上进行冲突解决,毕竟命令行和基本的文本软件来操作实在是费时费力。

变基rebase

合并和冲突并不是分支与分支之间独有的,在多人协作的时候,执行pull命令也会出现合并与冲突。这又是怎么回事呢?这里我用另外一个项目来举例。

现在我和小伙伴都在master上有一个提交,但是小伙伴先于我提交了。在我执行push时候就会报错,因此我需要使用pullmaster最新的代码先拉取到本地,这样就会形成一个合并。

有合并自然就有冲突,当然处理的方式和分支冲突的处理方法是相同的。但是这样通过pull合并的代码在分支内会将节点树变得非常不清爽。为了让节点树看起来简简单单的一条直线,我们可以使用变基rebase

rebase通常有两种使用场景。

  1. 将本地某个分支上连续的多次提交合并成一个。
  2. 在同个分支中,本地需要merge远程获取最新代码时将其变成直接提交。(冲突依旧是需要手动进行解决的)

在现在第一张图的这个场景下,执行命令git rebase,我们就可以得到下图完美的节点树了。

回滚和重置

刚才我们已经成功的把基本编程书籍汇总,并打上了一个新的标签表示我们的项目又达到了一个新的版本,现在我们来学习一下版本回滚。

  1. 确保当前在master分支。
  2. 新建文件多余的.txt,随意输入内容。
  3. 执行addcommit,注意不要使用push

现在我们的项目中多出了一个没有意义的文件,我们可以很简单的删除它,然后再进行一次提交。不过这里git给了我们其他更简单的解决方案。

回滚revert

刚才的提交,在我机器上生成的编码是ae93f1fd135b6a91d5b75288a71feab9062d3c29,缩写为ae93f1f,执行git revert ae93f1f。可以看到出现一个提示框,这个提示框的内容与之前我们使用merge时候是一样的,执行revert会生成一次提交。我们不修改内容退出,现在我们看到多余的.txt文件就被删除了,在Sourcetree中展示的结果就是这样的。

rever命令可以回滚某次提交的内容,如果我们有多次提交需要进行回滚,那么要按照最新的提交到最晚的提交顺序一个一个进行revert。若是遇到需要回滚有冲突的merge时候,还要增加-m [1或2]参数来选择回到哪个分支的内容。例如git revert 35f6996 -m 1便是把回滚到合并book-linux之前的内容。

重置reset

接着我们来试试resetreset有三种常用模式。

  • soft,保留当前文件内容(不会清空缓存区),将分支最新提交回退到指定版本。
  • mixed,默认模式,保留当前文件内容(会清空缓存区),将分支最新提交回退到指定版本。
  • hard,将当前文件内容和分支均回退到指定版本。(如果有未提交的内容也会被清理)

因为文件已经通过revert删除了,所以不管是哪种模式都可以达到我们的目标,现在我们来执行下git reset。可以发现项目最新的提交节点回到了之前v2.0的地方,之前我们操作的内容全部消失了。所以各位要向使用reset的时候必须要谨慎,否则导致代码丢失就要哭惨了。

以上版本回滚和重置如果只是涉及到自己本地的内容都还好,最多就是自己的工作白费了,但是要没有仔细审核内容而提交到远程,甚至还使用了git push -f,那么可能会对整个项目产生类似于rm -rf或者是删库跑路的这样严重的问题。

本次教程的下篇将会介绍Git Flow。

总结

本次中篇我们使用了Sourcetree来作为git查看和管理的工具,作为开发人员来说,开发软件通常会自带便利的插件进行git操作。

总结一下本次的新命令。

  • rebase变基操作可以将多个提交或合并提交变成一个提交,让节点树更清爽。
  • rever撤销某一次提交记录。
  • reset将当前分支的最新提交移动到指定提交记录。
posted @ 2021-04-18 22:43  Leney  阅读(370)  评论(0编辑  收藏  举报