git代码迭代版本 - 重建分支脚本

146 阅读4分钟

背景情况:

我们项目如两周一个更新版本,每个人可能同时在开发版本v1,同时也在开发后续需求v2,v3版本。

有两个基础条件:

  • 一是,我们所有业务分支v1,v2,v3都是从master拉取

  • 二是,我们业务分支可能会去合并公共分支common,比如一些基础设施的调整,或者是公共组件等分支,没期版本都有相应common分支

当,v1版本发布后,master分支已经更新,因为v2,v3分支是上期拉出来的,这次需要根据master分支rebase出修改的代码,所以就需要重建v2,v3分支

另外,我们v2,v3分支可能合并了相应的公共分支,比如common-v2,common-v3

那么比如v2上面的代码是master + common-v2 + 新加的业务代码这三部分组成;common-v2上面的代码是master + 公共v2的代码。现在master分支的已经更新到v1版本,那么此时就要重建这两个分支,那common-v2的代码也需要重建分支,然后再重建v2分支

现在我们重建common-v2分支的步骤:

1、确保master分支已经拉取最新,分支切换到common-v2,在命令行输入 git merge master --no-commit --no-off,获得common-v2和master的差异代码

2、存储上述差异代码

3、删除common-v2分支的本地分支和远程分支

4、从master拉分支命名为common-v2,此时common-v2和master分支一模一样

5、将第2步差异代码应用到common-v2

6、提交common-v2并push到服务器,重建common-v2完成

现在我们common-v2已经重建完成,接着重建v2分支:

1、确保master分支和common-v2分支已经拉取最新,将分支切换到v2分支,在命令行输入 git merge common-v2 --no-commit --no-off,获得v2和common-v2的差异代码

2、存储上述差异代码

3、删除v2分支的本地分支和远程分支

4、从master拉分支命名为v2,此时v2和master分支一模一样

5、合并common-v2分支到v2分支

6、将第2步差异代码应用到v2

7、提交v2并push到服务器,重建v2完成

可以看到,不论是重建common-v2还是重建v2过程基本相同,中间涉及很多git命令操作,可以通过shell脚本完成。

执行方式

git checkout v2 // 切换到v2分支
sh rebuild-branch.sh -c common-v2  // 执行重建脚本

重建分支脚本 rebuild-branch.sh

# !/bin/bash
help() {
    echo "Usage:"
    echo "rebuild-branch.sh [-c COMPARE_BRANCH -b BASE_BRANCH]"
    echo "e.g. rebuild-branch.sh -c feature/xxx -b main"
    echo "Description:"
    echo "COMPARE_BRANCH,比对分支(代码提纯的比对分支),默认是master"
    echo "BASE_BRANCH,基准分支(重建所需的基准分支),默认是master"
    echo "本脚本作用为将当前执行命令时的分支(需被重建的分支)与COMPARE_BRANCH进行比对,找出差异,并将差异应用到一条从BASE_BRANCH为基准创建的新分支(新分支名仍为需被重建的分支名,原来的需被重建的分支会被重命名并存在本地,用于安全自检。)"
    exit -1
}
# Defaults:
# 重建所需的基准分支
BASE_BRANCH=master
# 代码提纯的对比分支
COMPARE_BRANCH=master
# get opts
while getopts ":c:b:h" opt_name 
do
    case $opt_name in
        c)  COMPARE_BRANCH=$OPTARG
            ;;
        b)
            BASE_BRANCH=$OPTARG
            ;;
        h)
            help
            ;;
        ?) # 其它未指定名称参数
            echo "Unknown argument(s)."
            help
            exit 2
            ;;
    esac
done

# 确保在根目录
repo_dir=$(git rev-parse --show-toplevel)
# 捕获在项目根目录外执行脚本
if [ $? -ne 0 ];then
    exit
fi
cd $repo_dir

branch="$(git rev-parse --abbrev-ref HEAD)"

if [[ "$branch" == "$COMPARE_BRANCH" ]]; then
    echo "当前分支是$COMPARE_BRANCH(代码对比取差异的分支),请切换到你的工作分支"
    exit
elif [[ "$branch" == "$BASE_BRANCH" ]]; then
    echo "当前分支是$BASE_BRANCH(重建所基准的分支),请切换到你的工作分支"
    exit    
