Git使用总结五:分支管理

前些时间,公司产品经理针对司机端提出一个微信及支付宝二维码扫码支付需求,需求不急,但也是刚性任务,于是我在会后便火急火燎开干,期间碰到一些问题获取了一些经验,想分享给各位。

第一个问题,期间,或许因为公司反复修网造成GitLab地址变动,管理GitLab的后台并没有多余的时间来维护,所以短时间内,并不能将本地的修改 push 到远程。这种情况下,我将每次的修改 commit 到本地,等GitLab好了再 push,对此我深刻感受到Git的好处。

第二个问题,在公司我负责iOS移动端的独立开发与维护。由于是独立开发,使用Git时,我一般在 devfix bug 或者改需求。此次,我需求完成一半,测试那边给出反馈,我放下手头需求,紧急 fix bugcommit 到本地后,在无法 push 到远程的情况下,我需要紧急提交一个新版本。问题来了,由于GitLab未修复,我无法clone上个版本到本地来fix bug,又因为我dev分支上同时fix bug和迭代需求,本地也不是上一个版本。

创建与合并分支

在Git里,每次提交,Git把提交串成一个分支,这个分支是主分支,即 master 分支。HEAD 不是指向提交,而是指向 mastermaster 才指向提交,所以,HEAD指向的是当前分支。

Git创建一个 dev 分支时很快,因为除了需要增加一个 dev 指针,改变 HEAD 的指向,工作区的文件没有变。

Git合并 dev 分支到 master 分支也很快,在 dev 上完成工作后,直接把 master 指向 dev 当前的提交,就完成了合并。合并过程中,指针指向改变,工作区内容同样没有变。

  • 创建 dev 分支,然后切换到 dev 分支
git checkout -b dev
  • 创建分支
git branch <name>
  • 切换分支
git checkout <name>
  • git branch 查看当前分支
$ git branch
* dev
  master
  • git merge 命令用于合并指定分支到当前分支
git merge <name>
  • 删除分支
git branch -d <name>

解决冲突

  • 创建并切换 feature 分支
$ git checkout -b feature
Switched to a new branch feature
  • 修改工作区内容后,在 feature 分支上提交修改并且将暂存区的修改 commit 到当前分支
$ git add readme.txt
$ git commit -m "and simple"
[feature 75a857c] and simple
1 file changed, 1 insertion(+), 1 deletion(-)
  • 切换到 master 分支,系统将会提示当前 master 分支彼远程的 master 分支要超前一个提交
$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 1 commit
  • master 分支上把工作区内容进行修改,并且提交
$ git add readme.txt
$ git commit -m "& simple"
[master 400b400] & simple
1 file changed, 1 insertion(+), 1 deletion(-)
  • 此刻在master分支和feature分支都要提交的情况下,Git无法进行快速合并,如果试图把各自的修改合并,将会造成冲突。
$ git merge feature
Auto-merging readme.txt
CONFLICT (content): Merge conflict in readme.txt
Automatic merge failed; fix conflicts and then commit the result.
  • Git将会提示,readme.txt文件存在冲突,必须手动解决冲突后再提交,我们一般使用 git status 了解我们冲突的文件。
$ git status
# On branch master
# Your branch is ahead of 'origin/master' by 2 commits.
#
# Unmerged paths:
#   (use "git add/rm <file>..." as appropriate to mark resolution)
#
#       both modified:      readme.txt
#
no changes added to commit (use "git add" and/or "git commit -a")
  • 直接查看readme.txt文件夹下内容,Git用 <<<<<<<=======>>>>>>> 标记出不同分支的内容,我们修改文件夹下内容使 feature 分支和 master 分支保持一致后,再提交。

  • 使用带参数的 git log 也可以看到分支的合并情况

$ git log --graph --pretty=oneline --abbrev-commit
*   59bc1cb conflict fixed
|\
| * 75a857c AND simple
* | 400b400 & simple
|/
* fec145a branch test
...
  • 最后删除分支
$ git branch -d feature
Deleted branch feature (was 75a857c).
  • 所以说,当Git无法自动合并分支时,就必须首先解决冲突,解决冲突后,再提交,合并完成。使用 git log --graph 命令可以查看分支合并图

分支管理策略

在解决冲突时,我们提到了快速合并,通常,我们在合并分支时,Git会使用 Fast forward 模式,在 Fast forward 模式下,删除分支后,会丢失分支信息。

所以,我们会强制禁用 Fast forward 模式,Git会在 merge 时生成一个新的 commit,这样我们可以在分支历史上查看分支信息。

