0 本文摘要

信任咱们在日常作业中都会用到Git,但可能关于刚接触到Git的同学们来说这种东西的运用还不是很熟练,或许是关于尽管能够标准运用Git来完结日常开发的同学们,但可能关于指令背面的原理或许仍是一脸懵逼,因而本文期望用较为简略的言语,能够在Git的运用上给咱们带来协助或许能处理咱们的部分疑惑。首要第1节带咱们由浅入深的了解Git的一些原理,其次第2节具体针对Git的常用分支操作-兼并的两种办法(merge和rebase)进行了讨论以及给出了这两种兼并办法的运用主张,最后在附录中分类收拾了一些关于兼并操作的常用指令,便利咱们快速查找运用。

1 关于Git的一些根本原理

1.1 Git是什么—版别操控

Git是一个开源的分布式版别操控系统,能够有效、高速地处理从很小到非常大的项目版别办理。最初的意图是 LinusTorvalds 为了协助办理 Linux 内核开发而开发的一个开放源码的版别操控软件。

那么什么是“版别操控”呢?我为什么要关怀它呢? 版别操控是一种在开发的进程中用于办理咱们对文件、目录或工程等内容的修正前史,便利查看更改前史记载,备份以便康复以前的版别的软件工程技术。简略来说便是用于办理多人协同开发项意图技术。假定在多人进行软件开发时没有运用版别操控,将会引发许多问题,如软件代码的一致性、软件内容的冗余、软件进程的事物性、软件开发进程中的并发性、软件源代码的安全性,以及软件的整合等问题。下面总结了一些运用版别操控的优点:

● 实现跨区域多人协同开发

● 追寻和记载一个或许多个文件的前史记载

● 组织和保护你的源代码和文档

● 计算作业量

● 并行开发、进步开发功率

● 盯梢记载整个软件的开发进程

● 减轻开发人员的负担,节省时间,一同下降人为过错

因而,在多人开发中咱们有必要要运用版别操控,现在诞生了许多版别操控东西(如Git、SVN、CVS),可是由于Git易于学习,占用空间小,功能快如闪电,以及便利的暂时区域和多个作业流等特性,使Git成为影响力最大且运用最广泛的版别操控东西,下面咱们将介绍Git的一些根本原理。

1.2 Git的作业流程原理

(1)作业区域

首要来介绍介绍下Git的作业区域,分为作业区、暂存区和库房区,每个区域的转换联系如上图所示。

  • 作业区(workspace):便是咱们平常本地寄存项目代码的地方;
  • 暂存区(index/stage):用于暂时寄存咱们的改动,事实上它只是一个文件,保存行将提交到文件列表信息;
  • 库房区(Repository):便是安全寄存数据的方位,里边有你提交到一切版别的数据,可分为本地库房和长途库房(remote),也称为版别库。

(2)文件状况

Git 中的文件可分为五种状况:

  • untrack(未追寻):未盯梢, 此文件在文件夹中, 但并没有参加到git库, 不参加版别操控。 通过git add状况变为Staged;
  • unmodified(未修正):文件现已入库, 未修正, 即版别库中的文件快照内容与文件夹中完全一致。这种类型的文件有两种去处, 假定它被修正, 而变为Modified。假定运用git rm移出版别库, 则成为Untracked文件;
  • modified(已修正):已修正表明修正了文件,但还没保存到数据库中;
  • staged(已暂存):已暂存表明对一个已修正文件的当时版别做了符号,使之包括在下次提交的快照中;
  • committed(已提交):已提交表明数据现已安全地保存在本地数据库中。

结合文件的五种状况和三个作业区域的对应联系,引出Git 的根本作业流程如下:

(1)在作业区中修正文件A。

