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

Posted 乡间野农

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 checkout 用来丢弃工作区的修改,还原到暂存区的版本

$   git checkout — filename 

合并分支

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

$ git  branch
* dev
  master

给dev分支加一个文件,然后提交,最后合并到master分支上去,并且在合并分支后将dev分支删除,合并分支需要使用到git merge 命令,具体操作如下:

$ touch dev.txt
$ git add dev.txt
$ git commit -m add file dev.txt
[dev f8ba521] add file  dev.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..f8ba521  master -> 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,那么我们这次操作中涉及到的分支操作内容有,创建分支、合并分支、删除分支相关的操作,并且推送到了远程仓库

解决冲突

模拟场景

$ git  checkout -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(+)
$ git  checkout master
Switched to branch master
Your branch is up to date with rigion/master.
$ vi readme.txt
$ git  add 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.txt

no 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.
<<<<<<< HEAD
Creating a new branch is quick & simple.
=======
Creating a new branch is quick AND simple.
>>>>>>> features
$ git  add readme.txt
$ git commit  -m resolved fixed
[master e68db6c] resolved  fixed
$ git  status
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
$ git  log --graph --pretty=oneline
*   e68db6ce2192645403c90a311c25cee52fcde1e7 (HEAD -> master) resolved  fixed
|\\  
| * db758c4fd8de9f31e87bcb81787f7fd20db977b5 (features) AMD simple
* | c0264af950e75a512dc9895c9b3806c9ed4438ed & simple
|/  
* f8ba521f52ca2b4f6510ec3a35d7929fcde8d937 (rigion/master) add file  dev.txt
* 801d6f066eecf1270920a361659dd61db3257457 add mutiple  files
* ceebf2660aa2eea2f6c4e96a78dd5be08f728f6c add file test.txt
* 65d43dc687b35173b2d312bf7b71eb7593bc88ca append of files
* 400bdba9be3de24fb6077ef573564b6998af5cc9 tracks files
* e17c4d4d2d8d2893009f3e56e7711657055ef779 understand stage
* 7dc80a9b6475908835ab78562d7db68fda83757c append  GPL
* 56fb09bdfefc467e9b2f5aba2060c215c19f68c9 update  readme.tct
* 9235ffdcced6c829b3f0fb991d5548c14fe49dc7 add  readme.txt
$ git  branch -d features
Deleted branch features (was db758c4).

说明:版本冲突产生的根源:同一处修改记录存在两个不同的分支进行了修改的情况,git会认为有版本冲突

场面的场景中 features 分支在readme.txt文件末尾添加了一行内容:Creating a new branch is quick & simple 并提交到版本库

然后切换到master master 在未进行合并的情况下,同样在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
$ git  branch
  master
* zhengbing_dev
$ rm readme2.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:    readme2.txt

no changes added to commit (use "git add" and/or "git commit -a")
$ git rm readme2.txt
rm readme2.txt
$ git  commit -m delete readme2.txt
[zhengbing_dev a2fb2cd] delete readme2.txt
 1 file changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 readme2.txt
$ git  checkout 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 -d  zhengbing_dev
Deleted branch zhengbing_dev (was a2fb2cd).
$  git  log  --pretty=oneline
4464110564988026594dd4263d707c10577074da (HEAD -> master) Merge branch zhengbing_dev

使用Fast-Forward模式

$ git  checkout -b zhengbing_dev
Switched to a new branch zhengbing_dev
$ ll
total 8
-rw-r--r--  1 zhengbing  staff    0 10 13 15:54 LICENSE
-rw-r--r--  1 zhengbing  staff    0 10 16 22:50 china
-rw-r--r--  1 zhengbing  staff    0 10 17 01:03 dev.txt
-rw-r--r--  1 zhengbing  staff    0 10 16 22:50 no
-rw-r--r--  1 zhengbing  staff    0 10 16 22:50 one
-rw-r--r--  1 zhengbing  staff  203 10 19 11:29 readme.txt
-rw-r--r--  1 zhengbing  staff    0 10 14 01:15 test.txt
bogon:git zhengbing$ rm  no
bogon:git zhengbing$ ll
total 8
-rw-r--r--  1 zhengbing  staff    0 10 13 15:54 LICENSE
-rw-r--r--  1 zhengbing  staff    0 10 16 22:50 china
-rw-r--r--  1 zhengbing  staff    0 10 17 01:03 dev.txt
-rw-r--r--  1 zhengbing  staff    0 10 16 22:50 one
-rw-r--r--  1 zhengbing  staff  203 10 19 11:29 readme.txt
-rw-r--r--  1 zhengbing  staff    0 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:    no