--no-ff方式的git merge

  • 首先,创建并切换 dev 分支
$ git checkout -b dev 
Switched to a new branch dev
  • 修改工作区readme.txt文件,并提交一个新的 commit
$ git add readme.txt 
$ git commit -m "add merge"
[dev 6224937] add merge
 1 file changed, 1 insertion(+)
  • 切换回 master
$ git checkout master
Switched to branch 'master'
  • 合并 dev 分支时,注意使用 --no-ff 参数,表示禁用 Fast forward
$ git merge --no-ff -m "merge with --no-ff" dev
Merge made by the 'recursive' strategy.
 readme.txt |    1 +
 1 file changed, 1 insertion(+)
  • 合并后我们使用 git log 查看分支历史
$ git log --graph --pretty=oneline --abbrev-commit
*   7825a50 merge with no-ff
|\
| * 6224937 add merge
|/
*   59bc1cb conflict fixed
...

分支策略

其实,我们在实际开发中,应该按照几个基本原则进行分支管理:

  1. 首先,master 分支应该是最稳定的,也就是说,我们平时不能在 master 上干活,master 分支仅用来发布版本使用。

  2. 如果要干活,我们应该创建并切换一个分支,这个分支就是 dev 分支。也就是说,dev 分支是不稳定的,平时我们各自在 dev 分支上干活,每个人有自己的分支,不断往 dev 分支上合并,等到版本发布时,再把 dev 分支合并到 master 上。

Bug分支

当前,正在 dev 上的工作还没提交,我们需要经紧急修复一个bug,很自然地,需要创建一个 bug 分支来修复这个bug。有人会有疑问,为什么不把 dev 上工作区的修改先进行提交,其实我们并不是不想提交,而是工作进行到一半无法提交。那么,Git为我们提供一个 stash 功能,先把当前工作现场“储藏”起来,等恢复现场后继续工作。

$ git stash
Saved working directory and index state WIP on dev: 6224937 add merge
HEAD is now at 6224937 add merge
  • git stash 后,我们用 git status 查看工作区,工作区是干净的,我们可以放心创建分支修复bug。

  • 确定在那个分支上修复bug,就在那个分支上创建bug分支。此次我们在 master 上修复,就从 master 上创建临时分支。由于创建的 bug 分支是临时分支,修复bug后,切换到 master 分支,完成合并,最后删除 bug 分支。

  • 接着我们回到 dev 干活,使用 git status 查看工作区状态,发现工作区是干净的,这是我们需要使用 git stash list 查看存的工作现场。

$ git stash list
stash@{0}: WIP on dev: 6224937 add merge
  • 使用 git stash apply 恢复,但是恢复后,stash内容不会删除,需要使用 git stash drop 删除stash内容。

  • 或者,使用 git stash pop,恢复的同时把stash内容也删除了。

$ git stash pop
# On branch dev
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       new file:   hello.py
#
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   readme.txt
#
Dropped refs/stash@{0} (f624f8e5f082f2df2bed8a4e09c12fd2943bdd40)
  • 使用 git stash pop 后,使用 git stash list 查看,就看不到stash内容了。

Feature分支

一般情况下,添加一个新功能,需要创建一个 feature 分支,feature 分支作为临时开发新功能的分支最终要合并到 dev 分支,也就是说,我们添加一个新功能,并不是在 dev 上进行开发,而是要创建一个 feature 分支,而这个 feature 分支用于临时开发一个新功能,是一个临时分支。

  • 其实,feature 分支和 bug 分支类似,创建切换,合并,然后删除。

  • 取消新功能时,使用 git branch -d <name> 删除分支,但是会提示销毁失败,这时需要强行删除分支,使用命令 git branch -D <name>

$ git branch -D feature-vulcan
Deleted branch feature-vulcan (was 756d4af).
  • 所以,如果要丢弃一个没有被合并的分支,可以通过 git branch -D <name> 强行删除这个分支。

多人协作

真正意义上,Git的价值还是体现在团队协作作用上,而那些命令其实仅仅起到辅助协作的作用,如果是独立开发并不能深刻体会到这种协作的作用,但是如果进入纯技术公司团队,可能Git的这种协作价值才能真正的体现出来。

  • 从远程仓库 clone 时,实际上Git自动把本地 master 分支和远程 master 分支对应起来了,并且,远程仓库默认的名称是 origin

  • 所以说,我们使用 git remote 查看远程仓库的信息

$ git remote
origin
  • 或者,用 git remote -v 查看远程库详细信息
$ git remote -v
origin  git@github.com:michaelliao/learngit.git (fetch)
origin  git@github.com:michaelliao/learngit.git (push)