(2)git add fileA,将更改的部分增加到暂存区。具体进程是:首要,它给A文件创立1个校验和增加到暂存区中。校验和能够理解为是一个文件的唯一索引,git通过SHA-1这种哈希算法,遍历每一个文件,依据文件内容等信息,为文件创立索引,今后只要依据这个索引,咱们就能够取出一个文件中的完好内容。然后,git对当时的暂存区拍了一张照片,也便是咱们所说的快照,并将快照放入版别库。快照里包括什么内容呢?快照里包括咱们方才说的文件索引和文件完好内容(类似于key-value的结构)。一同,git选用内置的blob目标来存储这三个文件的快照。

(3)git commit来提交更新,找到暂存区的文件,将快照永久性存储到库房区中。具体进程是:首要,git用一个内置的tree目标,把文件的目录结构保存下来。然后,git在这个tree目标上又包了一层,创立了一个commit目标,这个commit目标也是咱们说的git进行版别办理的终究目标。commit目标里包括了tree目标,还包括作者、提交谈论等信息。

(3)数据存储

以上咱们了解到了Git的根本作业流程,那么Git是怎么存储代码信息的?咱们知道,Git与其它版别操控系统不同的是,保存的不是文件的变化或许差异,而是一系列不一同刻的快照 。在进行提交操作时,Git 会保存一个提交目标(commit object)。知道了 Git 保存数据的办法,咱们能够很自然的想到——该提交目标会包括一个指向暂存内容快照的指针。 但不只是是这样,该提交目标还包括了作者的姓名和邮箱、提交时输入的信息以及指向它的父目标的指针。 首次提交发生的提交目标没有父目标,一般提交操作发生的提交目标有一个父目标, 而由多个分支兼并发生的提交目标有多个父目标。

那么上述说到的快照是什么呢?快照便是在履行git commit时,对当时暂存区的状况拍照的一张“照片“,这个照片中涵盖的若干信息将被寄存到git版别库下。若干信息指的是什么?是文件的索引+文件的完好内容(key-value结构),文件的目录结构,和提交信息,这三者别离用git内置的blob,tree,commit目标进行存储。

  • blob: 在git中对应着”内容(content)”, 约等于一整个文件(不包括文件名和文件mode);
  • tree: 在git中对应着”目录(directory)”, 正如每一个目录中能够存储文件或其他子目录相同, tree的每一个节点能够是一个blob, 或许另一个tree;
  • commit: 对应着一次提交, 保存着对一个顶层树目标的引用(对应着某个途径下的一份完好的内容) , 以及提交信息(包括父commit);

咱们能够通过一个目录下的文件及结构来对应得到一组git目标,下图为文件/目录与blob/tree的对应联系:

简略来说, 便是咱们能够通过HEAD文件找到当时branch, 通过当时branch找到一个commit, 通过一个commit找到一个顶层目录对应的tree目标, 一个tree目标又会依据目录下的子目录和文件结构对应地指向一组tree目标和blob目标. 由此, 能够得到一个: HEAD(ref) -> branch -> commit -> tree -> tree/blob的指向图.

因而, 上面的由目录到git目标的对应联系能够被简化成:

在提交时, git会从顶部向下([He1oise 校对]仍是从底部往上)观看每一个blob和tree, 然后复用那些能够复用(没有改动)的目标, 创造出一棵部分复用的树, 所谓commit就指向了这棵树. 当然, 这儿咱们不用去考虑说树中的一个节点为什么会有多个父节点, 由于尽管咱们以为树中的节点总只有一个父节点, 但实践运用上假定咱们只考虑自顶而下地观察, 咱们其实只能看到这个节点是否归于某一棵树。

于是, 咱们在提交过后, 获得了一个commit目标, 这个commit目标会指向其.git所在的目录为根节点的tree目标. 因而, 咱们能通过一个commit目标找到一个对应的tree, 依据一个tree目标来递归地找到其子tree目标和blob目标, 因而找到当时途径下的一份完好的内容.

到这儿, 咱们就大约收拾解了一个分支是怎么对应顶层目录下的一切内容了。更进一步地发散开, 咱们已知一个commit可能有零到多个父commit, 则能够进一步了解到, 在一片commit组成的森林里, commit只是指向某一棵树的指示牌罢了.

2 Git的分支兼并办法浅析

2.1 分支是什么

