Skip to content

Commit

Permalink
Delete merged and squashed from other branches. (#11)
Browse files Browse the repository at this point in the history
This defaults to master currently, my change proposes that the script should take an argument and allow squashed branches to be pruned no matter where they were merged.
  • Loading branch information
colonelpopcorn committed Oct 15, 2021
1 parent 913c21b commit 201ad37
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 6 deletions.
10 changes: 9 additions & 1 deletion README.md
Expand Up @@ -11,16 +11,24 @@ This is useful if you work on a project that squashes branches into master. Afte
To run as a shellscript, simply copy the following command (setting up an alias is recommended). There's no need to clone the repo.

```bash
git checkout -q master && git for-each-ref refs/heads/ "--format=%(refname:short)" | while read branch; do mergeBase=$(git merge-base master $branch) && [[ $(git cherry master $(git commit-tree $(git rev-parse $branch\^{tree}) -p $mergeBase -m _)) == "-"* ]] && git branch -D $branch; done
# Change $TARGET_BRANCH to your targeted branch, e.g. change from `master` to `main` to delete branches squashed into `main`.
TARGET_BRANCH=master && git checkout -q $TARGET_BRANCH && git for-each-ref refs/heads/ "--format=%(refname:short)" | while read branch; do mergeBase=$(git merge-base $TARGET_BRANCH $branch) && [[ $(git cherry $TARGET_BRANCH $(git commit-tree $(git rev-parse $branch\^{tree}) -p $mergeBase -m _)) == "-"* ]] && git branch -D $branch; done
# OR you can put this function in a global git alias and call it like this
# `git delete-squashed` OR `git delete-squashed main`
git config --global alias.delete-squashed '!f() { local targetBranch=${1:-master} && git checkout -q $targetBranch && git branch --merged | grep -v "\*" | xargs -n 1 git branch -d && git for-each-ref refs/heads/ "--format=%(refname:short)" | while read branch; do mergeBase=$(git merge-base $targetBranch $branch) && [[ $(git cherry $targetBranch $(git commit-tree $(git rev-parse $branch^{tree}) -p $mergeBase -m _)) == "-"* ]] && git branch -D $branch; done; }; f'
```

### Node.js

You can also install the tool as a Node.js package from NPM. (The package code is in this repo.)

Additionally, you can specify an alternate branch to check for squashed merges, as well. This is useful for different names of trunk branches like `main` or `develop`.

```bash
$ npm install --global git-delete-squashed
$ git-delete-squashed
$ # Specify a different branch name like so
$ git-delete-squashed main
```

## Details
Expand Down
12 changes: 7 additions & 5 deletions bin/git-delete-squashed.js
Expand Up @@ -5,6 +5,8 @@
const childProcess = require('child_process');
const Promise = require('bluebird');
const DEFAULT_BRANCH_NAME = 'master';
const RUN_WITH_NODE = process.argv[0].includes('node');
const selectedBranchName = process.argv[RUN_WITH_NODE ? 2 : 1] || DEFAULT_BRANCH_NAME;

/**
* Calls `git` with the given arguments from the CWD
Expand All @@ -28,20 +30,20 @@ function git (args) {
git(['for-each-ref', 'refs/heads/', '--format=%(refname:short)'])
.then(branchListOutput => branchListOutput.split('\n'))
.tap(branchNames => {
if (branchNames.indexOf(DEFAULT_BRANCH_NAME) === -1) {
throw `fatal: no branch named '${DEFAULT_BRANCH_NAME}' found in this repo`;
if (branchNames.indexOf(selectedBranchName) === -1) {
throw `fatal: no branch named '${selectedBranchName}' found in this repo`;
}
}).filter(branchName =>
// Get the common ancestor with the branch and master
Promise.join(
git(['merge-base', DEFAULT_BRANCH_NAME, branchName]),
git(['merge-base', selectedBranchName, branchName]),
git(['rev-parse', `${branchName}^{tree}`]),
(ancestorHash, treeId) => git(['commit-tree', treeId, '-p', ancestorHash, '-m', `Temp commit for ${branchName}`])
)
.then(danglingCommitId => git(['cherry', DEFAULT_BRANCH_NAME, danglingCommitId]))
.then(danglingCommitId => git(['cherry', selectedBranchName, danglingCommitId]))
.then(output => output.startsWith('-'))
)
.tap(branchNamesToDelete => branchNamesToDelete.length && git(['checkout', DEFAULT_BRANCH_NAME]))
.tap(branchNamesToDelete => branchNamesToDelete.length && git(['checkout', selectedBranchName]))
.mapSeries(branchName => git(['branch', '-D', branchName]))
.mapSeries(stdout => console.log(stdout))
.catch(err => console.error(err.cause || err));

0 comments on commit 201ad37

Please sign in to comment.