else
    echo "需要被重建的分支:$branch"
    echo "代码比对提纯分支:$COMPARE_BRANCH"
    echo "重建所需基准分支:$BASE_BRANCH"
    echo "【请确认上述信息,输入y/n/h】?y 继续  n 放弃   h 查看帮助文档"
    read makesure
    if [[ "$makesure" == "y" ]];then
        echo "重建分支开始 !"
    elif [[ "$makesure" == "h" ]];then
        help
    else 
        exit 
    fi    
fi

# 检出比对分支
git checkout $COMPARE_BRANCH 
# 捕获上一步错误
if [ $? -ne 0 ];then
    echo "git checkout ${COMPARE_BRANCH} error"
    exit
fi
# 拉取最新代码
git pull

# 将当前分支往比对分支上合并提取差异
result="$(git merge $branch --no-commit --no-ff)"

if [[ $result == *conflict* ]];then
    echo "失败!存在冲突,请自行打开vscode解决,解决完后,输入y继续执行,输入n放弃并退出!"
    git merge --continue
    echo "【请输入y/n】?y 我已解决完  n 放弃合并"
    read constep
    if [[ "$constep" == "y" ]];then
        echo "您选择了我已解决完继续执行"
        # 暂存差异
        git add .
        # 将差异储藏
        git stash
        # result=`git merge --continue`
    else 
        echo "您选择了放弃合并,自动退出"
        git merge --abort
        git checkout $branch
        exit
    fi
else
    # 将差异储藏
    git stash
fi

# git merge --abort
# 切换到需要被重建的分支
git checkout $branch
# 捕获上一步错误
if [ $? -ne 0 ];then
    echo "git checkout ${branch} error"
    exit
fi

echo "【请输入y/n】合并正常,是否继续?"
read ispopstash
if [[ "$ispopstash" == "y" ]];then
    newbranch="$branch-$(date "+%d-%H-%M-%S")"
    echo $newbranch
    # 备份旧分支
    git branch -m $branch $newbranch
    # 检出备份分支并去掉备份分支远程跟踪关系
    git checkout $newbranch
    git branch --unset-upstream
    # 检出基准分支
    git checkout $BASE_BRANCH
    git pull
    # 从基准分支新建一条原分支名的分支
    git checkout -b $branch
    echo "【请输入y/n】分支已备份,从$BASE_BRANCH新建的纯净分支(这次未应用存储),是否推送到服务器?"
    read puremaster
    if [[ "$puremaster" == "y" ]];then
        echo "推送纯净分支"
        git push -f --set-upstream origin $branch
    else
        echo "未推送纯净分支,后续可一起推"
    fi

    echo "【请输入y/n】是否合并比较分支并推送?"
    read comparebranch
    if [[ "$comparebranch" == "y" ]];then
        echo "合并比较分支并推送"
        # 合并比较分支
        git merge --commit --no-edit $COMPARE_BRANCH 
        git push -f --set-upstream origin $branch
    else
        echo "未推送比较分支,后续可一起推"
    fi

    # 应用最近一次的代码储藏,即之前提纯的代码
    result="$(git stash pop)"

    if [[ $result == *conflict* ]];then
        echo "应用提纯的代码失败!存在冲突,请自行打开vscode解决"
        echo "【请输入y/n】?y 我已解决完  n 放弃合并"
        read constep
            if [[ "$constep" == "y" ]];then
                echo "您选择了我已解决完继续执行"

                git add .

            else 
                echo "您选择了放弃合并,自动退出"
                git merge --abort
                git checkout $branch
                exit
            fi
    else
        # 无冲突
        git add .
    fi

    echo "【请输入y/n】已应用存储,是否提交并推送到服务器?"
    read ispush
    if [[ "$ispush" == "y" ]];then

        git commit -m "feature: 新建分支$branch"

        if [[ "$puremaster" == "y" ]];then
            git push -f
        else
            git push -f --set-upstream origin $branch
        fi

        echo "重建完成,本地原分支备份为$newbranch可移除"
    else
        echo "您选择了放弃推送,请手动推送后续操作"
        exit
    fi
else
    echo "您选择了放弃合并,自动退出"
    exit
fi