Remove local Git branches merged with squash (2023)


The default merge method on GitHub pull requests creates a merge commit. But GitHub also provides us with severalmerge optionsand the Squash and Merge option is one of them. Since a squash merged commit is not the same as commits on a local branch,gitcannot list local branch merged with squash bygit branch - merged. Therefore, we cannot clean up stale local branches with the following commands.

$ git fetch --prune$ git branch --merged | egrep -v "(^\*|maestro|ANY_BRANCH_YOU_WANT_TO_EXCLUDE)" | xargs -I % rama git -d %

These commands can remove stale remote branches on GitHub and local branches if we use standard merge commits.

To clear local branch corresponding to PR merged with squash I usegeh cherry,git-merge-base, jgit-commit-tree. Since these are the commands that I rarely use in my software development process, I would like to introduce the usage of the commands.


  • Explaingeh cherry,git-merge-base, jgit-commit-tree
  • Please share shell script to clean up stale branches from my local git

Strategy to detect a merged branch with squash

Let's say we have a topic branchA, jAit is zipped and merged into a master on GitHub. For this situation, we can detect the local git squash merged branch with the following steps.

  1. Find a master commit forMaestroand subjectA.
  2. Create a zipped temporary commit from the main commit to the latest commits ofA.
  3. Check if zipped commit is already appliedMaestro.

strategy review

Based on the strategy described above, I will try and develop the steps on how we can detect the merged branch with squash in my local git.

Preparation before the experience

The repository that I will use during the experiment is prepared with the following commands. First, a Git initialization is performed and the first commit is added.

(Video) How to Close a Pull Request - Merge Commit vs Squash vs Rebase on GitHub

$ mkdir remote-squash-merge-branch$ cd remote-squash-merge-branch$ git init$ echo "1" >$ git add$ git commit -m "Initial commit"$ echo "parent commit to master and A" >>$ git commit -am "parent commit to master and A"$ git log --oneline546d16d (HEAD -> master) parent commit to master and A6669578 Initial commit

Second, a topic branch is calledAcreated and added two commits.

$ git checkout -b A$ echo "First commit in topic A" >>$ git commit -am "First commit in topic A"$ echo "Second commit in topic A" >>$ git commit - on "Second commit with topic branch A"

We can check the current state of Git trees withgit log --graph. We can confirm this from the following tree diagramAit's two commits before the master branch.

$ git log --graph --date-order --all --pretty=format:'%h %Cred%d %Cgreen%ad %Cblue%cn %Creset%s' --date=short* 709b12e (HEAD - > A) 2020-04-18 Takayuki WATANABE Second commit with topic branch A* 6a55918 2020-04-18 Takayuki WATANABE First commit with topic branch A* 546d16d (master) 2020-04-18 Takayuki WATANABE Main commit for teachers and A* 6669578 04/18/2020 Takayuki WATANABE First confirmation

Third, we have to pushAto a remote repository and create a pull request.

$ git remote add origin$ git push origin master

Finally, on GitHub, click squash and merge and review the commit and merge it into your local master branch.

(Video) 9. Git Tutorial - Branches in git (Create, Merge, Squash merge, etc) - complete video

$ git checkout master$ git fetch --all$ git merge origin/master

The graphic below illustrates the Git tree I want to use for the experiment. As you can see in the graph, the local master contains the squash combo commit. The ancestor owes himself to himMaestrojABranches is the commit hash546d16d.

