使用脚本批量删除远端分支

前言

        每月迭代结束,都不会主动去删除自己创建的分支,而仓库分支几年都没有清理,导致branchs差不多2k条。

 

思路

一、用脚本实现批量删除,无需手动执行git命令批量操作

二、支持筛选条件,如:已合并的分支、最后一次commit在三个月前、包含release字符的分支

版本一

#!/bin/bash

repository_name="$1"
echo "您即将删除【"$repository_name"】下的分支,请先找其他人备份好,以免误删!!!!";
echo " "

# 过滤条件,将无需删除的分支加入到这个数组中
excluded_branches=("master" "develop")

# 指定要过滤的分支名称中需包含的字符(为空则不进行该过滤)
excluded_filter="release/1."

# 指定要删除的分支名称中需包含的字符(为空则不进行该过滤)
# include_filter=""

# 获取当前系统时间的秒数
current_time=$(date +%s)

# 计算三个月前的时间戳
three_months_ago=$((current_time - 3600 * 24 * 90))

# 计算两个月前的时间戳
two_months_ago=$((current_time - 3600 * 24 * 60))

# 计算一个月前的时间戳
one_months_ago=$((current_time - 3600 * 24 * 30))


# 获取所有已合并的远程分支,并进行循环处理
for branch in `git branch -r --merged origin/master | grep -v HEAD`; do
    # 提取分支名称
    # simple_name=$(echo "$branch" | grep '/' | cut -d'/' -f 2);

    simple_name=$(echo "$branch" | sed 's#.*origin/##')

    # 排除不需要删除的分支
    excluded_flag="0";
    for excluded_branch in "${excluded_branches[@]}"; do
        if [[ "$simple_name" == "$excluded_branch" ]]; then
            excluded_flag="1";
            break
        fi
    done

    # 判断是否满足删除条件
    if [[ $excluded_flag == "0" ]]; then
        if [[ -n $excluded_filter ]]; then
            if [[ "$simple_name" == *"$excluded_filter"* ]]; then
                continue
            fi
        fi

        # if [[ -n $include_filter ]]; then
        #     if [[ "$simple_name" != *"$include_filter"* ]]; then
        #         continue
        #     fi
        # fi

        # 获取分支最后提交时间
        branch_timestamp=$(git show --format="%at" "$branch" | head -n1)

        # 根据实际需要选择 三个月前 $three_months_ago 两个月$two_months_ago  一个月前$one_months_ago  当前$current_time
        if [[ $branch_timestamp -lt $three_months_ago ]]; then
            echo "正在删除分支: $simple_name"

            # 删除本地分支
            # git branch -d "$simple_name"

            # 删除远程分支
            git push origin --delete "$simple_name"

            echo "分支 $simple_name 删除完成"
            echo ""
        fi
    fi
done
echo "清除结束"

问题一:删除分支过后,会出现本地与远端不一致的情况,导致去删除不存在的分支(通过pull无法解决)

原因:删除分支过后,会出现本地与远端不一致的情况,导致去删除不存在的分支(通过pull无法解决)

解决方法:增加更新远端与本地引用命令

htps://blog.csdn.net/BryantLmm/article/details/85130091

Git - git-remote Documentation

版本二

增加更新远端与本地引用命令

#!/bin/bash

repository_name="$1"
echo "您即将删除【"$repository_name"】下的分支,请先找其他人备份好,以免误删!!!!";
echo " "

# 过滤条件,将无需删除的分支加入到这个数组中
excluded_branches=("master" "develop")

# 指定要过滤的分支名称中需包含的字符(为空则不进行该过滤)
excluded_filter="release/1."

# 指定要删除的分支名称中需包含的字符(为空则不进行该过滤)
include_filter=""

# 获取当前系统时间的秒数
current_time=$(date +%s)

# 计算三个月前的时间戳
three_months_ago=$((current_time - 3600 * 24 * 90))

# 计算两个月前的时间戳
two_months_ago=$((current_time - 3600 * 24 * 60))

# 计算一个月前的时间戳
one_months_ago=$((current_time - 3600 * 24 * 30))

echo "更新本地与远端的分支引用"

# 先更新分支引用,确保git branch -r拉取的分支信息,与远端仓库一致(有删除过分支会出现不一致的情况,导致不必要的遍历)
git remote update origin  --prune

echo "更新完毕,开始批量删除目标分支"

