def merge(self): """ 将生产分支最新代码merge到当前分支 步骤: 1. 拉取生产分支: git fetch origin master && git checkout master && git rebase origin/master 2. 拉取当前分支: git fetch origin currbranch && git checkout currbranch && git rebase origin/currbranch 3. 将master合并到当前分支: git checkout currbranch && git merge master :return: """ prod_branch = igit.product_branch() curr_branch = igit.current_branch() if curr_branch == prod_branch: return #进入生产分支 ihelper.execute('git checkout %s' % prod_branch) #拉取生产远程分支到本地 igit.pull() #切回开发分支 ihelper.execute('git checkout %s' % curr_branch) #拉取远程开发分支到本地 igit.pull() #合并本地master到本地开发分支并推送到远程 igit.merge(prod_branch, need_pull=False) igit.set_last_sync_master_date(curr_branch) ok('done!')
def tag(self): """ 在生产分支上打标签 :return: """ if not self.args: return ihelper.execute('git tag') #将要在该分支上打标签 tag_branch = igit.product_branch() # 当前工作空间是否干净 if igit.current_branch() != tag_branch and not igit.workspace_is_clean( ): raise exception.FlowException(u'工作区中尚有未保存的内容') tag_name = None comment = '' while self.args: c = self.args.pop(0) if c == '-a': tag_name = self.args.pop(0) elif c == '-m': while self.args: if self.args[0].startswith('-'): break comment += self.args.pop(0) + ' ' if not comment: raise exception.FlowException(u'请输入标签注释') if not tag_name: tag_name = igit.tag_name() if not tag_name: raise exception.FlowException(u'未设置tag name') if ihelper.confirm(u'将在分支 %s 上打tag:%s, ok?' % (tag_branch, tag_name)) != 'y': warn(u'取消操作') return c_branch = igit.current_branch() try: #切换分支 if c_branch != tag_branch: info(u'切换到分支 %s:' % tag_branch) ihelper.execute('git checkout %s' % tag_branch) #打tag print igit.tag(tag_name, comment) except exception.FlowException, e: error(u'操作失败:') raise e
def delete(self): """ 删除本地匹配模式的多个分支,并删除远程相应分支 :return: """ if not self.args: raise exception.FlowException(u'指令格式错误,请输入help查看使用说明') tag_pattern = None del_remote = True del_branches = [] while self.args: c = self.args.pop(0) if c == '--no-remote': del_remote = False else: tag_pattern = c if not tag_pattern: raise exception.FlowException(u'请指定需要删除的分支匹配模式') for branch in igit.local_branches(): if branch == igit.product_branch(): continue if re.match(tag_pattern, branch): del_branches.append(branch) if not del_branches: warn(u'没有符合条件的分支') return #打印出将要删除的分支列表 warn(u'将要删除以下分支%s:' % ('(以及其对应的远程分支)' if del_remote else '')) for del_branch in del_branches: ok(del_branch) print if (ihelper.confirm( u'确定删除吗%s?' % ('(同时删除远程分支,删除后不可恢复)' if del_remote else ''), 'n') != 'y'): return #删除分支 for del_branch in del_branches: try: igit.delete_branch(del_branch, del_remote) except exception.FlowException, e: warn(str(e))
def create(self, args): """ 创建特性/修复分支。一次只能创建一个,会推到远端,且切换到此分支 :return: """ if not args: raise exception.FlowException(u'指令格式错误,请输入h %s查看使用说明' % self.cmd) branch = None auto_create_from_remote = False push_to_remote = True while args: c = args.pop(0) if c == '-y': auto_create_from_remote = True elif c == '--np' or c == '--no-push': push_to_remote = False else: branch = c if not branch: raise exception.FlowException(u'请输入分支名称') # 分支简称不可与项目、迭代名称相同(防止一些指令出现歧义) simple_branch = igit.simple_branch(branch) if simple_branch == iglobal.SPRINT or simple_branch in ihelper.projects( ): raise exception.FlowException(u'分支简称不可与项目或迭代名同名') branch = igit.real_branch(branch, self.cmd) # 检查当前分支下工作区状态 if not igit.workspace_is_clean(): raise exception.FlowException( u'工作区中尚有未提交的内容,请先用git commit提交或用git stash保存到Git栈中') # 分支名称重复性检查 info(u'检查本地分支...') if branch in igit.local_branches(): raise exception.FlowException(u'该分支名称已经存在') # 本地没有但远程有 create_from_remote = False info(u'检查远程分支...') if branch in igit.remote_branches(): if not auto_create_from_remote and ihelper.confirm( u'远程仓库已存在%s,是否基于该远程分支创建本地分支?' % branch) != 'y': return else: create_from_remote = True say(('white', u'正在创建分支'), ('sky_blue', branch), ('white', '...')) if create_from_remote: # 基于远程分支创建本地分支,会自动追踪该远程分支 ihelper.execute('git checkout -b ' + branch + ' origin/' + branch) else: # 切换到生产分支 p_branch = igit.product_branch() ihelper.execute('git checkout ' + p_branch) igit.pull() # 基于本地生产分支创建新分支 ihelper.execute('git checkout -b ' + branch) # 推送到远程 if push_to_remote: ihelper.execute('git push -u origin ' + branch + ':' + branch) if igit.workspace_is_clean(): #处理master更新检验,防止创建分支后执行master更新检查操作 igit.set_last_sync_master_date(branch) ok(u'创建成功!已进入分支:' + branch) else: raise exception.FlowException(u'创建分支失败')
def publish_to_master(self, branches=None): """ 发布分支到生产环境 :param branches: 待发布分支列表:[(proj_name, branch)] """ curr_p_branch = None tag_list = [] if not branches: #接着上次的继续发布 branches = ihelper.read_runtime('publish_branches') tag_list = ihelper.read_runtime('publish_tags') or [] if not branches: info(u'没有需要发布的分支') return orig_branches = list(branches) try: curr_proj = None for index, item in enumerate(branches): curr_p_branch = item proj, branch = tuple(item) if iglobal.PROJECT != proj: info(u'进入项目%s' % proj) extra.Extra('cd', [proj]).execute() if not igit.workspace_is_clean(): raise exception.FlowException( u'项目%s工作空间有未提交的更改,请先提交(或丢弃)后执行 %s p --continue 继续' % (proj, self.cmd)) # 首次进入项目执行fetch获取本地和远程分支差异 if curr_proj != proj: info('fetch...') igit.fetch(useCache=False) # 切换到将要合并的分支(如果不存在本地分支则会自动创建) ihelper.execute('git checkout %s' % branch) # 同步当前本地和远程分支(此处可能会出现冲突) igit.sync_branch() # 切换到master分支 ihelper.execute('git checkout %s' % igit.product_branch()) is_last_branch = index >= len( branches) - 1 or proj != branches[index + 1][0] # 合并 info(u'合并%s...' % branch) igit.merge(branch, need_pull=proj != curr_proj, need_push=is_last_branch) info(u'合并完成:%s' % branch) # 完成 orig_branches.remove(curr_p_branch) if proj != curr_proj: curr_proj = proj # 本项目发布完成后的一些操作 if is_last_branch: self.__post_publish(proj, tag_list) ok(u'发布完成!tag:') # 打印tag信息 for (proj_name, tag_name) in tag_list: info(' %s %s' % (proj_name, tag_name)) # 清空tag list tag_list = [] except Exception, e: error(e.message) warn(u'处理完成后执行 %s p --continue 继续。或执行 %s p --abort 结束' % (self.cmd, self.cmd))