$ git log --graph --date-order --all --pretty=format:'%h %Cred%d %Cgreen%ad %Cblue%cn %Creset%s' --date=short* 2b3d4ae (HEAD - > master, origin/master) 2020-04-18 GitHub A (#1)| * 709b12e (Source/A, A) 2020-04-18 Takayuki WATANABE Second commit with topic branch A| * 6a55918 2020-04-18 Takayuki WATANABE First commit with topic branch A|/* 546d16d 2020-04-18 Takayuki WATANABE Major commit for master and A* 6669578 2020-04-18 Takayuki WATANABE First commit

Step 1. Find a parent commit for master and topic A

Okay, let's start the experiment. As a first step, we need to find a master commit forMaestroand subjectA' whose commit hash is546d16d. There is a useful Git subcommand calledmerged base. Literally,merged base gitfind as many common ancestors as possible for a mergerMaestrojA.

$ git merge-base master A546d16de58d48d045a24649817ab9e0e256d4f7a$ ANCESTOR=`git merge-base master A`$ git show --oneline $ANCESTOR546d16d Confirmar principal para mestre e adiff --git a/ b/README.mdindex d00491f..817a9344 - -- a/ b/ -1 +1,2 @@ 1+compromiso principal para maestro y A

due togit merge-base maestro A, array variableANCESTORYou now have the commit hash for the main commit.

Step 2. Create a temporary compressed commit

The next step is to create a temporary commit that will contain all the commitsAbut it is squeezed into a commit. When we create the temporary commit, we don't want to change the commits and the treeA.Git-Commit-BaumNamecreates a new commit object using an ancestor commit object and a tree object.

$ TEMP_TREE=`git commit-tree $(git rev-parse A^{tree}) -p $ANCESTOR -m "temp tree object"`$ git log --oneline $TEMP_TREEbe75fbc temp tree object546d16d main commit to master e A6669578 inicial commit$ git show --oneline $TEMP_TREEbe75fbc árvore temporária objectdiff --git a/ b/README.mdindex 817a93f..e5f7cf8 100644--- a/ b/ -1,2 + 1.4 @@ 1 commit pai para master e A+Primeiro commit com branch de tópico A+Segundo commit com branch de tópico A
(Video) Squash your feature branch before a fast-forward merge! git rebase --interactive or git reset --soft

As I stated above,commit treeit does not change the state of existing commit and tree objects and creates a new commit object in their place. Therefore, if you search the tree for the master, you cannot find the graph's temporary commit.

$ git log --graph --date-order --all --pretty=format:'%h %Cred%d %Cgreen%ad %Cblue%cn %Creset%s' --date=short* 2b3d4ae (HEAD - > master, origin/master) 2020-04-18 GitHub A (#1)| * 709b12e (Source/A, A) 2020-04-18 Takayuki WATANABE Second commit with topic branch A| * 6a55918 2020-04-18 Takayuki WATANABE First commit with topic branch A|/* 546d16d 2020-04-18 Takayuki WATANABE Major commit for master and A* 6669578 2020-04-18 Takayuki WATANABE First commit

If you specify the temporary commit hash forGit registration, you can confirm the existence.

$ git log --graph --date-order --all --pretty=format:'%h %Cred%d %Cgreen%ad %Cblue%cn %Creset%s' --date=short $TEMP_TREE* 9f8364a ( HEAD -> master) 2020-04-18 Takayuki WATANABE One step ahead of confirmation, merged with Squash | *be75fbc 4/18/2020 Takayuki WATANABE temp tree object <- This is the commit temp object* | 2b3d4ae (Source/Master) 2020-04-18 GitHub A (#1)|/| * 709b12e (Source/A, A) 2020-04-18 Takayuki WATANABE Second commit with topic branch A| * 6a55918 2020-04-18 Takayuki WATANABE First commit with topic branch A|/* 546d16d 2020-04-18 Takayuki WATANABE Major commit for master and A* 6669578 2020-04-18 Takayuki WATANABE First commit

Step 3. Validate the pumpkin merged branch

Finally, we can compare the current master and the temp commit created in step 2. Since a squash creates a new commit and changes the commit hash, commit hashes don't work. But since the temporary commit includes all commits forAOn commit, merge validation is possible on GitHub by checking if the master branch contains a commit that has the sameContentas a temporary appointment.

geh cherryallows us to determine if the master has an equivalent commit. This command displays the SHA1 of each commit<head>..<upstream>. Therefore, if the temporary commit matches one of the master commits, the command generates a SHA1 with the prefix-.

$ git cherry master $TEMP_TREE-be75fbc3b3e3136e622b44936c391fc0f7252c33

Cool. Now we can verify that the master branch contains the merged commit on GitHub.

(Video) Learn Git Squash in 3 minutes // explained with live animations!

additional attempt

geh cherryOutput from SHA1 with-Prefix. We might instinctively expect this when comparing commitsgeh cherryare not equivalent, there is a different prefix-. Let's add another commit to master and rungeh cherry.

$ echo "One step ahead of commit merged with squash" >>$ git commit -am "One step ahead of commit merged with squash"$ git log --graph --date-order --all -- pretty= format:'%h %Cred%d %Cgreen%ad %Cblue%cn %Creset%s' --date=short $TEMP_TREE* 9f8364a (HEAD -> master) 2020-04-18 Takayuki WATANABE One step ahead squash merge commit | * be75fbc 2020-04-18 Takayuki WATANABE temp tree object * | 2b3d4ae (Source/Master) 2020-04-18 GitHub A (#1)|/| * 709b12e (Source/A, A) 2020-04-18 Takayuki WATANABE Second commit with topic branch A| * 6a55918 2020-04-18 Takayuki Watanabe First appointment to topic Branch A |/* 546d16d 2020-04-18 Takayuki Watanabe Main Committee for Master and A* 6669578 2020-04-18 Takayuki Watanab Initial Chery 9f8364a3e99911527d20ada97ce.face0a97ce.face0a97ce.

+is the prefix used to represent different commits.

Removal of obsolete local and remote branches

We can remove stale local branches with the combination of merged and merged branch deletes.git for each referencejgit rev-parseare useful for this type of automation. Here is an example shell script that removes stale local and remote branches at the same time.

#!/usr/bin/env zsh# gcl:git-cleanup-remote-and-local-branches## Remote and local branch cleanup is provided as follows:#1. Remove removed branches when deleted or merged#2. Delete local branches when your remote branches are deleted#3. Remove local branches if a master contains squash and merge commitsfunctiongit_prune_remote() { Eco "Start removing stale remote merged branches"git search --pruneEco "Complete deletion of stale remote merged branches"}functiongit_remove_merged_local_branch() { Eco "Start removing stale local merged branches"git branch - merged|egrep-v"(^\*|maestro|ANY_BRANCH_YOU_WANT_TO_EXCLUDE)" |xargs -I % rama git -d %Eco "Complete removal of stale local merged branches"}# Se usarmos `Squash and merge` no GitHub,# `git branch --merged` cannot detect merged branches.# As a result, git_remove_merged_local_branch() fails to clean up# unused local branches. This feature detects and removes local branches# when merging remote branches.## There is a borderline case. If you add suggested commits on GitHub,# Local and remote content are different. As a result,# This cleanup function cannot remove local branch merged with squash.functiongit_remove_squash_merged_local_branch() { Eco "Start removing obsolete local branches in combination with squash"git checkout -q mestre&&gitfor-each-references/headers/"--format=%(refname:short)" | while filerama; Again ancestor=p.smaestro git merge-base$rama) && [[ p.sgit cherry masterp.sGit-Commit-BaumNamep.sgit rev-parse$rama^{baum})- book page$ancestral-M_)) == "-"*]] &&rama git-D$rama done Eco "Stop removing stale local squash merged branches"}# Clean up remote and local branchesfunctiongl() {git_prune_remote git_remove_merged_local_branch git_remove_squash_merged_local_branch}gl

Tips for suggested commits on GitHub

With pull request reviews on GitHub, reviewers can do just thatSuggest code changes, and an author can integrate them. If we want to remove the local branches, we must also preserve the proposed changes to the local branch. Otherwise the above script will not be able to delete the local branch.


We can see a branch of pumpkin mixed withgit merge-base,Git-Commit-BaumName, jgeh cherry. So we can remove all deprecated local branches even if we use the squash and merge method on GitHub.


This article is inspired bynor tamanduá/git-delete-squashed

(Video) 6. Git Tutorial - merging commits into one - (git rebase and squashing)



How do I delete all merged branches locally? ›

Deleting Branches Merged into Main
  1. Open git bash and navigate to your git repository that you want to clean up.
  2. Fetch the latest from the git. Copy git fetch.
  3. See the list of local git branches. Copy git branch.
  4. Delete all local branches that have been merged to main branch. ...
  5. See the list of local git branches that remain.
Sep 19, 2021

Is it good practice to delete merged branches? ›

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 remove a merged branch in git? ›

You can use the Git reset command to undo a merge.

Can I delete local branch after merge? ›

Deleting a branch LOCALLY

Delete a branch with git branch -d <branch> . The -d option will delete the branch only if it has already been pushed and merged with the remote branch. Use -D instead if you want to force the branch to be deleted, even if it hasn't been pushed or merged yet. The branch is now deleted locally.

How do I clean up local git branches? ›

How to delete local Git branches
  1. Open a Git BASH window or Command Window in the root of your Git repository.
  2. If necessary, use the git switch or checkout command to move off the branch you wish to delete.
  3. Issue the git branch --delete <branchname> ...
  4. Run the git branch -a command to verify the local Git branch is deleted.
Oct 10, 2021

How can you see all local branches with merged? ›

With git branch --merged <commit> , your local list of branches will be filtered by all the branches who have been merged into a given branch or commit. Similar to above, you could type git branch --no-merged <commit> and only the branches not merged into the named commit would be listed.


1. How I use Git VSCode Github in a One-Man Team, No Git Commands to Memorize
2. Part 14: How to perform git squash (merge 2 or more commits into single commit)?
(Code of Duty)
3. Git tutorial 2: Git Branch Basics - Create, Merge & Delete Branches | with CHEATSHEET | by OsChannel
4. Use GIT squash to combine commits for cleaner GIT history
(John Duprat)
5. GIT Tutorial - How to Squash Commits
(Syal Study Zone)
6. Git: How to squash all commits, reset history on main branch ( 1 clean commit on master)
(Jason Cheung)


Top Articles
Latest Posts
Article information

Author: Nicola Considine CPA

Last Updated: 09/14/2023

Views: 5783

Rating: 4.9 / 5 (69 voted)

Reviews: 84% of readers found this page helpful

Author information

Name: Nicola Considine CPA

Birthday: 1993-02-26

Address: 3809 Clinton Inlet, East Aleisha, UT 46318-2392

Phone: +2681424145499

Job: Government Technician

Hobby: Calligraphy, Lego building, Worldbuilding, Shooting, Bird watching, Shopping, Cooking

Introduction: My name is Nicola Considine CPA, I am a determined, witty, powerful, brainy, open, smiling, proud person who loves writing and wants to share my knowledge and understanding with you.