Removing a worktree
| Time to read: | Activity duration: |
|---|---|
| 12 minutes | 20 minutes |
Overview
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:
./scripts/create-playground.sh wt_remove[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_removeThe folder nanorpm_main now contain a clone of the repository and four branches, and their corresponding worktrees are created.
| Worktree path | Git branch |
|---|---|
| nanorpm_main | main |
| nanorpm_feature-a | feature-a |
| nanorpm_feature-b | feature-b |
| nanorpm_feature-c | feature-c |
How to check?
Check the list of branches in your clone:
cd playgrounds/wt_remove/nanorpm_main
git worktree listDisplayed result should be similar to the following:
/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:
pushd ../nanorpm_feature-aLet'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 --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",git diffNow, go back to the worktree of the main folder:
popdAnd delete the worktree for the feature-a branch:
git worktree remove ../nanorpm_feature-aCommand should not proceed and return with an error message:
fatal: '../nanorpm_feature-a' contains modified or untracked files, use --force to delete itGit 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.
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:
popdWe should now be able to delete the worktree for the feature-a branch:
git worktree remove ../nanorpm_feature-aThis time command issue no error, and you can check that folder was deleted:
git worktree listAnd now the output should contain one less worktree:
/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.
ls ..nanorpm_feature-b nanorpm_feature-c nanorpm_mainBut 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:
git switch feature-a
git log --oneline -5621d829 (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 pakageWe 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:
cd ../nanorpm_feature-bYou can edit again package.json file:
- open the file in any editor;
- change version number from
1.0.0to1.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:
git stash push -m 'version bump'
git stash liststash@{0}: On feature-b: version bumpGo back to main branch and check again git stash list. The very same stash stack must be shown in the console.
cd ../nanorpm_main
git stash listNow, drop the worktree where this stash was pushed.
git worktree remove ../nanorpm_feature-b
git worktree listOutput must now show only two worktrees:
nanorpm_mainformainbranch;nanorpm_feature-cforfeature-cbranch.
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:
rm -rf ../nanorpm_feature-c/When you list the worktrees, it should now be flagged as prunable:
/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] prunablegit worktree listThere's two options to cleanup the list of worktrees in your repository:
- Either you manually remove the worktree using
git worktree remove. - 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:
git worktree pruneAnd now, the list of worktrees should only display the main clone:
/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.