no changes added to commit (use "git add" and/or "git commit -a")
$ git  rm no
rm no
$ git  commit -m delete no
[zhengbing_dev fc0536e] delete no
 1 file changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 no
$ git  checkout  master
Switched to branch master
Your branch is ahead of rigion/master by 5 commits.
  (use "git push" to publish your local commits)
$ git  merge  zhengbing_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 resolved  fixed
c0264af950e75a512dc9895c9b3806c9ed4438ed & simple
db758c4fd8de9f31e87bcb81787f7fd20db977b5 AMD simple
f8ba521f52ca2b4f6510ec3a35d7929fcde8d937 (rigion/master) add file  dev.txt
801d6f066eecf1270920a361659dd61db3257457 add mutiple  files
ceebf2660aa2eea2f6c4e96a78dd5be08f728f6c add file test.txt
65d43dc687b35173b2d312bf7b71eb7593bc88ca append of files
400bdba9be3de24fb6077ef573564b6998af5cc9 tracks files
e17c4d4d2d8d2893009f3e56e7711657055ef779 understand stage
7dc80a9b6475908835ab78562d7db68fda83757c append  GPL
56fb09bdfefc467e9b2f5aba2060c215c19f68c9 update  readme.tct
9235ffdcced6c829b3f0fb991d5548c14fe49dc7 add  readme.txt
bogon:git zhengbing$ git  branch  -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 resolved  fixed
c0264af950e75a512dc9895c9b3806c9ed4438ed & simple
db758c4fd8de9f31e87bcb81787f7fd20db977b5 AMD simple
f8ba521f52ca2b4f6510ec3a35d7929fcde8d937 (rigion/master) add file  dev.txt
801d6f066eecf1270920a361659dd61db3257457 add mutiple  files
ceebf2660aa2eea2f6c4e96a78dd5be08f728f6c add file test.txt
65d43dc687b35173b2d312bf7b71eb7593bc88ca append of files
400bdba9be3de24fb6077ef573564b6998af5cc9 tracks files
e17c4d4d2d8d2893009f3e56e7711657055ef779 understand stage
7dc80a9b6475908835ab78562d7db68fda83757c append  GPL
56fb09bdfefc467e9b2f5aba2060c215c19f68c9 update  readme.tct
9235ffdcced6c829b3f0fb991d5548c14fe49dc7 add  readme.txt

很明显的对比就能看到,没有使用—no-ff的情况下 删除被合并的分支后,被删除的分支没有留下任何痕迹

Bug分支

考虑两个问题:

  1. 开发某个任务的途中,leader告诉你要修改一个线上的bug,这时开发的内容么有提交,也不能提交,咋办?
  2. bug修复完成之后,最先是提交到master分支了,那么如何将这次bug的提交同步到dev分支?

第一个问题,git 提供了 git stash 来保留当前工作区的内容,等以后切换回开发分支之后,可以继续工作

$ git  checkout -b  zhengbing_dev
Switched to a new branch zhengbing_dev
bogon:git zhengbing$ ll
total 8
-rw-r--r--  1 zhengbing  staff    0 10 13 15:54 LICENSE
-rw-r--r--  1 zhengbing  staff    0 10 16 22:50 china
-rw-r--r--  1 zhengbing  staff    0 10 17 01:03 dev.txt
-rw-r--r--  1 zhengbing  staff    0 10 16 22:50 one
-rw-r--r--  1 zhengbing  staff  203 10 19 11:29 readme.txt
-rw-r--r--  1 zhengbing  staff    0 10 14 01:15 test.txt
$ rm china one
$ 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:    one

