GIT 版本管理 - 3 (分支管理)

男儿欲遂平生志,五经勤向窗前读。这篇文章主要讲述GIT 版本管理 - 3 (分支管理)相关的知识,希望能为你提供帮助。
分支管理分支管理有什么用呢?

  1. 便于协同工作时的版本管理
  2. 便于多任务同步互不干扰的版本管理
创建与合并分支 创建分支
$ git checkout -b dev

上面的命令创建了一个 dev 分支,并且将当前工作区分支从默认的master分支切换到dev分支
其实如果对上面的命令进行拆解,可以用两台命令来完成
$ git branch dev $ git checkout dev

创建分支使用git branch 命令后面跟分支的名称即可
切换分支使用git checkout 后面跟分支的名称即可,感觉很眼熟,是不是哪里用到过?
$ git checkout dev

【GIT 版本管理 - 3 (分支管理)】是的,前面的版本管理中也用到过 git checkout用来丢弃工作区的修改,还原到暂存区的版本
$git checkout — filename

合并分支使用 git branch 可以查看当前版本库中有哪些分支,* 号对应着的是当前正在使用的分支
$ gitbranch * dev master

给dev分支加一个文件,然后提交,最后合并到master分支上去,并且在合并分支后将dev分支删除,合并分支需要使用到git merge 命令,具体操作如下:
$ touch dev.txt $ git add dev.txt $ git commit -m add file dev.txt [dev f8ba521] add filedev.txt 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 dev.txt $ git checkout master Switched to branch master Your branch is up to date with rigion/master. $ git merge dev Updating 801d6f0..f8ba521 Fast-forward dev.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 dev.txt $ git branch -d dev Deleted branch dev (was f8ba521). $ git branch * master $ git push rigion master Enumerating objects: 3, done. Counting objects: 100% (3/3), done. Delta compression using up to 4 threads Compressing objects: 100% (2/2), done. Writing objects: 100% (2/2), 235 bytes | 235.00 KiB/s, done. Total 2 (delta 1), reused 0 (delta 0) remote: Resolving deltas: 100% (1/1), completed with 1 local object. To github.com:zhengbinger/learngit.git 801d6f0..f8ba521master -> master