推送分支

  • master 分支在本地作为主分支,要时刻与远程仓库同步。

  • dev 分支是开发分支,团队所有成员都需要在 dev 分支上工作,所以 dev 分支同样需要与远程同步。

  • bug 分支作为临时分支,只在本地修复bug,没有必要推送到远程,可能一周推送一次。

  • feature 分支同样是临时分支,但是,feature 分支是否推送到分支,取决于是否团队协作,如果是独立开发,feature 分支没有必要推送到远程,如果协作开发,需要推送到远程,与远程保持同步。

抓取分支

  • 从远程库 clone 时默认只能看到本地的 master 分支,我们可以使用 git stauts 查看。
$ git branch
* master
  • 要在 dev 分支上开发,必须创建远程 origindev 分支到本地,可以使用 git checkout -b dev origin/dev 命令创建本地 dev 分支。
$ git checkout -b dev origin/dev
  • 可以在本地创建的这个 dev 分支上修改,并且把修改 commitdev 分支,然后把 dev 分支 push 到远程。
$ git commit -m "add /usr/bin/env"
[dev 291bea8] add /usr/bin/env
 1 file changed, 1 insertion(+)
$ git push origin dev
Counting objects: 5, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 349 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@github.com:michaelliao/learngit.git
   fc38031..291bea8  dev -> dev
  • 由于你已经向 origin/dev分支 推送了提交,而devB碰巧对同样的文件做了修改,并且试图推送,由于我的最新提交和devB试图推送的提交有冲突,所以,推送失败。
$ git add hello.py 
$ git commit -m "add coding: utf-8"
[dev bd6ae48] add coding: utf-8
 1 file changed, 1 insertion(+)
$ git push origin dev
To git@github.com:michaelliao/learngit.git
 ! [rejected]        dev -> dev (non-fast-forward)
error: failed to push some refs to 'git@github.com:michaelliao/learngit.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Merge the remote changes (e.g. 'git pull')
hint: before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
  • 这时,Git提醒,先用 git pull 把最新的提交从 origin/dev 抓取下来,然后,在本地合并,先解决冲突,然后再推送到远程。
$ git pull
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 3 (delta 0)
Unpacking objects: 100% (3/3), done.
From github.com:michaelliao/learngit
   fc38031..291bea8  dev        -> origin/dev
There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details

    git pull <remote> <branch>

If you wish to set tracking information for this branch you can do so with:

    git branch --set-upstream dev origin/<branch>
  • git pull 失败,因为未指定本地 dev 分支和远程 origin/dev 分支链接,所以,设置 dev 和远程 origin/dev 的链接。
$ git branch --set-upstream dev origin/dev
Branch dev set up to track remote branch dev from origin.
  • git pull 成功后,git merge 合并存在冲突,先手动解决冲突,然后提交,最后 push 到远程。
$ git commit -m "merge & fix hello.py"
[dev adca45d] merge & fix hello.py
$ git push origin dev
Counting objects: 10, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (6/6), 747 bytes, done.
Total 6 (delta 0), reused 0 (delta 0)
To git@github.com:michaelliao/learngit.git
   291bea8..adca45d  dev -> dev
  • 请记住,如果 git pull 提示“no tracking information“,则说明本地分支和远程分支的链接关系没有创建,使用命令 git branch --set-upstream branch-name origin/branch-name,以上就是多人协作的工作模式。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,012评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,589评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,819评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,652评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,954评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,381评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,687评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,404评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,082评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,355评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,880评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,249评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,864评论 3 232
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,007评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,760评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,394评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,281评论 2 259

推荐阅读更多精彩内容

  • 1.git的安装 1.1 在Windows上安装Git msysgit是Windows版的Git,从https:/...
    落魂灬阅读 12,580评论 4 54
  • 声明:这篇文章来源于廖雪峰老师的官方网站,我仅仅是作为学习之用 Git简介 Git是什么? Git是目前世界上最先...
    横渡阅读 3,919评论 3 27
  • 远程仓库 到目前为止,我们已经掌握了如何在Git仓库里对一个文件进行时光穿梭,你再也不用担心文件备份或者丢失的问题...
    归云丶阅读 1,885评论 0 5
  • 石头小记 一块奇异形状的石头碎了,散在桌子上,一阵悲伤。 它经历了从大石山到大石头再到小石头的过程,从遥远的...
    碧风寒影阅读 361评论 0 3
  • angularjs是由谷歌公司开发并维护的一款开源的javascript框架,其特点用于构建单页面应用(SPA),...
    家娃阅读 356评论 1 1