Git 的分支,从本质上来说它只是是指向提交目标的可变指针。 Git 的默许分支姓名是 master。 在屡次提交操作之后,咱们其实现已有一个指向最后那个提交目标的 master 分支。 master 分支会在每次提交时主动向前移动。下面介绍下关于Git分支的一些根本概念:

  • Head指针:(1)指向当时所在的本地分支,咱们能够看到上图中Head指向的是Master分支,阐明当时是在Master分支上;(2)Head 指针跟着提交操作主动向前移动
  • 分支创立:git branch Dev ,会在当时所在的提交目标上创立一个指针。
  • 分支切换:git checkout Dev ,这条指令做了两件事(1)将Head指针移动到Dev分支上(2)将作业目录康复成Dev 分支所指向的快照内容。
  • 分支兼并:当咱们在Master和Dev分支各自提交了一次分支后,咱们能够看到,提交前史现已发生了分叉,当咱们想将Dev分支上的修正到Master分支上时,咱们能够运用git merge来完结兼并操作。git merge能够兼并一个或许多个分支到你现已检出的分支中, 然后它将当时分支指针移动到兼并成果上。

  

2.2 分支的兼并战略

咱们在上一节中说到,merge操作能够将两个分支的修正整合到一同。具体来说,git会尝试通过两个分支的commit指针,别离向前追溯,找到这两个commit指针在前史上最近的一次一起提交点。Git有几种不同的办法用来寻觅这个一起提交,而这些办法便是所谓的“兼并战略”。默许git会帮你主动选择适宜的兼并战略,也能够通过git merge -s战略姓名来强指定运用的战略类型。下面咱们来介绍一下最常见的几种兼并战略:Fast-foward,Recursice,Octopus 等。

(0)Three-way-merge(三向兼并原理)

在正式介绍git的兼并战略之前,咱们能够先来看下这种几种战略一起会遵循的一个原理:三向兼并原理(Three Way Merge),举例一个场景:假定有两个同学在各自的分支上对同一个文件进行修正,如下图:

这个时分咱们需求兼并两个分支成一个分支,假定咱们只对这两个文件进行比照,那么在代码兼并时,只知道这两个文件在第20行有差异,却不知道应该选用谁的版别。假定我知道这个文件的原件“base”,那么通过和“原件”代码的比照就能推算出应该选用谁的版别:

图示能够看出,B中的代码和Base相同,阐明B中并没有对这行代码做修正,而A中的代码和Base不相同,阐明A在Base的基础上对这行代码做了修正,那么A和B兼并应该选用A中的内容。当然还有一种状况是三个文件的代码都不相同,这就需求咱们自己手动去处理抵触了:

从上面的比如能够看出选用Tree-Way-Merge(也称为三向兼并)原理来兼并代码有个重要条件是能够找到两份代码的“原件”,而git由于记载了文件的提交前史,再通过本身的兼并战略就能够找到两个commit的公共commit是哪个,然后通过比对代码来进行兼并。

(1)Fast forward & Already Up-To-Date(退化)

      

Fast foward是最简略的一种兼并战略,如图将feature分支兼并到dev分支上,git只需求将dev分支的指向最后一个commit节点上。Fast forward是git在兼并两个没有分叉的分支时的默许行为,假定你想禁用掉这种行为,明确具有一次兼并的commit记载,能够运用git merge –no-ff指令来禁用掉。

(2)Recursive

Recursive是git中最重要也是最常用的兼并战略,简略概述为:通过算法寻觅两个分支的最近公共先人节点,再将找到的公共先人节点作为base节点运用三向兼并的战略来进行兼并。举个比如:圆圈里的字母为当时commit中的内容,当咱们要兼并C2,C3两个节点时,先找到他们的公共先人节点C1,接着和节点C1的内容进行比照,由于1的内容是A,所以C3并没有修正内容,而C2将内容改成B,所以最后的兼并成果C4的内容也是B。