上面这堆命令,做了很多操作
第一步:使用touch命令新建了一个dev.txt 的文件
第二步:使用git add命令将 dev.txt 文件加入到dev分支本地仓库的暂存区
第三步:使用git commit命令将暂存区的修改内容提交到本地仓库
第四部:使用git checkout 命令切换到master分支
第五步:在master 分支上使用 git merge 命令合并dev分支上的修改
第六步:使用git branch -d 命令删除dev分支
第七步:使用git branch 查看当前分支
第八步:使用git push推送当前master 上的修改到远程仓库
ok,那么我们这次操作中涉及到的分支操作内容有,创建分支、合并分支、删除分支相关的操作,并且推送到了远程仓库
解决冲突模拟场景
$ gitcheckout -b features $ vi readme.txt Git is a distributed version control system. Git is free software distributed under the GPL. Git has a mutable index called stage. Git tracks changes of files. Creating a new branch is quick & simple $ git add readme.txt $ git commit-m AND simple [features db758c4] AMD simple 1 file changed, 1 insertion(+) $ gitcheckout master Switched to branch master Your branch is up to date with rigion/master. $ vi readme.txt $ gitadd readme.txt $ git commit -m & simple $ git merge features Auto-merging readme.txt CONFLICT (content): Merge conflict in readme.txt Automatic merge failed; fix conflicts and then commit the result. $ git status On branch master Your branch is ahead of rigion/master by 1 commit. (use "git push" to publish your local commits)You have unmerged paths. (fix conflicts and run "git commit") (use "git merge --abort" to abort the merge)Unmerged paths: (use "git add < file> ..." to mark resolution)both modified:readme.txtno changes added to commit (use "git add" and/or "git commit -a") $ vireadme.txt Git is a distributed version control system. Git is free software distributed under the GPL. Git has a mutable index called stage. Git tracks changes of files. < < < < < < < HEAD Creating a new branch is quick & simple. ======= Creating a new branch is quick AND simple. > > > > > > > features $ gitadd readme.txt $ git commit-m resolved fixed [master e68db6c] resolvedfixed $ gitstatus On branch master Your branch is ahead of rigion/master by 3 commits. (use "git push" to publish your local commits)nothing to commit, working tree clean $ gitlog --graph --pretty=oneline *e68db6ce2192645403c90a311c25cee52fcde1e7 (HEAD -> master) resolvedfixed |\\ | * db758c4fd8de9f31e87bcb81787f7fd20db977b5 (features) AMD simple * | c0264af950e75a512dc9895c9b3806c9ed4438ed & simple |/ * f8ba521f52ca2b4f6510ec3a35d7929fcde8d937 (rigion/master) add filedev.txt * 801d6f066eecf1270920a361659dd61db3257457 add mutiplefiles * ceebf2660aa2eea2f6c4e96a78dd5be08f728f6c add file test.txt * 65d43dc687b35173b2d312bf7b71eb7593bc88ca append of files * 400bdba9be3de24fb6077ef573564b6998af5cc9 tracks files * e17c4d4d2d8d2893009f3e56e7711657055ef779 understand stage * 7dc80a9b6475908835ab78562d7db68fda83757c appendGPL * 56fb09bdfefc467e9b2f5aba2060c215c19f68c9 updatereadme.tct * 9235ffdcced6c829b3f0fb991d5548c14fe49dc7 addreadme.txt $ gitbranch -d features Deleted branch features (was db758c4).

说明:版本冲突产生的根源:同一处修改记录存在两个不同的分支进行了修改的情况,git会认为有版本冲突
场面的场景中 features 分支在readme.txt文件末尾添加了一行内容:Creating a new branch is quick & simple 并提交到版本库
然后切换到mastermaster 在未进行合并的情况下,同样在readme.txt 文件的末尾添加了一行内容
Creating a new branch is quick and simple 并提交到版本库
在没有进行合并的情况下我们和git并不知晓两个版本存在冲突
但是在我们将master分支与features分支进行合并的时候,git会发现这两个分支修改了同一处内容,所以需要手动去处理冲突之后再进行提交才能够合并两个版本的内容
分支管理策略git 默认的master 分支常用作上线分支,一般不进行轻易改动,到上线前才将开发分支上经过充分测试,没有问题的版本内容合并到master主分支进行上线版本整理
然后会有一个dev分支用来日常开发,每个开发人员通过拉取dev分支的内容并且创建自己的分支来进行开发,开发完成之后合并dev分支,测试环境可以拉取dev分支进行测试环境发布
分支合并时默认情况下git会使用 Fast-Forward 快速合并分支,使用这种模式的话,在删除被合并掉的分支后,不会留痕迹的,当然我们也可以在合并的时候使用参数 --no-ff 来配置不使用快速合并,这时在要合并的分支上回创建一次commit
这样的话,即使在合并之后删除被合并的分支,在合并分支上也会留下一次commit的痕迹,便于后期查找修改记录的来源
$ git checkout-b zhengbing_dev Switched to a new branch zhengbing_dev $ gitbranch master * zhengbing_dev $ rm readme2.txt $ gitstatus On branch zhengbing_dev Changes not staged for commit: (use "git add/rm < file> ..." to update what will be committed) (use "git checkout -- < file> ..." to discard changes in working directory)deleted:readme2.txtno changes added to commit (use "git add" and/or "git commit -a") $ git rm readme2.txt rm readme2.txt $ gitcommit -m delete readme2.txt [zhengbing_dev a2fb2cd] delete readme2.txt 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 readme2.txt $ gitcheckout master Switched to branch master Your branch is ahead of rigion/master by 3 commits. (use "git push" to publish your local commits) $ git merge zhengbing_dev --no-ff Removing readme2.txt Merge made by the recursive strategy. readme2.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 readme2.txt $ git log --pretty=oneline 4464110564988026594dd4263d707c10577074da (HEAD -> master) Merge branch zhengbing_dev a2fb2cda5f71231c9c0dd3eea6c9d6b673121529 (zhengbing_dev) delete readme2.txt $ git branch -dzhengbing_dev Deleted branch zhengbing_dev (was a2fb2cd). $gitlog--pretty=oneline 4464110564988026594dd4263d707c10577074da (HEAD -> master) Merge branch zhengbing_dev

