Foreword
At the end of each iteration, they will not take the initiative to delete the branches they created. The warehouse branches have not been cleaned up for several years, resulting in almost 2k branches.
Ideas
1. Use scripts to implement batch deletions without manually executing git command batch operations.
2. Support filter conditions, such as: merged branches, last commit three months ago, branches containing release characters
Version 1
#!/bin/bash repository_name="$1" echo "You are about to delete the branch under ["$repository_name"], please find someone else to back it up first to avoid accidental deletion!!!"; echo " " # Filter conditions and add branches that do not need to be deleted to this array excluded_branches=("master" "develop") #Specify the characters that need to be included in the branch name to be filtered (if it is empty, the filtering will not be performed) excluded_filter="release/1." #Specify the characters that need to be included in the name of the branch to be deleted (if it is empty, the filtering will not be performed) # include_filter="" # Get the seconds of the current system time current_time=$(date + %s) # Calculate the timestamp three months ago three_months_ago=$((current_time - 3600 * 24 * 90)) # Calculate the timestamp two months ago two_months_ago=$((current_time - 3600 * 24 * 60)) # Calculate the timestamp one month ago one_months_ago=$((current_time - 3600 * 24 * 30)) # Get all merged remote branches and perform loop processing for branch in `git branch -r --merged origin/master | grep -v HEAD`; do #Extract branch name # simple_name=$(echo "$branch" | grep '/' | cut -d'/' -f 2); simple_name=$(echo "$branch" | sed 's#.*origin/##') #Exclude branches that do not need to be deleted excluded_flag="0"; for excluded_branch in "${excluded_branches[@]}"; do if [[ "$simple_name" == "$excluded_branch" ]]; then excluded_flag="1"; break fi done # Determine whether the deletion conditions are met 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 # Get the last commit time of the branch branch_timestamp=$(git show --format="%at" "$branch" | head -n1) # Select based on actual needs Three months ago $three_months_ago Two months $two_months_ago One month ago $one_months_ago Current $current_time if [[ $branch_timestamp -lt $three_months_ago ]]; then echo "Deleting branch: $simple_name" # Delete local branch # git branch -d "$simple_name" # Delete remote branch git push origin --delete "$simple_name" echo "Branch $simple_name deletion completed" echo "" fi fi done echo "clear end"
Problem 1: After deleting a branch, there will be inconsistencies between the local and remote ends, resulting in the deletion of non-existent branches (which cannot be solved through pull)
Reason: After deleting a branch, there will be inconsistencies between the local and remote ends, resulting in deletion of non-existent branches (cannot be solved through pull)
Solution: Add the update remote and local reference command
https://blog.csdn.net/BryantLmm/article/details/85130091
Git – git-remote Documentation
Version 2
Added update remote and local reference commands
#!/bin/bash repository_name="$1" echo "You are about to delete the branch under ["$repository_name"], please find someone else to back it up first to avoid accidental deletion!!!"; echo " " # Filter conditions and add branches that do not need to be deleted to this array excluded_branches=("master" "develop") #Specify the characters that need to be included in the branch name to be filtered (if it is empty, the filtering will not be performed) excluded_filter="release/1." #Specify the characters that need to be included in the name of the branch to be deleted (if it is empty, the filtering will not be performed) include_filter="" # Get the seconds of the current system time current_time=$(date + %s) # Calculate the timestamp three months ago three_months_ago=$((current_time - 3600 * 24 * 90)) # Calculate the timestamp two months ago two_months_ago=$((current_time - 3600 * 24 * 60)) # Calculate the timestamp one month ago one_months_ago=$((current_time - 3600 * 24 * 30)) echo "Update local and remote branch references" # Update the branch reference first to ensure that the branch information pulled by git branch -r is consistent with the remote warehouse (deleting branches will cause inconsistencies, resulting in unnecessary traversal) git remote update origin --prune echo "Update completed, start deleting target branches in batches" # Get all merged remote branches and perform loop processing # for branch in `git branch -r --merged origin/master | grep -v HEAD`; do # Get all remote branches and perform loop processing for branch in `git branch -r | grep -v HEAD`; do #Extract branch name # simple_name=$(echo "$branch" | grep '/' | cut -d'/' -f 2); simple_name=$(echo "$branch" | sed 's#.*origin/##') #Exclude branches that do not need to be deleted excluded_flag="0"; for excluded_branch in "${excluded_branches[@]}"; do if [[ "$simple_name" == "$excluded_branch" ]]; then excluded_flag="1"; break fi done # Determine whether the deletion conditions are met 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 # Get the last commit time of the branch branch_timestamp=$(git show --format="%at" "$branch" | head -n1) # Select based on actual needs Three months ago $three_months_ago Two months $two_months_ago One month ago $one_months_ago Current $current_time if [[ $branch_timestamp -lt $three_months_ago ]]; then echo "Deleting branch: $simple_name" # Delete local branch # git branch -d "$simple_name" # Delete remote branch git push origin --delete "$simple_name" echo "Branch $simple_name deletion completed" echo "" fi fi done echo "Clear End"
Final version
Plus ask interaction
- Install inquirer.js
inquirer Chinese documentation | inquirer js Chinese tutorial | parsing | npm Chinese documentation
node executes the script to pass parameters, and supports the passing of empty writing method
Use “” to wrap parameters and not just separate them with spaces.
Node passes in the script, and the shell supports dynamic variable assignment
Node uses esec to execute the script. It cannot output in real time. It will wait for the script to be executed and output the print content at once
How to execute shell commands in nodejs and echo the results in real time?
Child process | Node.js v21.1.0 Documentation
solution:
Replace exec with spawn
Dynamicly pass in pull branch rules
Problem: This way of writing will cause all branches to be printed to the console
solve:
The code is as follows:
const inquirer = require('inquirer'); const { spawn } = require('child_process'); const format = { three_months_ago: '90 days ago', two_months_ago: '60 days ago', one_months_ago: '30 days ago', current_time: 'current', branch_all: 'All branches', branch_merged: 'Mergeed', branch_no_merged: 'Not merged', } const label = { name: 'The current project is:', excluded_filter: 'Specify the characters that need to be included in the branch name to be filtered:', include_filter: 'Specify the characters that need to be included in the branch name to be deleted:', date_range: 'Filter date range:', branch_rule: 'Get remote branch range:', } const question = [{ type: 'input', message: 'The current project is:', name: 'name', default: 'ircloud-ydp-web' }, { type: 'input', message: 'Specify the characters that need to be included in the branch name to be filtered (if it is empty, the filtering will not be performed):', name: 'excluded_filter', default: 'release/1.' }, { type: 'input', message: 'Specify the characters that need to be included in the name of the branch to be deleted (if it is empty, the filtering will not be performed):', name: 'include_filter', default: '' }, { type: 'list', message: 'Filter date range:', name: 'date_range', choices: ['three_months_ago', 'two_months_ago', 'one_months_ago', 'current_time'], default: 'three_months_ago', }, { type: 'list', message: 'Get remote branch range (all, merged, unmerged):', 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}, are you sure? `, 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('After obtaining the parameters, start executing the deletion script'); let paramsArr = Object.values(answer); const childProcess = spawn('sh', [`scripts/delBranch.sh`, ...paramsArr]); childProcess.stdout.on('data', (data) => { console.log(`Script execution output: ${data}`); }); childProcess.stderr.on('data', (data) => { console.error(`Script error message: ${data}`) }) } else { console.log('terminate execution'); } }) } async function main() { await getParams(); await confirmAgain(); } main();
#!/bin/bash repository_name="$1" echo "You are about to delete the branch under ["$repository_name"], please find someone else to back it up first to avoid accidental deletion!!!"; echo " " # Filter conditions and add branches that do not need to be deleted to this array excluded_branches=("master" "develop") #Specify the characters that need to be included in the branch name to be filtered (if it is empty, the filtering will not be performed) # excluded_filter="release/1." excluded_filter=$(echo ${2}) #Specify the characters that need to be included in the name of the branch to be deleted (if it is empty, the filtering will not be performed) include_filter=$(echo ${3}) # Get the seconds of the current system time current_time=$(date + %s) # Calculate the timestamp three months ago three_months_ago=$((current_time - 3600 * 24 * 90)) # Calculate the timestamp two months ago two_months_ago=$((current_time - 3600 * 24 * 60)) # Calculate the timestamp one month ago one_months_ago=$((current_time - 3600 * 24 * 30)) time_range=$(eval echo '$'${4}) echo "Update local and remote branch references" # Update the branch reference first to ensure that the branch information pulled by git branch -r is consistent with the remote warehouse (deleting branches will cause inconsistencies, resulting in unnecessary traversal) git remote update origin --prune echo "Update completed, start deleting target branches in batches" branch_all=""; branch_merged="--merged origin/master"; branch_no_merged="--no-merged origin/master"; get_branch_rule=$(eval echo '$'${5}) # Get (all/merged/unmerged) remote branches and perform loop processing for branch in `git branch -r ${get_branch_rule} | grep -v HEAD` ; do #Extract branch name # simple_name=$(echo "$branch" | grep '/' | cut -d'/' -f 2); simple_name=$(echo "$branch" | sed 's#.*origin/##') #Exclude branches that do not need to be deleted excluded_flag="0"; for excluded_branch in "${excluded_branches[@]}"; do if [[ "$simple_name" == "$excluded_branch" ]]; then excluded_flag="1"; break fi done # Determine whether the deletion conditions are met 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 # Get the last commit time of the branch branch_timestamp=$(git show --format="%at" "$branch" | head -n1) # Select based on actual needs Three months ago $three_months_ago Two months $two_months_ago One month ago $one_months_ago Current $current_time if [[ $branch_timestamp -lt $time_range ]]; then echo "Deleting branch: $simple_name" # Delete local branch # git branch -d "$simple_name" # Delete remote branch git push origin --delete "$simple_name" echo "Branch $simple_name deletion completed" echo "" fi fi done echo "Clear End"
Add execution command to package.json
“delete-node”: “node scripts/inquirerDelBranch.js”
End
At that time, one click was the most time-saving method