Skip to content

Removing a worktree

Time to read:Activity duration:
12 minutes20 minutes

Overview

bash
git worktree remove {FOLDER}

The remove subcommand for git worktree will delete a worktree:

  • {FOLDER} is the worktree folder that will be deleted.

Activity goal

This activity will show you how to use this command to remove a worktree that is no longer needed.

For thit activity; you will have four branches and one worktree for each.

Before we go and delete some worktrees, let see how Git will interact with each modification:

  • what is a commit becoming after worktree is deleted?
  • is a branch preserved after the worktree is deletes?
  • what's the deal with stash stack?
  • what happens to local change that are not saved in a commit?

Setup activity

Call the helper script to create the wt_remove activity:

bash
./scripts/create-playground.sh wt_remove
console
[INFO] Starting activity builder for 'wt_remove'
[INFO] Created activity folder: /Users/sylvain/dev/lab/git-tutorials/playgrounds/wt_remove
Cloning into 'nanorpm_main'...
remote: Enumerating objects: 252, done.
remote: Total 252 (delta 0), reused 0 (delta 0), pack-reused 252 (from 1)
Receiving objects: 100% (252/252), 497.60 KiB | 3.36 MiB/s, done.
Resolving deltas: 100% (147/147), done.
[Step] Cloned repository https://gitlab.com/sgamel-projects/nanorpn.git
Already on 'main'
Your branch is up to date with 'origin/main'.
Preparing worktree (checking out 'feature-a')
HEAD is now at 4188ec5 Test: add comprehensive integration tests for application workflow
Preparing worktree (checking out 'feature-b')
HEAD is now at 4188ec5 Test: add comprehensive integration tests for application workflow
Preparing worktree (checking out 'feature-c')
HEAD is now at 4188ec5 Test: add comprehensive integration tests for application workflow
[INFO] Successfully built activity 'wt_remove' in /Users/sylvain/dev/lab/git-tutorials/playgrounds/wt_remove
[INFO] You can now navigate to /Users/sylvain/dev/lab/git-tutorials/playgrounds/wt_remove to work on the activity.

cd /Users/sylvain/dev/lab/git-tutorials/playgrounds/wt_remove

The folder nanorpm_main now contain a clone of the repository and four branches, and their corresponding worktrees are created.

Worktree pathGit branch
nanorpm_mainmain
nanorpm_feature-afeature-a
nanorpm_feature-bfeature-b
nanorpm_feature-cfeature-c
How to check?

Check the list of branches in your clone:

bash
cd playgrounds/wt_remove/nanorpm_main
git worktree list

Displayed result should be similar to the following:

console
/Users/sylvain/dev/lab/git-tutorials/playgrounds/wt_remove/nanorpm_main       4188ec5 [main]
/Users/sylvain/dev/lab/git-tutorials/playgrounds/wt_remove/nanorpm_feature-a  4188ec5 [feature-a]
/Users/sylvain/dev/lab/git-tutorials/playgrounds/wt_remove/nanorpm_feature-b  4188ec5 [feature-b]
/Users/sylvain/dev/lab/git-tutorials/playgrounds/wt_remove/nanorpm_feature-c  4188ec5 [feature-c]

Remove with pending changes

I'm pretty sure you can easily guess what kind of outcome we'll get on this use case.

First go the worktree of our feature-a branch and create a small change in the repository:

bash
pushd ../nanorpm_feature-a

Let's perform a small change in package.json:

  • open the file in any editor;
  • replace "version": "1.0.0", with "version": "1.2.0",;
  • save the change and close editor
diff
diff --git a/package.json b/package.json
index 5315707..e8934fc 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "nanoRPN",
-  "version": "1.0.0",
+  "version": "1.2.0",
   "description": "A terminal-based RPN calculator",
   "main": "dist/main.js",
   "type": "module",
bash
git diff

Now, go back to the worktree of the main folder:

bash
popd

And delete the worktree for the feature-a branch:

bash
git worktree remove ../nanorpm_feature-a

Command should not proceed and return with an error message:

console
fatal: '../nanorpm_feature-a' contains modified or untracked files, use --force to delete it