使用Fast-Forward模式
$ gitcheckout -b zhengbing_dev Switched to a new branch zhengbing_dev $ ll total 8 -rw-r--r--1 zhengbingstaff0 10 13 15:54 LICENSE -rw-r--r--1 zhengbingstaff0 10 16 22:50 china -rw-r--r--1 zhengbingstaff0 10 17 01:03 dev.txt -rw-r--r--1 zhengbingstaff0 10 16 22:50 no -rw-r--r--1 zhengbingstaff0 10 16 22:50 one -rw-r--r--1 zhengbingstaff203 10 19 11:29 readme.txt -rw-r--r--1 zhengbingstaff0 10 14 01:15 test.txt bogon:git zhengbing$ rmno bogon:git zhengbing$ ll total 8 -rw-r--r--1 zhengbingstaff0 10 13 15:54 LICENSE -rw-r--r--1 zhengbingstaff0 10 16 22:50 china -rw-r--r--1 zhengbingstaff0 10 17 01:03 dev.txt -rw-r--r--1 zhengbingstaff0 10 16 22:50 one -rw-r--r--1 zhengbingstaff203 10 19 11:29 readme.txt -rw-r--r--1 zhengbingstaff0 10 14 01:15 test.txt $ git status On branch zhengbing_dev Changes not staged for commit: (use "git add/rm < file> ..." to update what will be committed) (use "git checkout -- < file> ..." to discard changes in working directory)deleted:nono changes added to commit (use "git add" and/or "git commit -a") $ gitrm no rm no $ gitcommit -m delete no [zhengbing_dev fc0536e] delete no 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 no $ gitcheckoutmaster Switched to branch master Your branch is ahead of rigion/master by 5 commits. (use "git push" to publish your local commits) $ gitmergezhengbing_dev Updating 4464110..fc0536e Fast-forward no | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 no bogon:git zhengbing$ git log --pretty=oneline fc0536e853bc505d45375746a3df4d5fd4e2cfad (HEAD -> master, zhengbing_dev) delete no 4464110564988026594dd4263d707c10577074da Merge branch zhengbing_dev a2fb2cda5f71231c9c0dd3eea6c9d6b673121529 delete readme2.txt e68db6ce2192645403c90a311c25cee52fcde1e7 resolvedfixed c0264af950e75a512dc9895c9b3806c9ed4438ed & simple db758c4fd8de9f31e87bcb81787f7fd20db977b5 AMD simple f8ba521f52ca2b4f6510ec3a35d7929fcde8d937 (rigion/master) add filedev.txt 801d6f066eecf1270920a361659dd61db3257457 add mutiplefiles ceebf2660aa2eea2f6c4e96a78dd5be08f728f6c add file test.txt 65d43dc687b35173b2d312bf7b71eb7593bc88ca append of files 400bdba9be3de24fb6077ef573564b6998af5cc9 tracks files e17c4d4d2d8d2893009f3e56e7711657055ef779 understand stage 7dc80a9b6475908835ab78562d7db68fda83757c appendGPL 56fb09bdfefc467e9b2f5aba2060c215c19f68c9 updatereadme.tct 9235ffdcced6c829b3f0fb991d5548c14fe49dc7 addreadme.txt bogon:git zhengbing$ gitbranch-d zhengbing_dev Deleted branch zhengbing_dev (was fc0536e). bogon:git zhengbing$ git log --pretty=oneline fc0536e853bc505d45375746a3df4d5fd4e2cfad (HEAD -> master) delete no 4464110564988026594dd4263d707c10577074da Merge branch zhengbing_dev a2fb2cda5f71231c9c0dd3eea6c9d6b673121529 delete readme2.txt e68db6ce2192645403c90a311c25cee52fcde1e7 resolvedfixed c0264af950e75a512dc9895c9b3806c9ed4438ed & simple db758c4fd8de9f31e87bcb81787f7fd20db977b5 AMD simple f8ba521f52ca2b4f6510ec3a35d7929fcde8d937 (rigion/master) add filedev.txt 801d6f066eecf1270920a361659dd61db3257457 add mutiplefiles ceebf2660aa2eea2f6c4e96a78dd5be08f728f6c add file test.txt 65d43dc687b35173b2d312bf7b71eb7593bc88ca append of files 400bdba9be3de24fb6077ef573564b6998af5cc9 tracks files e17c4d4d2d8d2893009f3e56e7711657055ef779 understand stage 7dc80a9b6475908835ab78562d7db68fda83757c appendGPL 56fb09bdfefc467e9b2f5aba2060c215c19f68c9 updatereadme.tct 9235ffdcced6c829b3f0fb991d5548c14fe49dc7 addreadme.txt

