Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I delete all local branches which would result in no changes if merged into master?

I know how to delete all local branches that have been merged. However, and I believe this is due to Github's new pull request squash and merge feature, I find myself being left with a lot of local branches that are unmerged, but if merged into master would result in no changes.

How can I prune these local branches, i.e. those local branches which haven't necessarily been merged, but wouldn't affect master (or, more generically, the current branch)?

like image 749
Claudiu Avatar asked Apr 05 '16 14:04

Claudiu


People also ask

Can I delete local branch after merge?

When you're done with a branch and it has been merged into master, delete it. A new branch can be made off of the most recent commit on the master branch. Also, while it is ok to hang onto branches after you've merged them into the master they will begin to pile up.

How do I delete all local branches?

Explanation: Get all branches (except for the master) via git branch | grep -v "master" command. Select every branch with xargs command. Delete branch with xargs git branch -D.

How do I delete all local branches except master?

Newer Git repositories have renamed the master branch to main. To delete all branches in Git except main, simply replace the grep for master with a grep for main: git branch | grep -v "main" | xargs git branch -D.


1 Answers

There is no perfect solution but you can get close, perhaps close enough.

Be sure to start with a clean work tree and index (see require_clean_work_tree in git-sh-setup).

For each candidate branch $branch that might be delete-able:

  1. Find its merge target (presumably merge_target=$(git config --get branch.${branch}.merge)). Check out the merge target.
  2. Do a merge with --no-commit; or in step 1, check out with --detach so that you will get a commit you can abandon, if the merge succeeds.
  3. Test whether git thinks the merge succeeded, and if so, whether the current tree matches the previous tree, i.e., brought in no changes. If you can test exact matches, and if you allow the commit to happen (via --detach), you can do this last test very simply, without any diff-ing: run both git rev-parse HEAD^{tree} and git rev-parse HEAD^^{tree}1 and see if they produce the same hash. If you don't allow the commit, you can still git diff the current (HEAD) commit against the proposed merge. If you need to remove some noise from the diff (e.g., config files that should not be, but are anyway, in the commits), this gives you a place to do it.
  4. Reset (git merge --abort; git reset --hard HEAD; git clean -f or similar, depending on how you have decided to implement steps 1-3). This is just meant to make your work tree and index clean again, for the next pass.
  5. If the merge in step 3 worked and introduced no changes, you may delete the local branch. Otherwise, keep it.

In essence, this is "actually do the merge and see what happens", just fully automated.


1This notation looks a bit bizarre, but it's just HEAD^—the first parent of HEAD—followed by ^{tree}. Alternate spellings might be easier to read: HEAD~1^{tree} or ${merge_target}^tree, where ${merge_target} is the branch you checked out in step 1. Note that this assumes the merge succeeded. The merge result is in the exit status of git merge: zero means succeeded, nonzero means failed and needs manual assistance, presumably due to a merge conflict.

like image 134
torek Avatar answered Oct 19 '22 06:10

torek