3、分支管理(git笔记)

注意内容:

  • 创建与合并分支
  • 分支管理策略
  • 分支暂存
  • 补丁
  • 多人协作开发

一、创建与合并分支

1.1 相关概念

  • master分支
    默认情况下,master是一条线,git是利用master指向最新的提交(因为master默认指向最新的提交点),再用HEAD指针指向master,就能确定当前分支以及当前分支的提交点。最终发布的就是master分支,但是对于其他的开发者不应该在master上进行修改或编写,应该建立子分支。

  • 子分支
    刚开始建立子分支时,子分支和master分支是指向同一个位置(提交点)的,而此时HEAD指针在子分支创建之后就会发生变化,不再指向master分支,而是指向子分支。也就是说HEAD指针需要指向当前工作的分支。而我们在子分支上进行任何操作(修改,添加)是不会影响到master分支的,而只是子分支向前推进。

  • 合并
    当子分支向前推进的时候,master所指向的位置是不变的,而我们所有的版本都保存在master上,于是这里我们需要将子分支和master分支进行合并。因为我们是在master分支上进行合并操作,那么HEAD指针必须指向master分支(也就是要断开HEAD与子分支)。于是就将master指向的提交点指向了子分支指向的提交点。合并之后我们如果确定不需要再使用子分支了,那么可以将其删除。

1.2 相关操作

  • 创建一个分支brh:
git branch brh
  • 查看
git branch
1

可以看到提示当前的工作区中有两个分支,同时使用*号提示指向master分支。

  • 切换到brh分支
git checkout brh
2

可以看到我们再次查询的时候发现指向了brh分支。
简化操作(创建并切换):

git checkout -b brh

注意:这里我们在之前已经创建了此分支,需要先将之前的同名分支删掉再使用此命令。

  • 删除分支
git branch -d brh

注意:在当前分支上是不能删除此分支的,需要切换到其他分支上再删除。

  • 修改相关文件Hello.java(我们这里在仓库mypro中操作)
public class Hello{
    public static void main(String args[]){
        System.out.println("Hello World");
        System.out.println("Hello World--001");
        System.out.println("Hello World--002");
        System.out.println("Hello World--003");
        System.out.println("modify --001");
        System.out.println("modify --002");
    }
}

此时的修改是在子分支上进行的,我们查询一下:

3

可以看到有明显的提示是在brh分支上。而主分支上的数据是不会改变的。我们可以先将子分支提交,而后在回到主分支上进行查看。
4

可以发现主分支上的文件确实没有改变。

  • 将两个分支都推送到远程仓库中
git remote set-url origin https://github.com/yjaal/mypro.git
git push origin master
git push origin brh
5

但是最终发布的版本一定是master,于是这里需要进行合并。

  • 合并(在主分支上操作)
git merge brh

首先我们分别改变主分支和brh中的Hello.java文件:
master:

public class Hello{
    public static void main(String args[]){
        System.out.println("modify --003");
    }
}

brh:

public class Hello{
    public static void main(String args[]){
        System.out.println("brh--modify --003");
    }
}

然后我们分别提交后推送:

6

这里可以发现这里出现了合并冲突(Automatic merge failed),我们查看冲突的内容:

git status

7

提示信息是修改了两次Hello.java文件,查看此文件:



public class Hello{
    public static void main(String args[]){
<<<<<<< HEAD
        System.out.println("modify --003");
=======
        System.out.println("brh--modify --003");
>>>>>>> brh
    }
}

这表明HEADbrh都有哪些信息,而此时我们是在主分支上,所以HEAD指向master的内容,这里进行了标记。现在就必须手工修改冲突的文件。

  • 手工修改冲突文件Hello.java
    master:
public class Hello{
    public static void main(String args[]){
        System.out.println("modify --003");
        System.out.println("brh--modify --003");
    }
}

这里我们希望主分支和子分支上修改的内容都进行保留,于是文件我们修改如上。然后我们再次进行提交。