很明显的对比就能看到,没有使用—no-ff的情况下删除被合并的分支后,被删除的分支没有留下任何痕迹
Bug分支考虑两个问题:
  1. 开发某个任务的途中,leader告诉你要修改一个线上的bug,这时开发的内容么有提交,也不能提交,咋办?
  2. bug修复完成之后,最先是提交到master分支了,那么如何将这次bug的提交同步到dev分支?
第一个问题,git 提供了 git stash 来保留当前工作区的内容,等以后切换回开发分支之后,可以继续工作
$ gitcheckout -bzhengbing_dev Switched to a new branch zhengbing_dev bogon:git zhengbing$ ll total 8 -rw-r--r--1 zhengbingstaff0 10 13 15:54 LICENSE -rw-r--r--1 zhengbingstaff0 10 16 22:50 china -rw-r--r--1 zhengbingstaff0 10 17 01:03 dev.txt -rw-r--r--1 zhengbingstaff0 10 16 22:50 one -rw-r--r--1 zhengbingstaff203 10 19 11:29 readme.txt -rw-r--r--1 zhengbingstaff0 10 14 01:15 test.txt $ rm china one $ gitstatus On branch zhengbing_dev Changes not staged for commit: (use "git add/rm < file> ..." to update what will be committed) (use "git checkout -- < file> ..." to discard changes in working directory)deleted:china deleted:oneno changes added to commit (use "git add" and/or "git commit -a") $ gitstash Saved working directory and index state WIP on zhengbing_dev: fc0536e delete no $ gitstatus On branch zhengbing_dev nothing to commit, working tree clean $ git checkout master Switched to branch master Your branch is ahead of rigion/master by 6 commits. (use "git push" to publish your local commits) $ git checkout-bissue-1024 Switched to a new branch issue-1024 $ vireadme.txt Git is a distributed version control system. Git is free software distributed under the GPL. Git has a mutable index called stage. Git tracks changes of files. Creating a new branch is quick AND simple. fix bug-1024 $ git add readme.txt $ gitcommit -mfixbug 1024 [issue-1024 70edc45] fixbug 1024 1 file changed, 1 insertion(+) $ gitmerge -m fixbug1024 issue-1024 Updating fc0536e..70edc45 Fast-forward (no commit created; -m option ignored) readme.txt | 1 + 1 file changed, 1 insertion(+) bogon:git zhengbing$ git branch -d issue-1024 Deleted branch issue-1024 (was 70edc45). $ gitcheckout zhengbing_dev Switched to branch zhengbing_dev $ gitstatus On branch zhengbing_dev nothing to commit, working tree clean $ gitstash list stash@0: WIP on zhengbing_dev: fc0536e delete no bogon:git zhengbing$ gitstashpop Removing one Removing china On branch zhengbing_dev Changes not staged for commit: (use "git add/rm < file> ..." to update what will be committed) (use "git checkout -- < file> ..." to discard changes in working directory)deleted:china deleted:oneno changes added to commit (use "git add" and/or "git commit -a") Dropped refs/stash@0 (bb34ec868164fa0522c4037054524aa0abf7eade) $ git stashlist $ git status On branch zhengbing_dev Changes not staged for commit: (use "git add/rm < file> ..." to update what will be committed) (use "git checkout -- < file> ..." to discard changes in working directory)deleted:china deleted:oneno changes added to commit (use "git add" and/or "git commit -a")