可是可能有更复杂的状况,出现几个分支彼此穿插的状况(Criss-Cross现象),如下图所示,当咱们在寻觅最近公共先人时,能够找到两个节点:节点C2和节点C3,依据不同公共先人,能够分为两种状况:

(1)节点C3作为base节点

通过三向兼并战略兼并(base节点的内容是A,两个待兼并分支节点的内容是B和C)咱们是无法得出应该运用哪个节点内容的,需求自己手动处理抵触。

(2)节点C2作为base节点

通过三向兼并战略兼并(base节点的内容是B,两个待兼并分支节点的内容是B和C)能够得出应该运用C来作为终究成果。

通过上述剖析,咱们能够得知正确的兼并成果应该是C,那么git要怎么确保自己能找到正确的base节点,尽可能的削减代码的兼并抵触呢?实践上git在兼并时,假定查找发现满意条件的先人节点不唯一,那么git会首要兼并满意条件的先人节点们,将兼并完的成果作为一个虚拟的base节点来参加接下来的兼并。如上图所示:git会首要兼并节点C2和节点C3,找到他们的公共先人节点1,在通过三项兼并战略得到一个虚拟的节点C23,内容是B,再将节点C23作为base节点,和节点5,节点6兼并,比较完后得出终究版别的内容应该是C。

(3)Octopus(复杂化)

Octopus 战略能够让咱们优雅的兼并多个分支。前面咱们介绍的战略都是针对两个分支的,假定现在有多个分支需求兼并,运用Recursive战略进行两两兼并会发生很多的兼并记载:每兼并其间两个分支就会发生一个新的记载,过多的兼并提交出现在提交前史里会成为一种“杂音“,对提交前史形成不必要的”污染“。Octopus在兼并多个分支时只会生成一个兼并记载,这也是git兼并多个分支的默许战略。如下图:在dev分支下履行git merge feature1 feature2。

2.3 分支的别的一种兼并操作:Rebase

(1)场景举例

咱们举一个实践运用的比如来引出Rebase操作,设想两种场景:(1)多人共用一个分支开发,且本地分支落后长途分支,需更新 (2)一个分支单人开发,且当时研制分支落后于骨干分支,需更新

其实,上述两种状况都可抽象为上图所示,由第(1)种状况来举例,假定有多人在同一个分支上开发,C1、C2为远端分支的提交,C3、C4为咱们在本地库房的提交还没有推送到远端,假定这个时别离的一个同学将他的提交记载C5推送到了远端,这时,咱们再想把咱们的本地的提交推送到远端时,就需求有一个更新长途库房并且兼并本地分支的操作,意图是将其它同学提交记载也保存下来。那么怎么更新呢?有两种办法:(1)git pull (2)git pull –rebase,咱们能够先来看下这两种操作所带来的成果:

   
其间,左图为git pull的操作后的提交前史,咱们能够看到在本地分支多了一次兼并记载C6,这是由于git pull 等同于 git fetch + git merge操作,先从远端拉取分支,接着再履行兼并操作(如有抵触需解除抵触),因而增加了一次提交记载C6;

图5为履行git pull –rebase操作,能够看到咱们本地的提交直接变基到了C5后边,并且没有增加提交记载,呈现出一条直线,这是由于git pull –rebase这个操作其实能够拆分为fetch+rebase操作,先从远端同步分支,接着再履行rebase操作。所以说这两个指令其实差别是在拉取分支后是履行了merge操作,仍是rebase操作。

(2)Rebase原理

咱们能够看到,通过merge更新操作长途此时也变成了非直线方法,且有多了一次merge记载,而rebase更新操作此时变成了一条直线方法,且没有增加提交记载。现在能够总结下,rebase有以下特点:

(1)Rebase之后会改动提交前史记载,分支不再岔开,而是变成了一条直线;

(2)rebase 之后假定有抵触,解抵触时需把每次的commit都解一遍;

(3)rebase之后没有保存merge记载,意味着没有保存这步的操作,而git的含义不便是保存记载吗?

