说在前面
不知道大家平时工作的时候会不会需要经常新建git分支来开发新需求呢?在我这边工作的时候,需求都是以issue的形式来进行开发,每个issue新建一个关联的分支来进行开发,这样可以通过issue看到一个需求完整的开发记录,便于后续需求回顾和需求回退。而我平时本地分支都不怎么清理,这就导致了我这两年来本地分支的数量达到了惊人的361个,所以便开始写了这个可以批量删除分支的命令行工具。
功能设计
我们希望可以通过命令行命令的方式来进行交互,快速获取本地分支列表及各分支的最后提交时间和合并状态,在控制台选择我们想要删除的分支。
功能实现
1、命令行交互获取相关参数
这里我们使用@jyeontu/j-inquirer
模块来完成命令行交互功能,@jyeontu/j-inquirer
模块除了支持inquirer
模块的所有交互类型,还扩展了文件选择器、文件夹选择器及多级选择器交互类型,具体介绍可以查看文档:https://www.npmjs.com/package/@jyeontu/j-inquirer
(1)获取操作分支类型
我们的分支分为本地分支和远程分支,这里我们可以选择我们需要操作的分支类型,选择列表为:"本地分支"、"远程分支"、"本地+远程"
。
(2)获取远程仓库名(remote)
我们可以输入自己git的远程仓库名,默认为origin
。
(3)获取生产分支名
我们需要判断各分支是否已经合并到生产分支,所以需要输入自己项目的生产分支名,默认为develop
。
相关代码
const branchListOptions = [ { type: "list", message: "请选择要操作的分支来源:", name: "branchType", choices: ["本地分支", "远程分支", "本地+远程"], }, { type: "input", message: "请输入远程仓库名(默认为origin):", name: "gitRemote", default: "origin", }, { type: "input", message: "请输入生产分支名(默认为develop):", name: "devBranch", default: "develop", }, ]; const res = await doInquirer(branchListOptions);
2、命令行输出进度条
在分支过多的时候,获取分支信息的时间也会较长,所以我们需要在控制台中打印相关进度,避免用户以为控制台卡死了,如下图:
3、git操作
(1)获取git本地分支列表
想要获取当前仓库的所有的本地分支,我们可以使用git branch
命令来获取:
function getLocalBranchList() { const command = "git branch"; const currentBranch = getCurrentBranch(); let branch = child_process .execSync(command) .toString() .replace(trimReg, "") .replace(rowReg, "、"); branch = branch .split("、") .filter( (item) => item !== "" && !item.includes("->") && item !== currentBranch ); return branch; }
(2)获取远程仓库分支列表
想要获取当前仓库的所有的远程分支,我们可以使用git ls-remote --heads origin
命令来获取,git ls-remote --heads origin
命令将显示远程仓库 origin
中所有分支的引用信息。其中,每一行显示一个引用,包括提交哈希值和引用的全名(格式为 refs/heads/<branch_name>
)。
示例输出可能如下所示:
Copy Code <commit_hash> refs/heads/master <commit_hash> refs/heads/develop <commit_hash> refs/heads/feature/xyz
其中,<commit_hash>
是每个分支最新提交的哈希值。
function getRemoteList(gitRemote) { const command = `git ls-remote --heads ${gitRemote}`; let branchList = child_process .execSync(command) .toString() .replace(trimReg, "") .replace(rowReg, "、"); branchList = branchList .split("、") .filter((item) => item.includes("refs/heads/")) .map((branch) => { return gitRemote + "/" + branch.split("refs/heads/")[1]; }); return branchList; }
(3)获取各分支详细信息
我们想要在每个分支后面显示该分支最后提交时间和是否已经合并到生产分支,这两个信息可以作为我们判断该分支是否要删除的一个参考。
- 获取分支最后提交时间
git show -s --format=%ci <branchName>
命令用于查看 指定 分支最新提交的提交时间。其中,--format=%ci
用于指定输出格式为提交时间。
在 Git 中,git show
命令用于显示某次提交的详细信息,包括作者、提交时间、修改内容等。通过使用 -s
参数,我们只显示提交摘要信息,而不显示修改内容。
git show -s --format=%ci develop
命令将显示 develop
分支最新提交的提交时间。输出格式为 ISO 8601 标准的时间戳,例如 2023-10-22 16:41:47 +0800
。
function getBranchLastCommitTime(branchName) { try { const command = `git show -s --format=%ci ${branchName}`; const result = child_process.execSync(command).toString(); const date = result.split(" "); return date[0] + " " + date[1]; } catch (err) { return "未获取到时间"; } }
- 判断分支是否合并到生产分支
git branch --contains <branchName>
命令用于查找包含指定分支(<branchName>
)的所有分支。
在 Git 中,git branch
命令用于管理分支。通过使用 --contains
参数,我们可以查找包含指定提交或分支的所有分支。
git branch --contains <branchName>
命令将列出包含 <branchName>
的所有分支。输出结果将显示每个分支的名称以及指定分支是否为当前分支。
示例输出可能如下所示:
Copy Code develop * feature/xyz bugfix/123
其中,*
标记表示当前所在的分支,我们只需要判断输出的分支中是否存在生产分支即可:
function isMergedCheck(branch) { try { const command = `git branch --contains ${branch}`; const result = child_process .execSync(command) .toString() .replace(trimReg, "") .replace(rowReg, "、"); const mergedList = result.split("、"); return mergedList.includes(gitInfoObj.devBranch) ? `已合并到${gitInfoObj.devBranch}` : ""; } catch (err) { return "未获取到合并状态"; } }
(4)删除选中分支
选完分支后我们就该来删除分支了,删除分支的命令大家应该就比较熟悉了吧
- git branch -D <branchName>
git branch -D <branchName>
命令用于强制删除指定的分支(<branchName>
)。该命令会删除本地仓库中的指定分支,无法恢复已删除的分支。
- git push <remote> :<branchName>
git push <remote> :<branchName>
命令用于删除远程仓库<remote>
中的指定分支(<branchName>
)。这个命令通过推送一个空分支到远程仓库的 <branchName>
分支来实现删除操作。
async function doDeleteBranch(branchList) { const deleteBranchList = await getDeleteBranch(branchList); if (!deleteBranchList) return; console.log("正在删除分支"); progressBar.run(0); deleteBranchList.forEach((branch, index) => { let command = `git branch -D ${branch}`; if (branch.includes("/")) { const tmp = branch.split("/"); command = `git push ${tmp[0]} :${tmp[1]}`; } child_process.execSync(command); progressBar.run(Math.floor(((index + 1) / deleteBranchList.length) * 100)); }); console.log(""); console.log("已删除分支:" + deleteBranchList); }
可以看到我们的分支瞬间就清爽了很多。
使用
该工具已经发布到 npm 上,可以直接通过命令npm i -g jyeontu
进行安装,安装完后在控制台中输入jyeontu git
即可进行操作。
源码
该工具的源码也已经开源,有兴趣的同学可以到Gitee上查看:Gitee地址
说在后面
🎉 这里是 JYeontu,现在是一名前端工程师,有空会刷刷算法题,平时喜欢打羽毛球 🏸 ,平时也喜欢写些东西,既为自己记录 📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解 🙇,写错的地方望指出,定会认真改进 😊,偶尔也会在自己的公众号『前端也能这么有趣』发一些比较有趣的文章,有兴趣的也可以关注下。在此谢谢大家的支持,我们下文再见 🙌。