恢复保留区有两种方式,
  1. git apply取出保留区的内容到工作区,但是不会删除stash中的内容
  2. git stashpop取出保留区的内容到工作区,并且同时删除取出的保留记录
git stash可以进行多次操作,可以使用git apply stash@0来取出某一条保留记录
第二个问题:bug修改完成之后的同步问题
因为dev分支是在修改bug之前拉取出来的,那么同样的在dev分支上也同时存在这个bug,那么,如何在不重复在dev分支上进行操作的情况下,将bug修复到dev分支上来呢?
git cherry-pick
git提供了git cherry-pick 可以将其他分支的某次修改同步到当前分支
$ gitbranch master * zhengbing_dev $ gitstash Saved working directory and index state WIP on zhengbing_dev: fc0536e delete no $ gitstatus On branch zhengbing_dev nothing to commit, working tree clean $ git checkout master Switched to branch master Your branch is ahead of rigion/master by 7 commits. (use "git push" to publish your local commits) $ git log --pretty=oneline 70edc45fc6118b1c9fbe1027b1160e0120468938 (HEAD -> master) fixbug 1024 fc0536e853bc505d45375746a3df4d5fd4e2cfad (zhengbing_dev) delete no 4464110564988026594dd4263d707c10577074da Merge branch zhengbing_dev ... $ git checkout zhengbing_dev Switched to branch zhengbing_dev $ git stash pop Removing one Removing china On branch zhengbing_dev Changes not staged for commit: (use "git add/rm < file> ..." to update what will be committed) (use "git checkout -- < file> ..." to discard changes in working directory)deleted:china deleted:oneno changes added to commit (use "git add" and/or "git commit -a") Dropped refs/stash@0 (74a9941a154523548a542a729ffac95bb6ed4c88) $ gitstashlist $ gitcherry-pick 70edc45 [zhengbing_dev 515389b] fixbug 1024 Date: Sat Oct 19 18:11:57 2019 +0800 1 file changed, 1 insertion(+) bogon:git zhengbing$ gitstatus On branch zhengbing_dev Changes not staged for commit: (use "git add/rm < file> ..." to update what will be committed) (use "git checkout -- < file> ..." to discard changes in working directory)deleted:china deleted:oneno changes added to commit (use "git add" and/or "git commit -a") $ vi readme.txt Git is a distributed version control system. Git is free software distributed under the GPL. Git has a mutable index called stage. Git tracks changes of files. Creating a new branch is quick AND simple. fix bug-1024

操作步骤:
  1. 将当前工作区保留到git
  2. 切换分支到master
  3. 找到修复bug的那次修改记录
  4. 切换分支到zhengbing_dev
  5. 将保留区的内容取出并删除保留区内容
  6. 使用 git cherry-pick 将master 上的修改记录同步过来
  7. 检查bug的内容是否已经同步过来
