git分支管理

分支就是科幻电影里面的平行宇宙,当你正在电脑前努力学习Git的时候,另一个你正在另一个平行宇宙里努力学习SVN。

如果两个平行宇宙互不干扰,那对现在的你也没啥影响。不过,在某个时间点,两个平行宇宙合并了,结果,你既学会了Git又学会了SVN!

分支在实际中有什么用呢?假设你准备开发一个新功能,但是需要两周才能完成,第一周你写了50%的代码,如果立刻提交,由于代码还没写完,不完整的代码库会导致别人不能干活了。如果等代码全部写完再一次提交,又存在丢失每天进度的巨大风险。

现在有了分支,就不用怕了。你创建了一个属于你自己的分支,别人看不到,还继续在原来的分支上正常工作,而你在自己的分支上干活,想提交就提交,直到开发完毕后,再一次性合并到原来的分支上,这样,既安全,又不影响别人工作。

其他版本控制系统如SVN等都有分支管理,但是用过之后你会发现,这些版本控制系统创建和切换分支比蜗牛还慢,简直让人无法忍受,结果分支功能成了摆设,大家都不去用。

但Git的分支是与众不同的,无论创建、切换和删除分支,Git在1秒钟之内就能完成!无论你的版本库是1个文件还是1万个文件。

创建与合并分支

在版本回退里,你已经知道,每次提交,Git都把它们串成一条时间线,这条时间线就是一个分支。截止到目前,只有一条时间线,在Git里,这个分支叫主分支,即master分支。HEAD严格来说不是指向提交,而是指向mastermaster才是指向提交的,所以,HEAD指向的就是当前分支。

一开始的时候,master分支是一条线,Git用master指向最新的提交,再用HEAD指向master,就能确定当前分支,以及当前分支的提交点:

每次提交,master分支都会向前移动一步,这样,随着你不断提交,master分支的线也越来越长:

当我们创建新的分支,例如dev时,Git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上:

你看,Git创建一个分支很快,因为除了增加一个dev指针,改改HEAD的指向,工作区的文件都没有任何变化!

不过,从现在开始,对工作区的修改和提交就是针对dev分支了,比如新提交一次后,dev指针往前移动一步,而master指针不变:

假如我们在dev上的工作完成了,就可以把dev合并到master上。Git怎么合并呢?最简单的方法,就是直接把master指向dev的当前提交,就完成了合并:

所以Git合并分支也很快!就改改指针,工作区内容也不变!

合并完分支后,甚至可以删除dev分支。删除dev分支就是把dev指针给删掉,删掉后,我们就剩下了一条master分支:

真是太神奇了,你看得出来有些提交是通过分支完成的吗?

下面开始实战。

首先,我们创建dev分支,然后切换到dev分支:

$ git checkout -b dev
Switched to a new branch 'dev'

git checkout命令加上-b参数表示创建并切换,相当于以下两条命令:

$ git branch dev
$ git checkout dev
Switched to branch 'dev'

然后,用git branch命令查看当前分支:

$ git branch
* dev
  master

git branch命令会列出所有分支,当前分支前面会标一个*号。

然后,我们就可以在dev分支上正常提交,比如对readme.txt做个修改,加上一行:

create new branch dev..

然后提交:

$ git add readme.txt
$ git commit -m "create new branch...."
[dev 45ae9a9] create new branch....
 1 file changed, 1 insertion(+)

现在,dev分支的工作完成,我们就可以切换回master分支:

$ git checkout master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.

切换回master分支后,再查看一个readme.txt文件,刚才添加的内容不见了!因为那个提交是在dev分支上,而master分支此刻的提交点并没有变:

现在,我们把dev分支的工作成果合并到master分支上:

$ git merge dev
Updating 90bc1f7..45ae9a9
Fast-forward
 readme.txt | 1 +
 1 file changed, 1 insertion(+)

git merge命令用于合并指定分支到当前分支。合并后,再查看readme.txt的内容,就可以看到,和dev分支的最新提交是完全一样的。

注意到上面的Fast-forward信息,Git告诉我们,这次合并是“快进模式”,也就是直接把master指向dev的当前提交,所以合并速度非常快。

当然,也不是每次合并都能Fast-forward,我们后面会讲其他方式的合并。

合并完成后,就可以放心地删除dev分支了:

$ git branch -d dev
Deleted branch dev (was 45ae9a9).

删除后,查看branch,就只剩下master分支了:

$ git branch
* master

因为创建、合并和删除分支非常快,所以Git鼓励你使用分支完成某个任务,合并后再删掉分支,这和直接在master分支上工作效果是一样的,但过程更安全。

小结

Git鼓励大量使用分支:

查看分支:git branch

创建分支:git branch <name>

切换分支:git checkout <name>

创建+切换分支:git checkout -b <name>

合并某分支到当前分支:git merge <name>

删除分支:git branch -d <name>

解决冲突

人生不如意之事十之八九,合并分支往往也不是一帆风顺的。

准备新的feature1分支,继续我们的新分支开发:

$ git checkout -b feature1
Switched to a new branch 'feature1'

 

修改readme.txt最后一行,改为:

create new branch feature1..

 

feature1分支上提交:

$ git add readme.txt
$ git commit -m "create new branch feature1 first modify"
[feature1 b4309b0] create new branch feature1 first modify
 1 file changed, 1 insertion(+)

切换到master分支:

$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)

Git还会自动提示我们当前master分支比远程的master分支要超前1个提交。

master分支上把readme.txt文件的最后一行改为:

goback master....

提交:

$ git add readme.txt
$ git commit -m "goback master first modify"
[master 0b56936] goback master first modify
 1 file changed, 1 insertion(+)

现在,master分支和feature1分支各自都分别有新的提交,变成了这样:

这种情况下,Git无法执行“快速合并”,只能试图把各自的修改合并起来,但这种合并就可能会有冲突,我们试试看:

$ git merge feature1
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.
  (use "git push" to publish your local commits)
You have unmerged paths.
  (fix conflicts and run "git commit")

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")
复制代码

我们可以直接查看readme.txt的内容:

复制代码
test git modify second
study git
three add
four add modify
five add modify
six add modify
seven add modify
eight add modify ...
create new branch dev..
<<<<<<< HEAD
goback master....
=======
create new branch feature1..
>>>>>>> feature1
复制代码

Git用<<<<<<<=======>>>>>>>标记出不同分支的内容,我们修改如下后保存:

复制代码
test git modify second
study git
three add
four add modify
five add modify
six add modify
seven add modify
eight add modify ...
create new branch dev..
create new branch feature1..
goback master....
复制代码

再提交:

$ git add readme.txt
$ git commit -m "fixed conflicts"
[master 0f3d64a] fixed conflicts

现在,master分支和feature1分支变成了下图所示:

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

复制代码
$ git log --graph --pretty=oneline --abbrev-commit
*   0f3d64a fixed conflicts
|\
| * b4309b0 create new branch feature1 first modify
* | 0b56936 goback master first modify
|/
* 45ae9a9 create new branch....
* 90bc1f7 test name
* c1bdf43 test commit
* dd34c9a no add but commit,because use other parameter
* 4ed30d1 eight modify dify
* b45ca96 eight modify
* 9332d40 seven modify
* 72c6f9b six modify
* f64b5a0 five modify
* de8fd65 four modify
* 83a4b1e three modify
* 01c05cf two modify
* 1acafa7 first modify
* 09c1bba first git
复制代码

最后,删除feature1分支:

$ git branch -d feature1
Deleted branch feature1 (was b4309b0).

小结

当Git无法自动合并分支时,就必须首先解决冲突。解决冲突后,再提交,合并完成。

git log --graph命令可以看到分支合并图。

=========================================================

Branch workflow

Aone2 Git 分支开发部署模型详细解读 http://docs.alibaba-inc.com:8090/pages/viewpage.action?pageId=194872297

分支情况 origin

  • master
  • develop
  • release
    • 20161129163217010_r_release_yingyongming
    • 20161029163217010_r_release_yingyongming
  • feature
    • 20161129_163448_newfeature_1
    • 20161129_163448_newfeature_2
  • hotfix
    • 20161129_163448_hotfix_1
  • tags
    • 20161129163217010_r_release_newfeature_yingyongming 创建分支的时候直接操作: git checkout -b feature/20161129_163448_newfeature_1

  • master:master永远是线上代码,最稳定的分支,存放的是随时可供在生产环境中部署的代码,当开发活动告一段落,产生了一份新的可供部署的代码时,发布成功之后,代码才会由 aone2 提交到 master,master 分支上的代码会被更新。应用上 aone2 后禁掉所有人的 master的写权限
  • develop:保存当前最新开发成果的分支。通常这个分支上的代码也是可进行每日夜间发布的代码,只对开发负责人开放develop权限。
  • feature: 功能特性分支,每个功能特性一个 feature/ 分支,开发完成自测通过后合并入 develop 分支。可以从 master 或者develop 中拉出来。
  • hotfix: 紧急bug分支修复分支。修复上线后,可以直接合并入master。

