欢迎来到皮皮网网首页

【潮汐小说源码】【支付系统免费源码】【现成的app源码】flow 源码

来源:刷访问源码 时间:2024-11-24 22:31:39

1.Flowable 介绍
2.springboot+vue+elementui+flowable+自定义表单
3.git flow使用规范
4.flow 使用详解 + 小结
5.技术干货!源码DPDK新手入门到网络功能深入理解
6.多master/develop分支如何使用gitflow版本控制

flow 源码

Flowable 介绍

       Flowable 是源码一个基于 Java 的轻量级业务流程引擎,它支持BPMN 2.0流程定义的源码部署与执行,包括流程实例的源码管理和查询。核心引擎提供API以管理流程并执行相关操作,源码同时支持CMMN用于案例管理,源码潮汐小说源码DMN进行决策规则处理。源码它的源码灵活性使其能轻易融入各种Java环境,如Java SE、源码Servlet容器或Java EE服务器,源码还可通过REST API进行调用。源码Flowable框架也包含一系列UI应用,源码如Modeler用于流程设计,源码Admin进行引擎管理,源码IDM负责人员和组织,源码以及Task处理任务执行。

       Flowable源自Activiti5.x的重构,引入了CMMN、DMN和表单等功能。其特点是高效且实战验证,提供了流程设计插件,以及以Angular构建的可扩展用户界面。关于软件包,它包含了database脚本、文档、jar包、war文件等,如Admin、IDM、Modeler、支付系统免费源码REST和Task应用,分别用于引擎管理、人员管理、流程设计、API暴露和任务处理。源码包则包含了各种模块结构,如SpringBoot启动类、配置文件、服务层、控制层等,以及用于编译和快速入门的脚本和教程,如运行IDM来创建用户权限,使用Modeler创建流程模板,通过Task应用查询并完成任务。

springboot+vue+elementui+flowable+自定义表单

       æºç 

        springboot: /zjm/zjmzxfzhl

        springcloud: /zjm/zjmzxfzhl-cloud

        演示环境

       /img/git-model@...)

       2.3 Git Flow 分支 Git Flow 流程中包含一下几种分支。

       1) master分支 主分支,随项目一直存在的长期分支。master分支HEAD所在的位置,永远是当前生产环境的代码。master分支不允许直接提交代码,仅允许从release或者hotfix分支通过merge request合并代码。

       2) develop分支 开发分支,随项目一直存在的长期分支。develop分支的HEAD所在的位置,永远是下一个版本中已开发完成的新特性的最新代码。develop分支的代码每天自动构建并部署到测试环境。develop分支不允许直接提交代码,仅允许从feature, release或者hotfix分支通过merge request合并代码。当develop分支中下一个版本的现成的app源码新特性已经全部开发完毕后,从develop分支开出release分支,进入测试阶段。在下个版本的release分支创建之前,非下个版本的feature分支不允许向develop分支合并。

       3) feature分支 feature分支是一类以feature/为前缀(gitflow默认值, 可以更换)的分支的统称。每一个feature分支从develop分支新建,进行==某一个功能==的开发。功能开发并测试稳定后,feature分支将合并回develop分支。同一个人可以同时开发多个feature分支,同一个feature分支也可以同时被多个人开发。多个feature同时开发的情形,后开发完的分支在最后合并回develop时,往往会遇到冲突的情况。此时一般遵循以下两种方法解决冲突。

       4) release分支 release分支是一类以release/为前缀(gitflow默认值, 可以更换)的分支的统称。develop分支上的下一个版本的所有新特性开发完毕,从develop分支开出一个该版本的release分支,并进行测试。release分支不允许进行新特性开发,而只进行bug修复和更新版本mata信息(如版本号, 构建日期, 更新日志等),并且可以不定期将新的bug修复改动合并回develop。当release充分测试稳定后,同时合并进入master分支和develop分支,并在master分支上的建议该release版本的TAG。

       5) hotfix分支 当生产环境发现bug时,可以通过新建hotfix分支,来修复bug,修复后双向合并到develop和master。娃娃机分销源码

       3. Git Commit Message 规范 Git 每次提交都要写 commit message,否则就不允许提交。一般来说,commit message 应该清晰地说明本次提交的内容或目的。程序猿作为最具创造力的物种,他们甚至可以在commit的时候写诗。我是图 规范 git commit message,能够:

       个人觉得认真规范的写commit message是对自己这次辛苦工作的总结和回顾。如果你够骚包,也可以加点仪式感进去。当下最流行的git commit 规范莫过于 angular规范。Angular规范的模板如下。

       (): // 空一行 // 空一行

       其中,header 是必须的,body 和 footer 可以省略。

       3.1 Header Header 必须在同一行,包含3部分: type, scope, subject。其中type和subject必须写,scope可不写。

       3.2 Body Body 部分是对本次提交代码的详细描述,主要描述本次提交的动机和需要同步给团队的信息。

       3.3 Footer Footer 部分只用于两种情况。

       3.4 Revert 有一种特殊情况,如果当前 commit 用于撤销以前的 commit,则必须以revert:开头,后面跟着被撤销 Commit 的 Header. Body部分的格式是固定的,必须写成This reverts commit <hash>., 其中的hash是被撤销 commit 的 SHA 标识符。例如: revert: feat(pencil): add 'graphiteWidth' option This reverts commit eccaabdff。

       4. Code Review 摘抄自知乎问题的源码下载电影神马回答,有兴趣的可以去知乎看看原问题。

       4.1 Code Review有什么用 通过参与实战和团队成员讨论思考,我们认为CodeReview最终的作用将归到促进工程师日常代码交流和人员的成长上面来,与此同时作为辅助手段来对产品质量进行把关。

       4.2 Code Review适合什么团队 从代码质量提升的角度上看,以下类型的团队,笔者建议把CodeReview活动有效运作起来:

       4.3 如何有效的Code Review 1、代码规范:明确Coding规则2、检视指南:制定一个checklist, 消除困惑和迷茫3、总结优化:透明问题,持续优化(非常重要)4、激励机制:激发主观能动性

       4.4 哪种方式进行Code Review 最后组合一下,笔者个人推荐的CodeReview方式是强制+事前+小片段+线上交流+高频率,同时,如果能结合线下的大模块方式开展代码交流活动,效果会更好,这个经验来自手机管家高权限应用组的接地气实践。

       5. 开发规范 必须遵守的规范.

       推荐遵守的规范.

       6. 示例

