TT Lab
Get started
Learn Learning paths Courses

Git in Practice

Add Another Desk Instead of Stashing Your Work

Continue in TT Lab

One-line summary

git worktree is a feature that attaches several working directories to a single repository (a single .git). Commits, branches and objects are all shared, and only the place that is checked out differs. So you can open another branch without pushing what you were doing anywhere.

Why this is needed

This happens on a Friday afternoon. You have half-edited twelve files on a feature branch, when an outage occurs in production and you have to put a hotfix into the release branch. Usually you do it like this.

git stash
git switch release
# 고치고 커밋하고 올리고
git switch feature
git stash pop

There are three traps in this flow. First, git stash does not take untracked files by default. A newly created file stays in place even when you switch branches and gets mixed into the wrong branch. Second, stash is an unnamed stack, so once two or three pile up you cannot tell which is which, and if stash pop conflicts, you have to do the recovery on the spot. Third, the moment you switch branches, the build outputs and dependency directories are wholly invalidated. In a large project, that rebuild takes longer than the hotfix itself.

There is also the method of making a second copy with git clone. That solves the three problems above, but you must download the history in full once more, and the branches of the two copies start to drift apart. A commit made on one side is not on the other, so in the end you push and fetch between the two again.

git worktree fills exactly that gap. There is one object store, so it does not re-download the history, and there are two directories, so build outputs do not get mixed.

How it works

When you run git worktree add <경로> <브랜치>, two things are created.

An important fact comes out of this. HEAD and the index are separate for each working copy, but branch references (refs/heads/*) are shared by the whole repository. So if you try to check out the same branch in two places, git refuses.

$ git worktree add /tmp/dup main
fatal: 'main' is already used by worktree at '/home/me/repo'

This is not unfriendliness but protection. If there is one branch reference but two working trees, the moment you commit on one side, the other side ends up sitting on a commit it did not make, and the index and the actual files fall out of sync. If you really want to look at the same commit in two places, attach it without a branch using --detach.

Cleanup splits into three commands.

Situation Command What it does
The work is finished and you fold it up cleanly git worktree remove <경로> Deletes the directory and the administrative files together
You already ran rm -rf on the directory git worktree prune Deletes only the leftover administrative files
It is briefly out of sight, like an external disk git worktree lock Locks it so that prune cannot touch it

If you delete only the directory with rm -rf, that place keeps showing up in git worktree list as prunable. If you then add again under the same name in that state, you hear "it already exists". And prune deletes only the administrative files — the branch created in that place stays as it is, so to clean up the branch too, you have to run git branch -d separately.

What it looks like in the field

There is also something to watch out for. When git gc runs inside a working copy, git must know those places in order to keep alive the objects that other working copies refer to, but if there is a place that you erased with rm -rf and did not prune, that information goes stale. It is safer not to put off cleanup.

What you will do in the next lab

You attach three working copies and see for yourself that trying to open the same branch twice is refused. You leave your unsaved changes as they are and commit a hotfix separately, and you confirm that, when you rm -rf a directory, prunable appears, and that the branch remains even after prune. Finally, you even see how a locked working copy refuses remove.

The official documentation is git-worktree.