美文网首页程序员Git教程ubuntu日常
Git使用总结五:分支管理

Git使用总结五:分支管理

作者: devinlaffer | 来源:发表于2017-03-29 14:40 被阅读338次

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

    第一个问题,期间,或许因为公司反复修网造成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,以上就是多人协作的工作模式。

    相关文章

      网友评论

        本文标题:Git使用总结五:分支管理

        本文链接:https://www.haomeiwen.com/subject/gvgeottx.html