1.多master/develop分支如何使用gitflow版本控制
2.flow 使用详解 + 小结
3.Flowable 介绍
4.springboot+vue+elementui+flowable+èªå®ä¹è¡¨å
5.git flow使用规范
6.Golang框架实战-KisFlow流式计算框架(8)-KisFlow Action
多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
}
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 项目的类型安全性和可维护性。
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分支中下一个版本的新特性已经全部开发完毕后,从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. 示例
Golang框架实战-KisFlow流式计算框架(8)-KisFlow Action
KisFlow是一个流式计算框架,旨在提供简单易用的API,帮助开发者快速构建和部署流式计算应用。本文将详细介绍KisFlow中的Action模块,特别是Abort、DataReuse和ForceEntryNext等关键Action的实现和使用方式。
### Abort Action
Abort Action允许开发者在执行Function时终止当前Flow的计算流程。Abort的实现依赖于一个名为AbortFuncHandler的业务回调方法。在该方法中,通过传递`flow.Next(kis.ActionAbort)`作为函数返回值,可以立即终止当前Flow的调度,从而避免执行后续的Function。
### Action模块定义
为了实现Abort功能,首先定义了`Abort`接口,并在`action.go`文件中实现了Abort行为。Abort行为通过设置Action的`Abort`成员变量为`true`来表示终止流程。此外,定义了`ActionFunc`函数类型,用于传递给KisFlow执行特定的Action动作。最后,实现了`LoadActions`方法,用于加载和组合多个Action动作。
### Next方法实现
`Next`方法是KisFlow的核心接口,用于在执行完一个Function后决定是否继续执行下一个Function。通过在`kis_flow.go`文件中添加Action成员和实现`Next`接口,开发者可以在自定义业务回调中调用`flow.Next(kis.ActionAbort)`来终止流程。
### Abort控制Flow流程
在`kis_flow.go`文件中,添加了一个成员变量`abort`来控制是否终止流程。在`Run`方法中,初始化并检查`abort`状态。在循环调度过程中,通过判断`abort`变量,可以选择性地跳过当前Function的执行,从而终止整个Flow的计算流程。同时,改进了流程以确保即使当前Function未提交数据(`flow.buffer`为空),也不会继续执行下一层Function。
### Action捕获及处理
创建了一个专门处理Action动作的方法`dealAction`,该方法在`kis_flow_action.go`文件中实现。通过集成`dealAction`到`Run`流程中,可以确保在执行完特定Action(如Abort)后,立即停止Flow的运行。
### Action Abort单元测试
为了验证Abort Action的正确性,设计了一个名为`abortFunc`的Function,并配置了相应的测试用例。通过`kis_action_test.go`文件中的测试代码,可以验证在执行Abort Action后,Flow确实会终止,而不会继续执行下一个Function。
### Action DataReuse
DataReuse Action允许当前Function的结果直接复用至上一层Function的结果,作为下一层Function的输入。实现该功能涉及修改Action接口、提供复用数据的方法,并在`dealAction`中捕获并处理DataReuse Action。
### Action ForceEntryNext
ForceEntryNext Action提供了一种机制,在当前Function未提交数据的情况下,强制执行下一层Function。实现该功能时需要注意,确保即使没有数据提交,也能正确地执行下一层Function。此外,包含了一个专门的测试用例,验证在不设置ForceEntryNext的情况下,Function的正常行为。
### Action JumpFunc
JumpFunc Action允许在Flow中跳转到指定的Function继续执行。实现时,需要谨慎考虑潜在的无限循环风险。通过在`kis_flow_action.go`文件中捕获JumpFunc Action,并根据JumpFunc的值调整下次执行的Function指针,实现了该功能。同样,包含了一个测试用例来验证JumpFunc的正确性。
### 源代码
KisFlow的源代码可访问以下链接:[KisFlow开源项目地址](github.com/aceld/kis-fl...)