flow 使用详解 + 小结

       flow 是一种用于静态检查 JavaScript 项目的工具,尤其适用于这种语言的弱类型和动态类型特性。在大型项目中,流类型注解能有效避免数据类型不匹配导致的问题。

       以重构 .NET 项目至 React 为例,源码与后端 API 传来的数据类型不匹配,导致使用时需不断转换数据类型,增加了开发难度。使用 flow 可以通过类型注解确保数据一致性,减少类型错误。

       安装和配置 flow 非常简单,通过 npm 或 yarn 建立项目并将其添加到 package.json。使用 babel 编译器移除 flow 语法,确保代码可正确运行。在项目中添加注释,flow 会检查类型是否符合预期。若类型不符,会报错提示。

       VSCode 集成了 flow 插件,可以直观地显示错误,通过设置关闭 JavaScript 校验功能以避免干扰。flow 的语法包括原始类型、数组类型、对象类型、函数类型及混合类型、any 类型和 maybe 类型等。

       原始类型如 boolean、string、number、null、undefined 和 symbol。数组类型使用 Array 或数组语法声明,只读数组使用 $ReadOnlyArray。对象类型使用 { } 格式,键值对数量未知时可使用数组声明。函数类型定义参数和返回值类型。

       混合类型使用 | 符号或 mixed 关键字表示变量可能为多种类型之一。any 关键字表示完全不进行类型检查,仅在特定情况下谨慎使用。maybe 类型允许接受 null 和 undefined 之外的其他类型。

       其他类型如 tuple、class 和 tuple 类型用于更细粒度的限制。flow 提供了强大且灵活的类型系统,以增强 JavaScript 项目的类型安全性和可维护性。