为什么选用rebase办法来完结兼并操作会有merge有这么多的不同呢?其实所谓的变基(rebase), 指的便是将提交到某一分支的一切修正在另一分支上再运用一次, 也便是想修正移动到另一个分支上. 看上去就好像是其base commit发生了变化。咱们能够从git源码上得知,rebase便是调用了屡次merge。

咱们能够从一个比如上直观表明一下rebase每一步都做了什么,如下图所示:在feature上rebase dev时,git会以dev分支对应的commit节点作为起点,将feature上commit节点”变基“至dev commit的后边,并且会创立全新的commit节点来代替之前commit,实践上rebase操作能够拆分红一系列的merge操作,现在咱们看一下rebase的进程中git所做的事情:首要咱们需求以C1作为base节点,C2和C4进行兼并生成新的C5,然后再将C5的parent指向C4。C3到C6改变进行了相同的步骤。由于相比较之前的commit,新的commit的parent变了,对应的hash值自然也变了。因而咱们在rebase的时分,当时分支有几个commit记载那么git就需求进行兼并几回。假定当时分支比较”干净“,只有一个commit记载的话,那么你rebase需求解的抵触其实和merge是相同的,区别便是rebase不会独自生成一个新的commit来记载这次兼并。

2.4 关于Merge和Rebase的一些讨论

(1)Rebase的一些问题

  • Rebase会修正前史记载

咱们可能都看过git文档(pro-git)里的经典戒律: Do not rebase commits that exist outside your repository and that people may have based work on. 假定在你的repo外, 有人根据你的某些commit在开发, 那么你就不应该对这些commit做rebase. 文档里说得很严重, 假定你不恪守这条准则, 或许说是戒律, 你会被人民仇视, 会被亲友唾弃。之所以整这么严重, 是由于rebase操作的本质是丢掉一些既有的提交, 然后相应地新建一系列改变内容相同但不相同的commit目标。假定这个提交在rebase前被推到了远端同享, 并且其他人也在根据它做开发, 那么当他们试图提交的时分, 就得做所谓的remerge了。不论是merge仍是rebase, 兼并行为都会发生, 并导致有端点(commit)被提交. 只不过在rebase中, 兼并发生在被依次运用每个差量, 伴跟着在一个分支中创立来自另一个分支的改变的线性前史而完结. 而一般的三路兼并则只是修正端点本身。

  • Rebase可能会导致一系列过错的提交

rebase除了修正前史记载之外, 还有更深远的效果: rebase会导致一系列新的提交. 尽管这些提交组合起来, 最后会到达相同的终究状况, 但中心的提交有新的SHA-1, 根据新的初始状况, 代表不同的差异。因而, 相较于merge, rebase的典型问题是: 它事实上被视为”将源分支上的一切修正逐项地运用到目标分支上”, 就之条件到的: “两种整合办法在分支的终究成果上文件内容与结构上毫无区别”, 但也仅此罢了——这些由于逐项运用发生的新提交对应的版别在实际里从来没有存在过, 没有人真实出产了这些提交, 也没有人能证明它们是可行的。

咱们看一个比如:在commit2中界说了一个函数, 接受数字或字符串类型. 在commit4中调用了这个函数, 传入了一个数字. 紧接着由于函数func保护的同学告诉说从commit3今后不兼容数字方法了, 需求依靠方做修正(page/page2). 因而, 在commit5中, 咱们增加上了对类型的修正. 这个时分去rebase代码, 将commit4和commit5迁移成commit4’和commit5′, 这个时分, commit5’是完全正确且安全的, 可是假定咱们commit5里有过错, 期望回退到commit4’去, 问题就大条了. 由于commit4’事实上没有任何人测验过, 也不是开发者特意上传的内容. 并且能够看见, 在这个比如里, 是完全通不过类型系统的检查的。

(2)其它相关场景举例

咱们曾经在团队内部做了一个关于merge和rebase合理运用的调查问卷, 有一个主张是期望能够从二者的原理出发, case by case来剖析场景和躲避途径,下面列出了一些作者本人或搭档们在实践开发中遇到的一些问题场景:

场景1:慎重运用 force push