上面操作区,已经看到,我们修改bug的记录已经同步到zhengbing_dev这个分支上来了
新功能开发分支当接到leader的任务要开发一个新功能时,最好不要在dev分支上进行开发,从dev分支上拉取一个新功能的分支来进行开发,因为dev分支会提供给多个开发人员并行开发,所以dev尽量不要让开发人员直接在上面做开发,只做合并,这样的话正常情况下我们只需要按要求在新功能分支上进行开发,完成后合并到dev分支,最后删除新功能分支就可以了,但是如果中途要取消这个分支的功能开发怎么处理呢?在合并前直接销毁就好了,即使合并之后也可以版本回退来取消新功能合并的修改记录,还原到之前的版本(这里不做赘述)
$ git checkout master Switched to branch master Your branch is ahead of rigion/master by 7 commits. (use "git push" to publish your local commits) $ git branch-d zhengbing_dev error: The branch zhengbing_dev is not fully merged. If you are sure you want to delete it, run git branch -D zhengbing_dev. $ gitbranch -D zhengbing_dev Deleted branch zhengbing_dev (was a2237c7).

销毁分支使用git branch -D 即可
多人协作(远程仓库操作)查看远程库信息
$ git remote origion

显示更多详细信息
$ git remote -v origion git@github.com:zhengbinger/learngit.git (fetch) origion git@github.com:zhengbinger/learngit.git (push)

推送修改到远程仓库git push [远程分支名][本地分支名]
$ gitpush origion master Enumerating objects: 17, done. Counting objects: 100% (17/17), done. Delta compression using up to 4 threads Compressing objects: 100% (15/15), done. Writing objects: 100% (15/15), 1.26 KiB | 1.26 MiB/s, done. Total 15 (delta 11), reused 0 (delta 0) remote: Resolving deltas: 100% (11/11), completed with 2 local objects. To github.com:zhengbinger/learngit.git f8ba521..70edc45master -> master

推送当前分支到远程仓库,并在远程仓库创建新的dev分支git pushorigion[要推送的分支名]:[远程分支名-自定义]
$ git push origion zhengbing_dev:dev Enumerating objects: 3, done. Counting objects: 100% (3/3), done. Delta compression using up to 4 threads Compressing objects: 100% (2/2), done. Writing objects: 100% (2/2), 226 bytes | 226.00 KiB/s, done. Total 2 (delta 1), reused 0 (delta 0) remote: Resolving deltas: 100% (1/1), completed with 1 local object. remote: remote: Create a pull request for dev on GitHub by visiting: remote:https://github.com/zhengbinger/learngit/pull/new/dev remote: To github.com:zhengbinger/learngit.git * [new branch]zhengbing_dev -> dev

克隆远程分支到本地,默认情况下只会clone master 分支,克隆下来再进行切换就好
$ git clone git@github.com:zhengbinger/learngit.git

切换并新建dev分支,并且是从远程的dev分支拉取
$ gitcheckout -b dev origion/dev Branch dev set up to track remote branch dev from origion. Switched to a new branch dev

协同开发当自己的dev分支想要push之前有其他人在该分支上进行了修改,那么当前push是不会成功的。
那么要怎么做呢?
先把对方的修改拉取下来gitpull
那么如果对方的修改记录与当前的修改记录存在冲突呢?那git会让你拉取下来再进行手工处理冲突后进行提交处理
还有一种情况下是gitpull 无法都无法处理,就是当前本地版本与远程版本未建立连接的情况
使用命令可以为当前版本与远程版本建立连接git branch --set-upstream-to=origin/< branch> dev
Rebaserebase操作可以把本地未push的分叉提交历史整理成直线;
rebase的目的是使得我们在查看历史提交的变化时更容易,因为分叉的提交需要三方对比
rebase 其实主要功能就是对想在本地提交的历史记录进行整理,让你能够更清楚的去看版本或者分支的历史记录
git删除远程分支
git push origin:zhengbing_dev

    推荐阅读