![](./_image/2016-07-19 19-58-15.jpg?r=60)

Git-Develop 分支模式是基于 Git 代码库设计的一种需要严格控制发布质量和发布节奏的开发模式。develop 作为固定的持续集成和发布分支,并且分支上的代码必须经过 CodeReview 后才可以提交到 Develop 分支。它的基本流程如下:

  • 每一个需求/变更都单独从Master上创建一条Branch分支;
  • 用户在这个Branch分支上进行Codeing活动;
  • 代码达到发布准入条件后aone上提交Codereview,Codereview通过后代码自动合并到Develop分支;
  • 待所有计划发布的变更分支代码都合并到Develop后,系统再 rebase master 代码到Develop 分支,然后自行构建,打包,部署等动作。
  • 应用发布成功后Aone会基于Develop分支的发布版本打一个“当前线上版本Tag”基线;
  • 应用发布成功后Aone会自动把Develop分支的发布版本合并回master;

Branch 命令

  • 查看分支:git branch 、git branch -vgit branch -vv (查看当前分支 tracking 哪个远端分支)、git branch --mergedgit branch --no-merged
  • 创建分支:git branch branchname
    • 例: 基于 master 分支新建 dev 分支 : git branch dev
  • 基于之前的某个 Commit 新开分支: git branch branchname <sha1-of-commit>
    • 例: 基于上线的的提交 a207a38d634cc10441636bc4359cd8a18c502dea 创建 hotfix 分支 : git branch hotfix a207a38
    • 例: 基于 remoteBranch、localBranch、commitId、tag 创建分支均可以 git checkout -b newbranch localBranch/remoteBranch/commitId/tag
    • 例: 创建一个空的分支
       git checkout --orphan gh-pages # 创建一个orphan的分支,这个分支是独立的
       Switched to a new branch \'gh-pages\'
       git rm -rf . # 删除原来代码树下的所有文件
       rm \'.gitignore\'
       #注意这个时候你用git branch命令是看不见当前分支的名字的,除非你进行了第一次commit。添加新的文件,并且 commit 掉,就能看到分支了。
  • 切换分支: git checkout branchname
    • 例: 由分支 master 切换到 dev 分支:git checkout dev
  • 创建新分支并切换到下面:git checkout -b branchname 或者 git branch branchname && git checkout branchname
    • 例:基于 master 分支新建 dev 分支,并切换到 dev 分支上: git checkout -b dev 或 git branch dev && git checkout dev
  • 查看分支代码不同:git diff branchname 比较 branchname 分支与当前分支的差异点,若只看文件差异,不看差异内容:git diff branchName --stat
  • 合并分支:git merge branchname 将 branchname 分支代码合并到当前分支
  • 删除分支:git branch -d branchname 强制删除未合并过的分支:git branch -D branchname
  • 重命名分支: git branch -m dev development 将分支 dev 重命名为 development
  • 查看远程分支:git branch -r 或 git branch -r -v
  • 获取远程分支到本地:git checkout -b local-branchname origin/remote-branchname
  • 推送本地分支到远程:git push origin remote-branchname 或 git push origin local-branchname:remote-branchname
    • 将本地 dev 代码推送到远程 dev 分支: git push (-u) origin dev 或 git push origin dev:dev
    • (技巧)将本地 dev 分支代码推送到远程 master 分支: git push origin dev:master
  • 删除远程分支:git push origin :remote-branchname 或 git push origin --delete remote-branchname
  • 手动跟踪分支,master分支追踪origin/next分支: git branch --track master origin/next 或者 git branch --set-upstream-to=origin/master 看 git 的版本是否支持。
  • TrackingBranch,可以通过 git branch -vv 来查看当前 track 的分支情况。新建立分支时会自动 track 相应远程分支,git checkout -b sf origin/serverfix (Branch sf set up to track remote branch serverfix from origin. Switched to a new branch 'sf'). 也可以手动 track: git branch -u origin/serverfix (Branch serverfix set up to track remote branch serverfix from origin). 等同于命令 git checkout --track origin/serverfix