技术干货!DPDK新手入门到网络功能深入理解

       DPDK新手入门

       一、安装

       1. 下载源码

       DPDK源文件由几个目录组成。

       2. 编译

       二、配置

       1. 预留大页

       2. 加载 UIO 驱动

       三、运行 Demo

       DPDK在examples文件下预置了一系列示例代码,这里以Helloworld为例进行编译。

       编译完成后会在build目录下生成一个可执行文件,通过附加一些EAL参数可以运行起来。

       以下参数都是比较常用的

       四、核心组件

       DPDK整套架构是基于以下四个核心组件设计而成的

       1. 环形缓冲区管理(librte_ring)

       一个无锁的多生产者,多消费者的FIFO表处理接口,可用于不同核之间或是逻辑核上处理单元之间的通信。

       2. 内存池管理(librte_mempool)

       主要职责是在内存中分配用来存储对象的pool。 每个pool以名称来唯一标识,并且使用一个ring来存储空闲的对象节点。 它还提供了一些其他的服务,如针对每个处理器核心的缓存或者一个能通过添加padding来使对象均匀分散在所有内存通道的对齐辅助工具。

       3. 网络报文缓冲区管理(librte_mbuf)

       它提供了创建、释放报文缓存的能力,DPDK应用程序可能使用这些报文缓存来存储数据包。这个缓存通常在程序开始时通过DPDK的mempool库创建。这个库提供了创建和释放mbuf的API,能用来暂存数据包。

       4. 定时器管理(librte_timer)

       这个模块为DPDK的执行单元提供了异步执行函数的能力,也能够周期性的触发函数。它是通过环境抽象层EAL提供的能力来获取的精准时间。

       五、环境抽象层(EAL)

       EAL是用于为DPDK程序提供底层驱动能力抽象的,它使DPDK程序不需要关注下层具体的网卡或者操作系统,而只需要利用EAL提供的抽象接口即可,EAL会负责将其转换为对应的API。

       六、通用流rte_flow

       rte_flow提供了一种通用的方式来配置硬件以匹配特定的Ingress或Egress流量,根据用户的任何配置规则对其进行操作或查询相关计数器。

       这种通用的方式细化后就是一系列的流规则,每条流规则由多种匹配模式和动作列表组成。

       一个流规则可以具有几个不同的动作(如在将数据重定向到特定队列之前执行计数,封装,解封装等操作),而不是依靠几个规则来实现这些动作,应用程序操作具体的硬件实现细节来顺序执行。

       1. 属性rte_flow_attr

       a. 组group

       流规则可以通过为其分配一个公共的组号来分组,通过jump的流量将执行这一组的操作。较低的值具有较高的优先级。组0具有最高优先级,且只有组0的规则会被默认匹配到。

       b. 优先级priority

       可以将优先级分配给流规则。像Group一样,较低的值表示较高的优先级,0为最大值。

       组和优先级是任意的,取决于应用程序,它们不需要是连续的,也不需要从0开始,但是最大数量因设备而异,并且可能受到现有流规则的影响。

       c. 流量方向ingress or egress

       流量规则可以应用于入站和/或出站流量(Ingress/Egress)。

       2. 模式条目rte_flow_item

       模式条目类似于一套正则匹配规则,用来匹配目标数据包,其结构如代码所示。

       首先模式条目rte_flow_item_type可以分成两类:

       同时每个条目可以最多设置三个相同类型的结构:

       a. ANY可以匹配任何协议,还可以一个条目匹配多层协议。

       b. ETH

       c. IPv4

       d. TCP

       3. 操作rte_flow_action

       操作用于对已经匹配到的数据包进行处理,同时多个操作也可以进行组合以实现一个流水线处理。

       首先操作类别可以分成三类:

       a. MARK对流量进行标记,会设置PKT_RX_FDIR和PKT_RX_FDIR_ID两个FLAG,具体的值可以通过hash.fdir.hi获得。

       b. QUEUE将流量上送到某个队列中

       c. DROP将数据包丢弃

       d. COUNT对数据包进行计数,如果同一个flow里有多个count操作,则每个都需要指定一个独立的id,shared标记的计数器可以用于统一端口的不同的flow一同进行计数。

       e. RAW_DECAP用来对匹配到的数据包进行拆包,一般用于隧道流量的剥离。在action定义的时候需要传入一个data用来指定匹配规则和需要移除的内容。

       f. RSS对流量进行负载均衡的操作,他将根据提供的数据包进行哈希操作,并将其移动到对应的队列中。

       其中的level属性用来指定使用第几层协议进行哈希:

       g. 拆包Decap

       h. One\Two Port Hairpin

       七、常用API

       1. 程序初始化

       2. 端口初始化

       3. 队列初始化

       DPDK-网络协议栈-vpp-ovs-DDoS-虚拟化技术

       DPDK技术路线视频教程地址立即学习

       一、DPDK网络

       1. 网络协议栈项目

       2.dpdk组件项目

       3.dpdk经典项目

       二、DPDK框架

       1. 可扩展的矢量数据包处理框架vpp(c/c++)

       2.DPDK的虚拟交换机框架OvS

       3.golang的网络开发框架nff-go(golang)

       4. 轻量级的switch框架snabb(lua)

       5. 高效磁盘io读写spdk(c)

       三、DPDK源码

       1. 内核驱动

       2. 内存

       3. 协议

       4. 虚拟化

       5. cpu

       6. 安全

       四、性能测试

       1. 性能指标

       2. 测试方法

       3. 测试工具DPDK相关学习资料分享:点击领取,备注DPDK

       DPDK新手入门原文链接:DPDK上手