no changes added to commit (use "git add" and/or "git commit -a")
$ git  stash
Saved working directory and index state WIP on zhengbing_dev: fc0536e delete no
$ git  status
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  -b  issue-1024
Switched to a new branch issue-1024
$ 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
$ git add readme.txt 
$ git  commit -m  fix  bug 1024
[issue-1024 70edc45] fix  bug 1024
 1 file changed, 1 insertion(+)
$ git  merge -m fix  bug  1024 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).
$ git  checkout zhengbing_dev
Switched to branch zhengbing_dev
$ git  status
On branch zhengbing_dev
nothing to commit, working tree clean
$ git  stash list
stash@0: WIP on zhengbing_dev: fc0536e delete no
bogon:git zhengbing$ 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:    one

no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@0 (bb34ec868164fa0522c4037054524aa0abf7eade)
$ git stash  list
$ 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:    one

no changes added to commit (use "git add" and/or "git commit -a")

恢复保留区有两种方式,

  1. git apply 取出保留区的内容到工作区,但是不会删除stash中的内容
  2. git stash pop 取出保留区的内容到工作区,并且同时删除取出的保留记录

git stash 可以进行多次操作,可以使用 git apply stash@0 来取出某一条保留记录

第二个问题:bug修改完成之后的同步问题

因为dev分支是在修改bug之前拉取出来的,那么同样的在dev分支上也同时存在这个bug,那么,如何在不重复在dev分支上进行操作的情况下,将bug修复到dev分支上来呢?

git cherry-pick

git提供了git cherry-pick 可以将其他分支的某次修改同步到当前分支

$ git  branch
  master
* zhengbing_dev
$ git  stash
Saved working directory and index state WIP on zhengbing_dev: fc0536e delete no
$ git  status
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) fix  bug 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:    one

no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@0 (74a9941a154523548a542a729ffac95bb6ed4c88)
$ git  stash  list
$ git  cherry-pick 70edc45
[zhengbing_dev 515389b] fix  bug 1024
 Date: Sat Oct 19 18:11:57 2019 +0800
 1 file changed, 1 insertion(+)
bogon:git zhengbing$ 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:    one

no 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.
$ git  branch -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 [远程分支名] [本地分支名]

$ git  push 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..70edc45  master -> master

推送当前分支到远程仓库,并在远程仓库创建新的dev分支 git push origion [要推送的分支名]:[远程分支名-自定义]

$ 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分支拉取

$ git  checkout -b dev origion/dev
Branch dev set up to track remote branch dev from origion.
Switched to a new branch dev

协同开发

当自己的dev分支想要push之前有其他人在该分支上进行了修改,那么当前push是不会成功的。

那么要怎么做呢?

先把对方的修改拉取下来 git pull

那么如果对方的修改记录与当前的修改记录存在冲突呢?那git会让你拉取下来再进行手工处理冲突后进行提交处理

还有一种情况下是git pull 无法都无法处理,就是当前本地版本与远程版本未建立连接的情况

使用命令可以为当前版本与远程版本建立连接 git branch --set-upstream-to=origin/<branch> dev

Rebase

rebase操作可以把本地未push的分叉提交历史整理成直线;

rebase的目的是使得我们在查看历史提交的变化时更容易,因为分叉的提交需要三方对比

rebase 其实主要功能就是对想在本地提交的历史记录进行整理,让你能够更清楚的去看版本或者分支的历史记录

git 删除远程分支
git push origin :zhengbing_dev

以上是关于GIT 版本管理 - 3 (分支管理)的主要内容,如果未能解决你的问题,请参考以下文章

Git配置版本控制与分支管理

Git配置版本控制与分支管理

Git系列Git分支管理

Git与Github学习版本控制和分支管理

Git与Github学习版本控制和分支管理

Git与Github学习版本控制和分支管理