在使用 gitflow 做版本控制系统,发现gitflow的时候只能指定一个master/develop,如果要多分支使用要如何操作呢?那么来看看我是如何给gitflow加料的。
公司都是git作为版本控制,公司一些项目组在用gitflow,但是我们组没有强制,但是我上月出了一次事故,总结就是分支管理问题,所以开始强迫自己使用gitflow,以前的项目是一个master和一个develop,自己checkout一个分支,然后merge(不理解的可以看看a-successful-git-branching-model).
问题出现了:项目有几个主分支和开发分支,比如master_sina,master_qq. master_buzz ,而gitflow的时候只能指定一个master/develop, 这样你start一个feature/hotfix之前就要去.git/config里面修改 [gitflow “branch”]项的相关主分支和开发分支,so不方便,看了下源码,给gitflow加点料.
添加功能
当你打开了feature/hotfix分支,但是你不想要它了(当然你可以直接git branch -D xx),使用git flow hotfix/feature delete,自动帮你删除这个分支,以便你新建其他分支(git flow只容许你一次存在一个hotfix/feature分支).
你想使用gitflow删除其它存在分支嘛?不需要 git branch -D,你还可以git flow hotfix/feature delete XX.
比如我在init的时候指定了master为master_sina,而当我想创建master_qq的hotfix,我只需要在start的是否给它取名字是’qq_‘开头的即可,要是有其它的需要你可以直接在源码里面添加对应的内容.
例子 git-flow-hotfix 我主要标记我修改的部分,代码如下:
- init(){
- require_git_repo
- require_gitflow_initialized
- gitflow_load_settings
- VERSION_PREFIX=$(eval"echo`gitconfig--getgitflow.prefix.versiontag`")
- PREFIX=$(gitconfig--getgitflow.prefix.hotfix)
- }
- #增加help的选项说明
- usage(){
- echo"usage:gitflowhotfix[list][-v]"
- echo"gitflowhotfixstart[-F]<version>[<base>]"
- echo"gitflowhotfixfinish[-Fsumpk]<version>"
- echo"gitflowhotfixpublish<version>"
- echo"gitflowhotfixdelete[branch]"
- echo"gitflowhotfixtrack<version>"
- }
- cmd_default(){
- cmd_list"$@"
- }
- cmd_list(){
- DEFINE_booleanverbosefalse'verbose(more)output'v
- parse_args"$@"
- localhotfix_branches
- localcurrent_branch
- localshort_names
- hotfix_branches=$(echo"$(git_local_branches)"|grep"^$PREFIX")
- if[-z"$hotfix_branches"];then
- warn"Nohotfixbranchesexist."
- warn""
- warn"Youcanstartanewhotfixbranch:"
- warn""
- warn"gitflowhotfixstart<version>[<base>]"
- warn""
- exit0
- fi
- current_branch=$(gitbranch--no-color|grep'^*'|grep-v'nobranch'|sed's/^*//g')
- short_names=$(echo"$hotfix_branches"|sed"s^$PREFIXg")
- #determinecolumnwidthfirst
- localwidth=0
- localbranch
- forbranchin$short_names;do
- locallen=${#branch}
- width=$(max$width$len)
- done
- width=$(($width+3))
- localbranch
- forbranchin$short_names;do
- localfullname=$PREFIX$branch
- localbase=$(gitmerge-base"$fullname""$MASTER_BRANCH")
- localmaster_sha=$(gitrev-parse"$MASTER_BRANCH")
- localbranch_sha=$(gitrev-parse"$fullname")
- if["$fullname"="$current_branch"];then
- printf"*"
- else
- printf""
- fi
- ifflagverbose;then
- printf"%-${width}s""$branch"
- if["$branch_sha"="$master_sha"];then
- printf"(nocommitsyet)"
- else--phpfensi.com
- localtagname=$(gitname-rev--tags--no-undefined--name-only"$base")
- localnicename
- if["$tagname"!=""];then
- nicename=$tagname
- else
- nicename=$(gitrev-parse--short"$base")
- fi
- printf"(basedon$nicename)"
- fi
- else
- printf"%s""$branch"
- fi
- echo
- done
- }
- cmd_help(){
- usage
- exit0
- }
- parse_args(){
- #parseoptions
- FLAGS"$@"||exit$?
- evalset--"${FLAGS_ARGV}"
- #readargumentsintoglobalvariables
- VERSION=$1
- BRANCH=$PREFIX$VERSION
这里就是我多master/develop的技巧,我这里会判断要新建的分支的前缀,要是qq_开头就会基于master_qq和develop_qq创建分支,所以你可以根据你的需要在这里加一些方法.
- test`exprmatch"$@""qq_"`-ne0&&MASTER_BRANCH="$MASTER_BRANCH"_qq&&
- DEVELOP_BRANCH="$DEVELOP_BRANCH"_qq
- }
- require_version_arg(){
- if["$VERSION"=""];then
- warn"Missingargument<version>"
- usage
- exit1
- fi
- }
- require_base_is_on_master(){
- if!gitbranch--no-color--contains"$BASE"2>/dev/null
- |sed's/[*]//g'
- |grep-q"^$MASTER_BRANCH$";then
- die"fatal:Givenbase'$BASE'isnotavalidcommiton'$MASTER_BRANCH'."
- fi
- }
- require_no_existing_hotfix_branches(){
- localhotfix_branches=$(echo"$(git_local_branches)"|grep"^$PREFIX")
- localfirst_branch=$(echo${hotfix_branches}|head-n1)
- first_branch=${first_branch#$PREFIX}
- [-z"$hotfix_branches"]||
- die"Thereisanexistinghotfixbranch($first_branch).Finishthatonefirst."
- }
- #添加delete参数,函数需要cmd_开头
- cmd_delete(){
- if["$1"=""];then
- #当不指定参数自动去找存在的未关闭的gitflow分支
- localhotfix_branches=$(echo"$(git_local_branches)"|grep"^$PREFIX")
- test"$hotfix_branches"=""&&die"Therehasnotexistinghotfixbranchcandelete"&&exit1
- else
- #指定参数先判断参数是不是的数量格式
- test$#!=1&&die"Thereonlyneedoneparameterindicatesthebranchtobedeleted"&&exit1
- hotfix_branches="$1"
- fi
- #当要删除的分支就是当前分支,先checkout到develop分支
- test"$hotfix_branches"="$(git_current_branch)"&&echo'Firstcheckoutdevelpbranch';git_docheckout"$DEVELOP_BRANCH"
- gitbranch-D${hotfix_branches}>/dev/null2>&1&&echo'DeleteSuccessed'||die"Didnotfindbranch:[$hotfix_branches]"
- }
- cmd_start(){
- DEFINE_booleanfetchfalse"fetchfrom$ORIGINbeforeperformingfinish"F
- parse_args"$@"
- BASE=${2:-$MASTER_BRANCH}
- require_version_arg
- require_base_is_on_master
- require_no_existing_hotfix_branches
- #sanitychecks
- require_clean_working_tree
- require_branch_absent"$BRANCH"
- require_tag_absent"$VERSION_PREFIX$VERSION"
- ifflagfetch;then
- git_dofetch-q"$ORIGIN""$MASTER_BRANCH"
- fi
- ifhas"$ORIGIN/$MASTER_BRANCH"$(git_remote_branches);then
- require_branches_equal"$MASTER_BRANCH""$ORIGIN/$MASTER_BRANCH"
- fi
- #createbranch
- git_docheckout-b"$BRANCH""$BASE"
- echo
- echo"Summaryofactions:"
- echo"-Anewbranch'$BRANCH'wascreated,basedon'$BASE'"
- echo"-Youarenowonbranch'$BRANCH'"
- echo
- echo"Follow-upactions:"
- echo"-Bumptheversionnumbernow!"
- echo"-Startcommittingyourhotfixes"
- echo"-Whendone,run:"
- echo
- echo"gitflowhotfixfinish'$VERSION'"
- echo
- }
- cmd_publish(){
- parse_args"$@"
- require_version_arg
- #sanitychecks
- require_clean_working_tree
- require_branch"$BRANCH"
- git_dofetch-q"$ORIGIN"
- require_branch_absent"$ORIGIN/$BRANCH"
- #createremotebranch
- git_dopush"$ORIGIN""$BRANCH:refs/heads/$BRANCH"
- git_dofetch-q"$ORIGIN"
- #configureremotetracking
- gitconfig"branch.$BRANCH.remote""$ORIGIN"
- gitconfig"branch.$BRANCH.merge""refs/heads/$BRANCH"
- git_docheckout"$BRANCH"
- echo
- echo"Summaryofactions:"
- echo"-Anewremotebranch'$BRANCH'wascreated"
- echo"-Thelocalbranch'$BRANCH'wasconfiguredtotracktheremotebranch"
- echo"-Youarenowonbranch'$BRANCH'"
- echo
- }
- cmd_track(){
- parse_args"$@"
- require_version_arg
- #sanitychecks
- require_clean_working_tree
- require_branch_absent"$BRANCH"
- git_dofetch-q"$ORIGIN"
- require_branch"$ORIGIN/$BRANCH"
- #createtrackingbranch
- git_docheckout-b"$BRANCH""$ORIGIN/$BRANCH"
- echo
- echo"Summaryofactions:"
- echo"-Anewremotetrackingbranch'$BRANCH'wascreated"
- echo"-Youarenowonbranch'$BRANCH'"
- echo
- }
- cmd_finish(){
- DEFINE_booleanfetchfalse"fetchfrom$ORIGINbeforeperformingfinish"F
- DEFINE_booleansignfalse"signthereleasetagcryptographically"s
- DEFINE_stringsigningkey"""usethegivenGPG-keyforthedigitalsignature(implies-s)"u
- DEFINE_stringmessage"""usethegiventagmessage"m
- DEFINE_stringmessagefile"""usethecontentsofthegivenfileastagmessage"f
- DEFINE_booleanpushfalse"pushto$ORIGINafterperformingfinish"p
- DEFINE_booleankeepfalse"keepbranchafterperformingfinish"k
- DEFINE_booleannotagfalse"don'ttagthisrelease"n
- parse_args"$@"
- require_version_arg
- #handleflagsthatimplyotherflags
- if["$FLAGS_signingkey"!=""];then
- FLAGS_sign=$FLAGS_TRUE
- fi
- #sanitychecks
- require_branch"$BRANCH"
- require_clean_working_tree
- ifflagfetch;then
- git_dofetch-q"$ORIGIN""$MASTER_BRANCH"||
- die"Couldnotfetch$MASTER_BRANCHfrom$ORIGIN."
- git_dofetch-q"$ORIGIN""$DEVELOP_BRANCH"||
- die"Couldnotfetch$DEVELOP_BRANCHfrom$ORIGIN."
- fi
- ifhas"$ORIGIN/$MASTER_BRANCH"$(git_remote_branches);then
- require_branches_equal"$MASTER_BRANCH""$ORIGIN/$MASTER_BRANCH"
- fi
- ifhas"$ORIGIN/$DEVELOP_BRANCH"$(git_remote_branches);then
- require_branches_equal"$DEVELOP_BRANCH""$ORIGIN/$DEVELOP_BRANCH"
- fi
- #trytomergeintomaster
- #incaseapreviousattempttofinishthisreleasebranchhasfailed,
- #butthemergeintomasterwassuccessful,weskipitnow
- if!git_is_branch_merged_into"$BRANCH""$MASTER_BRANCH";then
- git_docheckout"$MASTER_BRANCH"||
- die"Couldnotcheckout$MASTER_BRANCH."
- git_domerge--no-ff"$BRANCH"||
- die"Thereweremergeconflicts."
- #TODO:Whatdowedonow?
- fi
- ifnoflagnotag;then
- #trytotagtherelease
- #incaseapreviousattempttofinishthisreleasebranchhasfailed,
- #butthetagwassetsuccessful,weskipitnow
- localtagname=$VERSION_PREFIX$VERSION
- if!git_tag_exists"$tagname";then
- localopts="-a"
- flagsign&&opts="$opts-s"
- ["$FLAGS_signingkey"!=""]&&opts="$opts-u'$FLAGS_signingkey'"
- ["$FLAGS_message"!=""]&&opts="$opts-m'$FLAGS_message'"
- ["$FLAGS_messagefile"!=""]&&opts="$opts-F'$FLAGS_messagefile'"
- evalgit_dotag$opts"$VERSION_PREFIX$VERSION""$BRANCH"||
- die"Taggingfailed.Pleaserunfinishagaintoretry."
- fi
- fi
- #trytomergeintodevelop
- #incaseapreviousattempttofinishthisreleasebranchhasfailed,
- #butthemergeintodevelopwassuccessful,weskipitnow
- if!git_is_branch_merged_into"$BRANCH""$DEVELOP_BRANCH";then
- git_docheckout"$DEVELOP_BRANCH"||
- die"Couldnotcheckout$DEVELOP_BRANCH."
- #TODO:Actually,accountingfor'gitdescribe'pays,soweshould
- #ideallygitmerge--no-ff$tagnamehere,instead!
- git_domerge--no-ff"$BRANCH"||
- die"Thereweremergeconflicts."
- #TODO:Whatdowedonow?
- fi
- #deletebranch
- ifnoflagkeep;then
- #这个问题很奇怪,在完成分支删除它也会存在当前分支是
- #要删除的分支删除报错的问题,所以先切换走
- test"$BRANCH"="$(git_current_branch)"&&git_docheckout"$DEVELOP_BRANCH"
- git_dobranch-d"$BRANCH"
- fi
- ifflagpush;then
- git_dopush"$ORIGIN""$DEVELOP_BRANCH"||
- die"Couldnotpushto$DEVELOP_BRANCHfrom$ORIGIN."
- git_dopush"$ORIGIN""$MASTER_BRANCH"||
- die"Couldnotpushto$MASTER_BRANCHfrom$ORIGIN."
- ifnoflagnotag;then
- git_dopush--tags"$ORIGIN"||
- die"Couldnotpushtagsto$ORIGIN."
- fi
- fi
- echo
- echo"Summaryofactions:"
- echo"-Latestobjectshavebeenfetchedfrom'$ORIGIN'"
- echo"-Hotfixbranchhasbeenmergedinto'$MASTER_BRANCH'"
- ifnoflagnotag;then
- echo"-Thehotfixwastagged'$VERSION_PREFIX$VERSION'"
- fi
- echo"-Hotfixbranchhasbeenback-mergedinto'$DEVELOP_BRANCH'"
- ifflagkeep;then
- echo"-Hotfixbranch'$BRANCH'isstillavailable"
- else
- echo"-Hotfixbranch'$BRANCH'hasbeendeleted"
- fi
- ifflagpush;then
- echo"-'$DEVELOP_BRANCH','$MASTER_BRANCH'andtagshavebeenpushedto'$ORIGIN'"
- fi
- echo
- }