多master/develop分支如何使用gitflow版本控制

       在使用 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 `git config --get gitflow.prefix.versiontag`")

        PREFIX=$(git config --get gitflow.prefix.hotfix)

        }

        # 增加help的选项说明

        usage() {

        echo "usage: git flow hotfix [list] [-v]"

        echo " git flow hotfix start [-F] version [base]"

        echo " git flow hotfix finish [-Fsumpk] version"

        echo " git flow hotfix publish version"

        echo " git flow hotfix delete [branch]"

        echo " git flow hotfix track version"

        }

        cmd_default() {

        cmd_list "$@"

        }

       cmd_list() {

        DEFINE_boolean verbose false 'verbose (more) output' v

        parse_args "$@"

       local hotfix_branches

        local current_branch

        local short_names

        hotfix_branches=$(echo "$(git_local_branches)" | grep "^$PREFIX")

        if [ -z "$hotfix_branches" ]; then

        warn "No hotfix branches exist."

        warn ""

        warn "You can start a new hotfix branch:"

        warn ""

        warn " git flow hotfix start version [base]"

        warn ""

        exit 0

        fi

        current_branch=$(git branch --no-color | grep '^* ' | grep -v 'no branch' | sed 's/^* //g')

        short_names=$(echo "$hotfix_branches" | sed "s ^$PREFIX g")

       # determine column width first

        local width=0

        local branch

        for branch in $short_names; do

        local len=${ #branch}

        width=$(max $width $len)

        done

        width=$(($width+3))

       local branch

        for branch in $short_names; do

        local fullname=$PREFIX$branch

        local base=$(git merge-base "$fullname" "$MASTER_BRANCH")

        local master_sha=$(git rev-parse "$MASTER_BRANCH")

        local branch_sha=$(git rev-parse "$fullname")

        if [ "$fullname" = "$current_branch" ]; then

        printf "* "

        else

        printf " "

        fi

        if flag verbose; then

        printf "%-${ width}s" "$branch"

        if [ "$branch_sha" = "$master_sha" ]; then

        printf "(no commits yet)"

        else

        local tagname=$(git name-rev --tags --no-undefined --name-only "$base")

        local nicename

        if [ "$tagname" != "" ]; then

        nicename=$tagname

        else

        nicename=$(git rev-parse --short "$base")

        fi

        printf "(based on $nicename)"

        fi

        else

        printf "%s" "$branch"

        fi

        echo

        done

        }

       cmd_help() {

        usage

        exit 0

        }

       parse_args() {

        # parse options

        FLAGS "$@" || exit $?

        eval set -- "${ FLAGS_ARGV}"

        # read arguments into global variables

        VERSION=$1

        BRANCH=$PREFIX$VERSION

        # 这里就是我多master/develop的技巧,我这里会判断要新建的分支的前缀,

        # 要是qq_开头就会基于master_qq和develop_qq创建分支。所以你可以根据你的需要在这里加一些方法

        test `expr match "$@" "qq_"` -ne 0 MASTER_BRANCH="$MASTER_BRANCH"_qq

        DEVELOP_BRANCH="$DEVELOP_BRANCH"_qq

        }

       require_version_arg() {

        if [ "$VERSION" = "" ]; then

        warn "Missing argument version"

        usage

        exit 1

        fi

        }

       require_base_is_on_master() {

        if ! git branch --no-color --contains "$BASE" 2/dev/null

        | sed 's/[* ] //g'

        | grep -q "^$MASTER_BRANCH$"; then

        die "fatal: Given base '$BASE' is not a valid commit on '$MASTER_BRANCH'."

        fi

        }

       require_no_existing_hotfix_branches() {

        local hotfix_branches=$(echo "$(git_local_branches)" | grep "^$PREFIX")

        local first_branch=$(echo ${ hotfix_branches} | head -n1)

        first_branch=${ first_branch#$PREFIX}

        [ -z "$hotfix_branches" ] ||

        die "There is an existing hotfix branch ($first_branch). Finish that one first."

        }

        # 添加delete 参数,函数需要cmd_开头

        cmd_delete() {

        if [ "$1" = "" ]; then

        # 当不指定参数自动去找存在的未关闭的gitflow分支

        local hotfix_branches=$(echo "$(git_local_branches)" | grep "^$PREFIX")

        test "$hotfix_branches" = "" die "There has not existing hotfix branch can delete" exit 1

        else

        # 指定参数先判断参数是不是的数量格式

        test $# != 1 die "There only need one parameter indicates the branch to be deleted" exit 1

        hotfix_branches="$1"

        fi

        # 当要删除的分支就是当前分支,先checkout到develop分支

        test "$hotfix_branches" = "$(git_current_branch)" echo 'First checkout develp branch'; git_do checkout "$DEVELOP_BRANCH"

        git branch -D ${ hotfix_branches} /dev/null echo 'Delete Successed'|| die "Did not find branch: [$hotfix_branches]"

       }

        cmd_start() {

        DEFINE_boolean fetch false "fetch from $ORIGIN before performing finish" F

        parse_args "$@"

        BASE=${ 2:-$MASTER_BRANCH}

        require_version_arg

        require_base_is_on_master

        require_no_existing_hotfix_branches

       # sanity checks

        require_clean_working_tree

        require_branch_absent "$BRANCH"

        require_tag_absent "$VERSION_PREFIX$VERSION"

        if flag fetch; then

        git_do fetch -q "$ORIGIN" "$MASTER_BRANCH"

        fi

        if has "$ORIGIN/$MASTER_BRANCH" $(git_remote_branches); then

        require_branches_equal "$MASTER_BRANCH" "$ORIGIN/$MASTER_BRANCH"

        fi

       # create branch

        git_do checkout -b "$BRANCH" "$BASE"

       echo

        echo "Summary of actions:"

        echo "- A new branch '$BRANCH' was created, based on '$BASE'"

        echo "- You are now on branch '$BRANCH'"

        echo

        echo "Follow-up actions:"

        echo "- Bump the version number now!"

        echo "- Start committing your hot fixes"

        echo "- When done, run:"

        echo

        echo " git flow hotfix finish '$VERSION'"

        echo

        }

       cmd_publish() {

        parse_args "$@"

        require_version_arg

       # sanity checks

        require_clean_working_tree

        require_branch "$BRANCH"

        git_do fetch -q "$ORIGIN"

        require_branch_absent "$ORIGIN/$BRANCH"

       # create remote branch

        git_do push "$ORIGIN" "$BRANCH:refs/heads/$BRANCH"

        git_do fetch -q "$ORIGIN"

       # configure remote tracking

        git config "branch.$BRANCH.remote" "$ORIGIN"

        git config "branch.$BRANCH.merge" "refs/heads/$BRANCH"

        git_do checkout "$BRANCH"

       echo

        echo "Summary of actions:"

        echo "- A new remote branch '$BRANCH' was created"

        echo "- The local branch '$BRANCH' was configured to track the remote branch"

        echo "- You are now on branch '$BRANCH'"

        echo

        }

       cmd_track() {

        parse_args "$@"

        require_version_arg

       # sanity checks

        require_clean_working_tree

        require_branch_absent "$BRANCH"

        git_do fetch -q "$ORIGIN"

        require_branch "$ORIGIN/$BRANCH"

       # create tracking branch

        git_do checkout -b "$BRANCH" "$ORIGIN/$BRANCH"

       echo

        echo "Summary of actions:"

        echo "- A new remote tracking branch '$BRANCH' was created"

        echo "- You are now on branch '$BRANCH'"

        echo

        }

       cmd_finish() {

        DEFINE_boolean fetch false "fetch from $ORIGIN before performing finish" F

        DEFINE_boolean sign false "sign the release tag cryptographically" s

        DEFINE_string signingkey "" "use the given GPG-key for the digital signature (implies -s)" u

        DEFINE_string message "" "use the given tag message" m

        DEFINE_string messagefile "" "use the contents of the given file as tag message" f

        DEFINE_boolean push false "push to $ORIGIN after performing finish" p

        DEFINE_boolean keep false "keep branch after performing finish" k

        DEFINE_boolean notag false "don't tag this release" n

        parse_args "$@"

        require_version_arg

       # handle flags that imply other flags

        if [ "$FLAGS_signingkey" != "" ]; then

        FLAGS_sign=$FLAGS_TRUE

        fi

       # sanity checks

        require_branch "$BRANCH"

        require_clean_working_tree

        if flag fetch; then

        git_do fetch -q "$ORIGIN" "$MASTER_BRANCH" ||

        die "Could not fetch $MASTER_BRANCH from $ORIGIN."

        git_do fetch -q "$ORIGIN" "$DEVELOP_BRANCH" ||

        die "Could not fetch $DEVELOP_BRANCH from $ORIGIN."

        fi

        if has "$ORIGIN/$MASTER_BRANCH" $(git_remote_branches); then

        require_branches_equal "$MASTER_BRANCH" "$ORIGIN/$MASTER_BRANCH"

        fi

        if has "$ORIGIN/$DEVELOP_BRANCH" $(git_remote_branches); then

        require_branches_equal "$DEVELOP_BRANCH" "$ORIGIN/$DEVELOP_BRANCH"

        fi

       # try to merge into master

        # in case a previous attempt to finish this release branch has failed,

        # but the merge into master was successful, we skip it now

        if ! git_is_branch_merged_into "$BRANCH" "$MASTER_BRANCH"; then

        git_do checkout "$MASTER_BRANCH" ||

        die "Could not check out $MASTER_BRANCH."

        git_do merge --no-ff "$BRANCH" ||

        die "There were merge conflicts."

        # TODO: What do we do now?

        fi

       if noflag notag; then

        # try to tag the release

        # in case a previous attempt to finish this release branch has failed,

        # but the tag was set successful, we skip it now

        local tagname=$VERSION_PREFIX$VERSION

        if ! git_tag_exists "$tagname"; then

        local opts="-a"

        flag sign opts="$opts -s"

        [ "$FLAGS_signingkey" != "" ] opts="$opts -u '$FLAGS_signingkey'"

        [ "$FLAGS_message" != "" ] opts="$opts -m '$FLAGS_message'"

        [ "$FLAGS_messagefile" != "" ] opts="$opts -F '$FLAGS_messagefile'"

        eval git_do tag $opts "$VERSION_PREFIX$VERSION" "$BRANCH" ||

        die "Tagging failed. Please run finish again to retry."

        fi

        fi

       # try to merge into develop

        # in case a previous attempt to finish this release branch has failed,

        # but the merge into develop was successful, we skip it now

        if ! git_is_branch_merged_into "$BRANCH" "$DEVELOP_BRANCH"; then

        git_do checkout "$DEVELOP_BRANCH" ||

        die "Could not check out $DEVELOP_BRANCH."

       # TODO: Actually, accounting for 'git describe' pays, so we should

        # ideally git merge --no-ff $tagname here, instead!

        git_do merge --no-ff "$BRANCH" ||

        die "There were merge conflicts."

        # TODO: What do we do now?

        fi

       # delete branch

        if noflag keep; then

        # 这个问题很奇怪,在完成分支删除它也会存在当前分支是

        # 要删除的分支删除报错的问题,所以先切换走

        test "$BRANCH" = "$(git_current_branch)" git_do checkout "$DEVELOP_BRANCH"

        git_do branch -d "$BRANCH"

        fi

       if flag push; then

        git_do push "$ORIGIN" "$DEVELOP_BRANCH" ||

        die "Could not push to $DEVELOP_BRANCH from $ORIGIN."

        git_do push "$ORIGIN" "$MASTER_BRANCH" ||

        die "Could not push to $MASTER_BRANCH from $ORIGIN."

        if noflag notag; then

        git_do push --tags "$ORIGIN" ||

        die "Could not push tags to $ORIGIN."

        fi

        fi

       echo

        echo "Summary of actions:"

        echo "- Latest objects have been fetched from '$ORIGIN'"

        echo "- Hotfix branch has been merged into '$MASTER_BRANCH'"

        if noflag notag; then

        echo "- The hotfix was tagged '$VERSION_PREFIX$VERSION'"

        fi

        echo "- Hotfix branch has been back-merged into '$DEVELOP_BRANCH'"

        if flag keep; then

        echo "- Hotfix branch '$BRANCH' is still available"

        else

        echo "- Hotfix branch '$BRANCH' has been deleted"

        fi

        if flag push; then

        echo "- '$DEVELOP_BRANCH', '$MASTER_BRANCH' and tags have been pushed to '$ORIGIN'"

        fi

        echo

        }