# 获取所有已合并的远程分支,并进行循环处理
# for branch in `git branch -r --merged origin/master | grep -v HEAD`; do

# 获取所有的远程分支,并进行循环处理
for branch in `git branch -r | grep -v HEAD`; do
    # 提取分支名称
    # simple_name=$(echo "$branch" | grep '/' | cut -d'/' -f 2);

    simple_name=$(echo "$branch" | sed 's#.*origin/##')

    # 排除不需要删除的分支
    excluded_flag="0";
    for excluded_branch in "${excluded_branches[@]}"; do
        if [[ "$simple_name" == "$excluded_branch" ]]; then
            excluded_flag="1";
            break
        fi
    done

    # 判断是否满足删除条件
    if [[ $excluded_flag == "0" ]]; then
        if [[ -n $excluded_filter ]]; then
            if [[ "$simple_name" == *"$excluded_filter"* ]]; then
                continue
            fi
        fi

        if [[ -n $include_filter ]]; then
            if [[ "$simple_name" != *"$include_filter"* ]]; then
                continue
            fi
        fi

        # 获取分支最后提交时间
        branch_timestamp=$(git show --format="%at" "$branch" | head -n1)

        # 根据实际需要选择 三个月前 $three_months_ago 两个月$two_months_ago  一个月前$one_months_ago  当前$current_time
        if [[ $branch_timestamp -lt $three_months_ago ]]; then
            echo "正在删除分支: $simple_name"

            # 删除本地分支
            # git branch -d "$simple_name"

            # 删除远程分支
            git push origin --delete "$simple_name"

            echo "分支 $simple_name 删除完成"
            echo ""
        fi
    fi
done
echo "清除结束"

最终版

加上询问交互

  • 安装inquirer.js

inquirer中文文档|inquirer js中文教程|解析 | npm中文文档

node执行脚本传参,支持传空的写法

用""包裹参数,不能只用空格分隔

node传入脚本,shell支持动态变量赋值

node用esec执行脚本,不能实时输出,会等脚本执行完毕一次性输出打印内容

nodejs 如何执行 shell 命令,并把结果实时回显输出?

Child process | Node.js v21.1.0 Documentation

解决方案:

用spawn替换exec

动态传入拉取分支规则

问题:这种写法会导致打印输出所有分支到控制台

解决:

 代码如下:

const inquirer = require('inquirer');
const { spawn } = require('child_process');


const format = {
  three_months_ago: '90天前',
  two_months_ago: '60天前',
  one_months_ago: '30天前',
  current_time: '当前',
  branch_all: '所有分支',
  branch_merged: '已合并',
  branch_no_merged: '未合并',
}
const label = {
  name: '当前项目是:',
  excluded_filter: '指定要过滤的分支名称中需包含的字符:',
  include_filter: '指定要删除的分支名称中需包含的字符:',
  date_range: '过滤日期范围:',
  branch_rule: '获取远程分支范围:',
}

const question = [{
  type: 'input',
  message: '当前项目是:',
  name: 'name',
  default: 'ircloud-ydp-web'
},
{
  type: 'input',
  message: '指定要过滤的分支名称中需包含的字符(为空则不进行该过滤):',
  name: 'excluded_filter',
  default: 'release/1.'
},
{
  type: 'input',
  message: '指定要删除的分支名称中需包含的字符(为空则不进行该过滤):',
  name: 'include_filter',
  default: ''
},
{
  type: 'list',
  message: '过滤日期范围:',
  name: 'date_range',
  choices: ['three_months_ago', 'two_months_ago', 'one_months_ago', 'current_time'],
  default: 'three_months_ago',
},
{
  type: 'list',
  message: '获取远程分支范围(全部、已合并、未合并):',
  name: 'branch_rule',
  choices: ['branch_all', 'branch_merged', 'branch_no_merged'],
  default: 'branch_all',
}]


let answer = {}

function getParams () {
  return inquirer.prompt(question).then(res => {
    console.log(res)
    answer = {...res}
  })
}