8

可以看到冲突已经解决。然后进行推送。


9
  • 在实际开发中存在很多分支合并的情况,那就需要查看分支合并的历史记录
git log --graph --pretty=oneline
10

这里“graph”表示使用绘图的方式进行显示。此是需要删除brh分支


11

二、分支管理策略

之前使用的合并方式都是使用的Fast forward的合并方式,而此种方式只是改变了master的指针,可是有些时候也可以不使用此种快速合并方式,即在合并命令上增减上一个-no-ff的参数,这样就表示在合并之后会自动的生成一个新的提交号,从而保证合并数据的完整性。可以这样理解,之前的合并方式是将子分支合并到master分支上,于是HEAD指向的位置没有改变,而此种方式是让合并之后的文件再次进行提交,而HEAD指向这个新的提交点,也就是主分支向前推进了一步。

  • 创建新的分支:
git checkout -b brh
  • 新建一个新的文件Emp.java
public class Emp{
    public static void main(String args[]){
        System.out.println("the new file Emp.java");
    }
}
  • 提交修改
git add .
git commit -m "create a new file"
  • 切换回master分支
git checkout master
  • 使用非快速的方式合并分支
git merge --no-ff -m "no fast-forward merge" brh

此种方式会有一个新的提交,所以需要加上-m的参数

12

  • 查看一下提交的日志信息
git log --graph --pretty=oneline --abbrev-commit
13

这里我们在后面加上了一些参数,让显示的信息更加简洁。从提示信息中可以看到,出现了一个新的提交号,而之前的合并我们发现好像也有一个提交号,但是那是在合并发生冲突之后我们解决冲突重新提交产生的,并不是在合并的时候产生的。

于是这里我们的分支策略就是:

  • master分支应该是非常稳定的,也就是仅用来发布新版本,不要在此分支上开发。
  • 在各个子分支上进行开发工作,避免出现问题。

三、分支暂存

比如我们正在一个子分支上进行开发,但是突然有新的任务需要马上完成,同时此时我们不能将子分支上的代码提交,因为在实际开发中不能将有问题的或者没开发完的代码提交,于是此时我们就需要将分支暂存起来。

  • 创建并切换到一个新的分支(先将没用的分支删除)
git checkout -b brh
  • 在分支上编写Emp.java文件
public class Emp{
    public static void main(String args[]){
        System.out.println("the new file Emp.java");
        System.out.println("modify --001");
    }
}
  • 将此文件保存在暂存区之中,此时代码还没有开发完成,不能提交
git add .
  • 将此分支暂存
git stash
14

这样此工作场景就暂存起来了,查看:


15

我们在将分支暂存之后仓库的状态是干净的。

  • 此时如果我们要修改的代码还在master分支上,于是我们又切换到master分支上:
git checkout master
  • 再次创建一个新的分支进行开发
git checkout -b dev
  • 修改Hello.java文件
public class Hello{
    public static void main(String args[]){
        System.out.println("modify --003");
        System.out.println("brh--modify --003");
        System.out.println("dve branch modify");
    }
}
  • 提交此分支
git commit -a -m "dev branch modify"
  • 现在如果此分支完成了,那我们需要切换回brh分支上继续开发,但是注意:此时还处于dev分支上。切换回master分支并合并dev分支:
git checkout master
git merge --no-ff -m "merge dev branch" dev
git branch -d dev
  • 此时我们需要切换到brh分支上继续开发,还需要恢复之前的开发状态
git checkout brh
git stash list
16

这里我们回到brh分支上查看了暂存区中的状态,表明brh分支上有一个暂存,同时对于brh上的暂存我们使用此命令在主分支上也是可以查到的。那现在我们需要将暂存区进行恢复。有两种形式,如下。

  • 形式一:先恢复,而后再手工删除暂存
git stash apply
git stash drop
  • 形式二:恢复的同时也将暂存内容删除
git stash pop
17

此时就可以进行开发了。