“Checking out a local branch from a remote branch automatically creates what is called a “tracking branch” (or sometimes an “upstream branch”). Tracking branches are local branches that have a direct relationship to a remote branch. If you’re on a tracking branch and type git pull, Git automatically knows which server to fetch from and branch to merge into. When you clone a repository, it generally automatically creates a master branch that tracks origin/master. However, you can set up other tracking branches if you wish – ones that track branches on other remotes, or don’t track the master branch. The simple case is the example you just saw, running git checkout -b [branch] [remotename]/[branch]. This is a common enough operation that git provides the --track shorthand:”

Tag

  • 查看 tag:git tag
  • 查找指定 tag,比如查找 V1.0.* :git tag -l 'V1.0.*' 会列出匹配到的,比如 V1.0.1,V1.0.1.1,V1.0.2 等
  • 创建轻量级 tag(lightweight tags):git tag tag-name ,例如: git tag v1.0
  • 创建 tag(annotated tags):git tag -a tag-name -m 'msg' ,例如:git tag -a v1.0.0 -m '1.0.0版本上线完毕打tag'
    • annotated tags VS lightweight tags 可以通过命令真实查看下:git show v1.0 / git show v1.0.0
    • “A lightweight tag is very much like a branch that doesn’t change – it’s just a pointer to a specific commit. Annotated tags, however, are stored as full objects in the Git database. They’re checksummed; contain the tagger name, e-mail, and date; have a tagging message; and can be signed and verified with GNU Privacy Guard (GPG). ”
  • 查看指定 tag 信息:git show tag-name
  • 基于历史某次提交(commit)创建 tag :git tag -a tagname <sha1-of-commit>
    • 例:基于上线时的提交 a207a38d634cc10441636bc4359cd8a18c502dea 创建tag:git tag -a v1.0.0 a207a38
  • 删除 tag :git tag -d tagname
  • 拉取远程 tag 到本地:git pull remotename --tags 例如:git pull origin --tags
  • 推送 tag 到远程服务器:git push remotename tagname 例如:git push origin v1.0.0
  • 将本地所有 tag 推送到远程:git push remotename --tags 例如:git push origin --tags
  • 删除远程 tag :git push origin :tagname 或者 git push origin --delete tagname 或者 git push origin :refs/tags/v0.9

Submodule

添加子模块:$ git submodule add [url] [path] 如:$ git submodule add git://github.com/soberh/ui-libs.git src/main/webapp/ui-libs 初始化子模块:$ git submodule init ----只在首次检出仓库时运行一次就行 更新子模块:$ git submodule update ----每次更新或切换分支后都需要运行一下 删除子模块:(分4步走哦)

  1. $ git rm --cached [path]
  2. 编辑“.gitmodules”文件,将子模块的相关配置节点删除掉
  3. 编辑“ .git/config”文件,将子模块的相关配置节点删除掉
  4. 手动删除子模块残留的目录

Stash

经常有这样的事情发生,当你正在进行项目中某一部分的工作,里面的东西处于一个比较杂乱的状态,而你想转到其他分支上进行一些工作。问题是,你不想提交进行了一半的工作,否则以后你无法回到这个工作点。解决这个问题的办法就是 git stash 命令。 stash 可以获取你工作目录的中间状态,也就是你修改过的被追踪的文件和暂存的变更,并将它保存到一个未完结变更的堆栈中,随时可以重新应用。

usage: git stash list [<options>] 查看当前 stash 的列表
   or: git stash show [<stash>] 查看某一个版本的详细内容
   or: git stash drop [-q|--quiet] [<stash>] 删除 stash 中内容
   or: git stash ( pop | apply ) [--index] [-q|--quiet] [<stash>] 将 stash 中的代码应用到工作区中
   or: git stash branch <branchname> [<stash>]
   or: git stash [save [--patch] [-k|--[no-]keep-index] [-q|--quiet]
		       [-u|--include-untracked] [-a|--all] [<message>]]
   or: git stash clear  清空 stash 中所有内容

oh-my-zsh 常用命令

alias g='git'
alias ga='git add'
alias gco='git checkout'
alias gcb='git checkout -b'
alias gcm='git checkout master'
alias gcd='git checkout develop'
alias gd='git diff'
alias gf='git fetch'
alias gfo='git fetch origin'
alias gl='git pull'
alias gp='git push'
posted @ 2019-04-16 09:50  igoodful  阅读(261)  评论(6编辑  收藏  举报