function confirmAgain () {
  const str = Object.keys(answer).reduce((prev, curr) => {
    if(['date_range', 'branch_rule'].includes(curr)) {
      prev += `${label[curr]} ${format[answer[curr]]}; `;
    }else{
      prev += `${label[curr]} ${answer[curr]}; `;
    }
    return prev;
  }, '')
  return inquirer.prompt([{
    type: 'list',
    message: `${str},确定吗?`,
    name: 'answer',
    choices: ['yes', 'no'],
    default: 'yes'
  }]).then(res => {
    if (res.answer === 'yes') {
        // let params = Object.values(res).reduce((prev, curr) => {
      //   prev += `"${curr}" `;
      //   return prev
      // }, '')
      // console.log(`bash scripts/delBranch.sh ${params}`);
      // exec(`bash scripts/delBranch.sh ${params}`,(error, stdout, stderr) => {
        //   console.log(stdout);
        //   console.log(stderr);
        //   if (error !== null) {
          //       console.log(`exec error: ${error}`);
          //   }
          // })
      console.log('参数获取完毕,开始执行删除脚本');
      let paramsArr = Object.values(answer);
      const childProcess = spawn('sh', [`scripts/delBranch.sh`, ...paramsArr]);
      childProcess.stdout.on('data', (data) => {
        console.log(`脚本执行输出:${data}`);
      });
      childProcess.stderr.on('data', (data) => {
        console.error(`脚本错误信息:${data}`)
      })
    } else {
      console.log('终止执行');
    }
  })
}


async function main() {
  await getParams();
  await confirmAgain();
}

main();
#!/bin/bash

repository_name="$1"
echo "您即将删除【"$repository_name"】下的分支,请先找其他人备份好,以免误删!!!!";
echo " "

# 过滤条件,将无需删除的分支加入到这个数组中
excluded_branches=("master" "develop")

# 指定要过滤的分支名称中需包含的字符(为空则不进行该过滤)
# excluded_filter="release/1."
excluded_filter=$(echo ${2})

# 指定要删除的分支名称中需包含的字符(为空则不进行该过滤)
include_filter=$(echo ${3})

# 获取当前系统时间的秒数
current_time=$(date +%s)

# 计算三个月前的时间戳
three_months_ago=$((current_time - 3600 * 24 * 90))

# 计算两个月前的时间戳
two_months_ago=$((current_time - 3600 * 24 * 60))

# 计算一个月前的时间戳
one_months_ago=$((current_time - 3600 * 24 * 30))

time_range=$(eval echo '$'${4})

echo "更新本地与远端的分支引用"

# 先更新分支引用,确保git branch -r拉取的分支信息,与远端仓库一致(有删除过分支会出现不一致的情况,导致不必要的遍历)
git remote update origin  --prune

echo "更新完毕,开始批量删除目标分支"

branch_all="";
branch_merged="--merged origin/master";
branch_no_merged="--no-merged origin/master";

get_branch_rule=$(eval echo '$'${5})


# 获取(所有/已合并/未合并)的远程分支,并进行循环处理
for branch in `git branch -r ${get_branch_rule} | grep -v HEAD` ; do
    # 提取分支名称
    # simple_name=$(echo "$branch" | grep '/' | cut -d'/' -f 2);

    simple_name=$(echo "$branch" | sed 's#.*origin/##')

    # 排除不需要删除的分支
    excluded_flag="0";
    for excluded_branch in "${excluded_branches[@]}"; do
        if [[ "$simple_name" == "$excluded_branch" ]]; then
            excluded_flag="1";
            break
        fi
    done

    # 判断是否满足删除条件
    if [[ $excluded_flag == "0" ]]; then
        if [[ -n $excluded_filter ]]; then
            if [[ "$simple_name" == *"$excluded_filter"* ]]; then
                continue
            fi
        fi

        if [[ -n $include_filter ]]; then
            if [[ "$simple_name" != *"$include_filter"* ]]; then
                continue
            fi
        fi


        # 获取分支最后提交时间
        branch_timestamp=$(git show --format="%at" "$branch" | head -n1)

        # 根据实际需要选择 三个月前 $three_months_ago 两个月$two_months_ago  一个月前$one_months_ago  当前$current_time
        if [[ $branch_timestamp -lt $time_range ]]; then
            echo "正在删除分支: $simple_name"

            # 删除本地分支
            # git branch -d "$simple_name"

            # 删除远程分支
            git push origin --delete "$simple_name"

            echo "分支 $simple_name 删除完成"
            echo ""
        fi
    fi

  done

echo "清除结束"

package.json中加上执行命令

"delete-node": "node scripts/inquirerDelBranch.js"

结束

当时一键点击是最省时的

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值