四、补丁(patch)

补丁就是针对局部代码的修改。在很多的代码维护中,如果按照最早克隆的方式克隆下来再修改,而我们又只是修改一段很小的部分,此时这种方式就太麻烦了,于是这里我们希望将代码的一些补丁信息发给开发者,而开发者需要知道哪些代码被修改了,这样修改的代价就比较低了。git提供了两种方案:一种是使用git diff生成标准的补丁;另一种是使用git format-patch生成git专用的补丁。

4.1 生成标准的补丁

补丁一定是针对文件的修改进行的,这里以Emp.java为例:

//当前状态
public class Emp{
    public static void main(String args[]){
        System.out.println("the new file Emp.java");
    }
}
  • 建立一个新的分支并查看
git  checkout -b cbrh
  • 修改Emp.java文件:
public class Emp{
    public static void main(String args[]){
        System.out.println("the new file Emp.java");
        System.out.println("modfigy --001");
        System.out.println("modfigy --001");
    }
}
  • 比较代码
git diff Emp.java
  • 在cbrh分支上进行提交
git commit -a -m "commit cbrh-001"

注意:此时我们并没有合并到主分支上。

  • 生成补丁文件(myPatch
git diff master > myPatch

此时在仓库中会生成一个补丁文件。这个文件是git可以读懂的信息文件。之后需要模拟另外一个开发者,他是专门进行补丁合并的开发者。

  • 创建并切换到一个新的分支
git checkout master
git checkout -b patchbrh

注意:这里必须先切换到主分支,不然就是在brh上创建分支,那么新建的分支就和brh分支上的内容一样了,就不能进行模拟了。

  • 应用补丁信息
git apply myPatch

18

此时我们查看patchbrh分支中的Emp.java文件就和cbrh分支上的此文件一样了,表示成功应用了此补丁。

  • 提交合并分支patchbrh
git commit -a -m "patch apply"
git checkout master
git merge --no-ff -m "merge patchbrh" patchbrh
19

4.2生成git专用补丁

  • 先进行一个清空:
git branch -D cbrh
git branch -D patchbrh
  • 创建一个分支cbrh
git checkout -b cbrh
  • 修改Emp.java文件
public class Emp{
    public static void main(String args[]){
        System.out.println("the new file Emp.java");
        System.out.println("modfigy --001");
        System.out.println("modfigy --001");
        System.out.println("modfigy --002");
    }
}
  • 提交
git commit -a -m "modify --002"
  • 下面与原始代码进行笔记,并且会自动生成补丁文件
git format-patch -M master

现在表示要与master分支笔记,其中-M就是指定分支。

20

此时就已经生成了一个补丁文件0001-modify-002.patch,这个补丁文件严格来讲是一个email形式的数据,我们需要发送给另一个开发者。

  • 创建并切换到分支patchbrh
git checkout master
git checkout -b patchbrh
  • 应用补丁
git am 0001-modify-002.patch
21
  • 提交补丁文件
git commit -a -m "one patch file"
22

可以看到这里我们直接提交的时候提示我们有一个新增的文件(就是补丁),这里我们先将补丁删除,然后再提交。之后就可以进行代码的更正了。

  • 关于两种补丁方式的说明
    生成标准补丁就是兼容性比较好,如果不是在git管理的仓库上,此类方式生成的补丁是非常容易被接受的;而如果是向公共的开发社区进行代码的补丁更正,那么建议使用git专用的补丁,这样不仅标准,而且也可以将更正人的id公布了。

五、多人协作开发

分支的处理实际上就是为了更好的多人开发做出的准备,那么下面我们利用两个命令行窗口的方式(模拟其他开发者)进行项目代码的编写。首先需要说明几点:

  • 一般master分支是项目的核心分支,只要进行代码的克隆,那么此分支一定会被保存下来;
  • 开发者一般会建立一系列分支,比如,这里建立了一个brh分支进行代码的编写;
  • 如果要进行调试可以建立一个bug分支,如果要增加新功能,则可以建立feature分支。

开始试验:

  • 准备:创建一个新的分支brh
git checkout -b brh
  • 在新的分支上建立一个新的文件Dept.java
public class Dept{
    public static void main(String args[]){
        System.out.println("the new file Dept.java");
    }
}
  • 建此代码进行提交
git commit -a -m "the new file Dept.java"
  • 将两个分支提交到服务器上
git push origin master
git push origin brh
  • 为了模拟另一个开发者,建立另一个命令行窗口(2号),并且将代码复制下来,先要在E:\github\LocalSource中建立一个目录myproclone,然后将项目克隆下来。
git clone https://github.com/yjaal/mypro.git
23
  • 2号窗口中查看分支信息
git branch -a
24

注意:在查看之前我们要进入到仓库的目录。提示信息显示只是将master分支拷贝下来了,但是
brh分支并没有存在。

  • 建立并切换到brh分支上(2号)
git checkout -b brh
  • 将远程服务器上的brh分支的内容拷贝到本地brh分支上(2号)
git merge origin/brh

25

此时我们就将远程brh分支拷贝到了本地brh分支,我们可以看到Dept.java文件已经存在了。

  • 现在2号开发者增加了一个文件Admin.java
public class Admin{
    public static void main(String args[]){
        System.out.println("the new file Admin.java on 2 command window");
    }
}
  • 2号开发者将新的代码进行提交
git add .
git commit -m "the commit of 2 command window"
  • 2号开发者进行推送
git push origin brh
26

此时代码就已经推送到了服务器上了。

  • 1号开发者目录下还只是上一次提交的内容,此时需要取得最新的数据,这里有两种方式可以取得:
git fetch//方式一:表示只是取得最新的分支数据,但是不会发生合并操作
git pull//方式二:取得最新数据并进行合并
27

这里出现了一些错误,指出当前的分支和服务器上的分支没有什么关系,如果要想解决则需要让这两个分支产生关系,而提示信息中也给我们指出了相关的命令。

  • 关系匹配
git branch --set-upstream-to=origin/brh brh
git pull

28

这里我们先进行了关系匹配,而后进行了同步,在仓库中我们会发现新的文件Admin.java。这样就实现了多个开发者之间的关联。

  • 2号开发者修改Admin.java文件
public class Admin{
    public static void main(String args[]){
        System.out.println("the new file Admin.java on 2 command window");
        System.out.println("modify on 2 command window");
    }
}
  • 2号开发者进行提交并推送
git commit -a -m "modify on 2 command window"
git push origin brh
  • 1号开发者也进行了开发者也对Admin.java文件进行了修改:
public class Admin{
    public static void main(String args[]){
        System.out.println("the new file Admin.java on 2 command window");
        System.out.println("modify on 1 command window");
    }
}
  • 1号开发者进行提交
git commit -a -m "modify on 1 command window"
  • 1号开发者进行同步
git pull

29

此时我们会发现出现了问题。因为两位开发者修改了同一个代码,产生了冲突,1号开发者的Admin.java文件如下:

public class Admin{
    public static void main(String args[]){
        System.out.println("the new file Admin.java on 2 command window");
<<<<<<< HEAD
        System.out.println("the new file Admin.java on 1 command window");
=======
        System.out.println("modify on 2 command window");
>>>>>>> 2f31c9c1cdaf9dae08da064828ac51d3ee18febe
    }
}
  • 1号开发者手工解决冲突,保留所有代码Admin.java
public class Admin{
    public static void main(String args[]){
        System.out.println("the new file Admin.java on 2 command window");
        System.out.println("the new file Admin.java on 1 command window");
        System.out.println("modify on 2 command window");
    }
}
  • 再次提交并推送
git commit -a -m "solve confilict"
git push origin brh
30

其实这只是简单的冲突解决,和我们之前的冲突解决基本上是一样的。

最后:这就是分支操作的基本操作步骤。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容