Git is kind enough to detect that some file were updated and change was not saved in a commit. Preventing you to shoot yourself in the foot, it just doesn't let you remove the worktree, unless you insist stringly by using the --force command line option.

Remove after commit

So if you cannot delete a worktree when changes are not in a commit, let's go back and commit the change.

bash
pushd ../nanorpm_feature-a
git add package.json
git commit -m 'version increased'

This time we saved the change to a new commit. We can go back to the worktree of the main branch:

bash
popd

We should now be able to delete the worktree for the feature-a branch:

bash
git worktree remove ../nanorpm_feature-a

This time command issue no error, and you can check that folder was deleted:

bash
git worktree list

And now the output should contain one less worktree:

console
/Users/sylvain/dev/lab/git-tutorials/playgrounds/wt_remove/nanorpm_main       4188ec5 [main]
/Users/sylvain/dev/lab/git-tutorials/playgrounds/wt_remove/nanorpm_feature-b  4188ec5 [feature-b]
/Users/sylvain/dev/lab/git-tutorials/playgrounds/wt_remove/nanorpm_feature-c  4188ec5 [feature-c]

And you can check the content of the parent folder to verify that folder was really removed.

bash
ls ..
console
nanorpm_feature-b       nanorpm_feature-c       nanorpm_main

But more important: is you change still availabe somewhere?

You can check that branch feature-a still exists and switch to it to verify commit history:

bash
git switch feature-a
git log --oneline -5
621d829 (HEAD -> feature-a) version increased
4188ec5 (origin/main, origin/HEAD, main, feature-c, feature-b) Test: add comprehensive integration tests for application workflow
2258bf2 Test: add CLI method tests (showHelp, isHelpCommand, getInput)
b5d6287 Test: add comprehensive CLI method tests (showHelp, isHelpCommand, getInput, close)
2d88c36 doc: added name in pakage

We saw:

  • that Git will prevent us to delete a worktree with pending changes, either in tracked or untracked file.
  • that when a worktree is removed, the local branch is preserved.

We've seen how commits and pending changes are handled. But what about stash stack?

Remove with stashed changes

Now, let's check how stashed changes are handled in worktrees.

First switch to the feature-b branch and start to do some changes:

bash
cd ../nanorpm_feature-b

You can edit again package.json file:

  • open the file in any editor;
  • change version number from 1.0.0 to 1.2.0;
  • save the change and close editor.

Running git status now must show that package.json is modified.

We can stash this change, then verify it was properly added to the stack of stashes:

bash
git stash push -m 'version bump'
git stash list
console
stash@{0}: On feature-b: version bump

Go back to main branch and check again git stash list. The very same stash stack must be shown in the console.

bash
cd ../nanorpm_main
git stash list

Now, drop the worktree where this stash was pushed.

bash
git worktree remove ../nanorpm_feature-b
git worktree list

Output must now show only two worktrees:

  • nanorpm_main for main branch;
  • nanorpm_feature-c for feature-c branch.

Run again git stash list and you will see that saved changes is still preserved in the stash stack.

Why?

Worktrees are only views on a given local clone. They share the same local repository, explaining why commits or stashes can be retrieved without issues between worktrees.

Remove prunable worktree

Let's come back to the scenario we mentionned quickly in previous section.

We still have one worktree that is untouched. Just remove this folder:

bash
rm -rf ../nanorpm_feature-c/

When you list the worktrees, it should now be flagged as prunable:

console
/Users/sylvain/dev/lab/git-tutorials/playgrounds/wt_remove/nanorpm_main       4188ec5 [main]
/Users/sylvain/dev/lab/git-tutorials/playgrounds/wt_remove/nanorpm_feature-c  4188ec5 [feature-c] prunable
bash
git worktree list

There's two options to cleanup the list of worktrees in your repository:

  1. Either you manually remove the worktree using git worktree remove.
  2. Or you use a semi-automatic command that allow to remove all prunable worktrees in a single command.

For this example you will use the second options:

bash
git worktree prune

And now, the list of worktrees should only display the main clone:

console
/Users/sylvain/dev/lab/git-tutorials/playgrounds/wt_remove/nanorpm_main  4188ec5 [main]

The prune sub-command is the best option if you have multiple prunable worktrees to remove at once.