首要来共享下团队内部曾经在git上踩过的坑:

如上图所示,A同学和B同学共用一个研制分支,B同学现已提交了两次commit并推送到了远端。之后,A同学也现已开发完结,咱们能够看到A同学的本地库房分支现已落后于远端,理应先从远端更新分支,再推送到远端。可是A同学没有这么做,如下图所示,而是直接force push了上去,就导致了下面这种状况,B同学的C3、C4提交记载被“丢掉”掉了。

此时的补救的办法能够是:B同学更新远端分支(git pull 或 git pull –rebase),再提交上去,提交前史变为下图:

那么咱们应该怎么避免这个问题呢:

(1)提交代码时慎重运用force push,主张运用push(原因:假定咱们运用push推送时,本地分支落后远端时会有提示)

(2)A正确提交办法:先更新本地分支,再推送到远端。

咱们怎么更新本地分支:两种办法merge或rebase,下面是两种指令更新后的分支示意图

咱们能够看到,选用merge更新的办法,多了一条兼并记载C6,而rebase则是直接把记载从C5改变到了C4’提交的后边且没有多一次的提交记载。

场景2:rebase解抵触

咱们知道,在选用rebase办法更新代码时,假定有抵触 解抵触时需把每次的commit都解一遍。咱们设想这样一种场景,feature分支上共有三次提交,咱们在处理抵触1和抵触2时假定包括了第三次提交的全部变动内容,咱们在推代码后会奇特的发现C5记载不见了,这是由于rebase兼并的本质是丢掉掉原有的提交,而另创立与原提交记载“类似”的提交,通过上述办法解抵触后,新的C5’现已没有任何新的改动,所以C5会被“丢掉掉”。

场景3:merge和rebase的提交前史差异

咱们能够直观看到,通过rebase更新操作提交前史变成了一条直线方法,而通过merge更新操作长途的提交前史为非直线方法,且由于更新(而不是兼并)多了一次merge记载。可是rebase也有许多缺陷:

(1)rebase 之后 假定有抵触 解抵触时需把每次的commit都解一遍。

(2)rebase之后没有保存merge记载,意味着没有保存这步的操作,而git的含义不便是保存记载吗?

可是假定咱们换一种思路考虑,咱们在本地分支中运用 rebase 来更新,是为了让咱们的本地提交记载更加明晰可读。(当然, rebase 不只用来兼并 master 的改动,还能够在协同开发时 rebase 队友的改动)而主分支中运用 merge 来把 feature 分支的改动兼并进来,是为了保存分支信息。那么怎么适宜的运用rebase和merge呢?假定全运用 merge 就会导致提交前史繁复穿插,错综复杂。假定全运用 rebase 就会让你的commits history变成一条光溜溜的直线。因而,一个好的commits history,应该是这样的,有兼并记载且分支不交织:

*   e2e6451 (HEAD -> master) feture-c finished
|\
| * 516fc18 C.2
| * 09112f5 C.1
|/
*   c6667ab feture-a finished
|\
| * e64c4b6 A.2
| * 6058323 A.1
|/
*   2b24281 feture-b finished

而不应该是这样的,分支交织,看起来很混乱:

*   9f0c13b (HEAD -> master) feture-c finished
|\
| * 55be61c C.2
| *   e18b5c5 merge master
| |\
| |/
|/|
* |   ee549c2 feture-a finished
|\ \
| * | 51f2126 A.3
| * |   72118e2 merge master
| |\ \
| |/ /
|/| |
* | |   6cb16a0 feture-b finished
|\ \ \
| * | | 7b27b77 B.3
| * | | 3aac8a2 B.2
| * | | 2259a21 B.1
|/ / /
| * | 785fab7 A.2
| * | 2b2b664 A.1
|/ /
| * bf9e77f C.1
|/
* 188abf9 init

也不应该是这样的,完全呈一条直线,没有任何的兼并记载:

* b8902ed (HEAD -> master) C.2
* a4d4e33 C.1
* 7e63b80 A.3
* 760224c A.2
* 84b2500 A.1
* cb4c4cb B.3
* 2ea8f0d B.2
* df97f39 B.1
* 838f514 init

(3)Merge和Rebase的比照以及运用主张

咱们通过上述比如得知,rebase和 merge 不是二选一的联系,要协同运用。当开发只归于自己的分支时尽量运用rebase,削减无用的commit合到主分支里,多人协作时尽量运用merge,一方面削减抵触,另一个方面也让每个人的提交有迹可循。依照上述思路来说,咱们依照如下规则能够合理运用rebase和merge操作:

(1)假定咱们只注重于更新操作时,rebase操作可能会更好些,由于没必要多生成一个除了开发外的merge记载,也能够让咱们的本地提交记载明晰可读。

(2)当咱们要把研制分支合入到骨干时,咱们更注重的是兼并的操作,保存兼并的记载,这个时分用merge会好些。

merge rebase
– 原理 三路兼并 屡次merge
– 对前史的看法 “提交”的前史 “改变”的前史
– 对前史的态度 咱们应当保存每一次提交的现场, 不应该对其做修正. 咱们应当使改变足够明晰, 每一次改变的内容和在提交链上的方位应当能体现出它的用处何意图.
– 优点/缺陷:
(1)是否保存兼并记载 保存兼并记载✅ 不会保存兼并记载
(2)前史提交记载 分支交织 提交记载呈直线型更清新
(3)更新代码提交记载 更新代码时会增加一条兼并记载 更新代码时不会增加兼并记载✅
(4)解抵触 兼并代码有抵触时,只需处理一次✅ 每个commit都需求别离解抵触
– 适用场景
(1)feature分支合入骨干 保存兼并记载✅
(2)更新代码 落后骨干提交过多时估计抵触较多✅ 更新代码时,且估计抵触不多✅

附录 Git兼并常用指令汇总收拾

假定当时在feature分支,公共开发分支为feature,示意图如下:

(1)merge

# feature分支与dev分支兼并
git merge dev 
# 禁用主动提交
git merge --no-commit dev 
# 禁用快进兼并(保存merge记载)
git merge --no-ff dev
# 将dev分支的commit压缩成一个再兼并
git merge --squash dev
# 指定兼并战略(如ours、subtree,默以为recursive和octopus)
git merge -s <strategy> dev
# 显现具体的兼并成果信息
git merge -v dev
# 显现兼并的进展信息(不显现--no-progress)
git merge -progress dev
# 创立兼并节点时的提交信息
git merge -m "" dev
# 兼并抵触
git merge --continue
# 扔掉当时兼并抵触的处理进程并尝试重建兼并前的状况
git merge --abort

(2)rebase

# 将feature分支变基到dev分支上 
git rebase dev
# 交互式修正或兼并commit记载,具体运用可见https://www.jianshu.com/p/4a8f4af4e803
git rebase -i [startpoint]  [endpoint]
# 拉取长途分支后选用rebase办法兼并代码
git pull --rebase
# 兼并抵触
git rebase --continue
# 将feature分支从feature0分支变基到到master
git rebase --onto master feature0
# 放弃此次rebase
git rebase --abort

(3)cherry-pick

# 把其他分支的某一个commit合入到当时分支
git cherry-pick <commit id> 
# 兼并中有抵触,处理完后需求履行下面指令
git cherry-pick --continue

hi, 我是快手电商的小昊和顾昂~

快手电商无线技术团队正在招贤纳士🎉🎉🎉! 咱们是公司的核心事务线, 这儿云集了各路高手, 也充满了机会与应战. 伴跟着事务的高速发展, 团队也在快速扩张. 欢迎各位高手参加咱们, 一同创造世界级的电商产品~

热招岗位: Android/iOS 高档开发, Android/iOS 专家, Java 架构师, 产品司理(电商布景), 测验开发… 很多 HC 等你来呦~

内部引荐请发简历至 >>>咱们的邮箱: hr.ec@kuaishou.com <<<, 补白我的诨名成功率更高哦~ 😘