Git Diff Two Worktrees' Uncommitted Changes
Prepared and checked using AI. Sources are linked in the article.
To git diff two worktrees’ uncommitted changes, compare their directories with git diff --no-index -- path-a path-b. This form compares paths on the filesystem, so neither agent needs to stage or commit. Start with the source directories you care about: a whole-worktree comparison can also include ignored files and Git’s administrative files. Check each worktree’s status alongside the comparison so you can tell which agent changed a file and whether a new file is untracked.
Locate the worktrees and check their starting commits
Run the following from a checkout of the repository. Git can list its worktrees and their checked-out revisions:
git worktree list --porcelain
For example, if two agent worktrees are siblings of the checkout you are in, give them short shell variables for the commands below:
A=../agent-a
B=../agent-b
Use the paths shown by git worktree list if your layout differs. Quoting $A and $B in later commands also keeps paths containing spaces together.
Check each starting commit before attributing every difference to an agent. git -C runs a command from the specified directory, and git rev-parse HEAD prints the current commit’s object name:
git -C "$A" rev-parse HEAD
git -C "$B" rev-parse HEAD
If the names match and neither agent has committed, the worktrees share the same committed starting point. A direct directory diff then shows how their current files differ. If the names do not match, the directory diff still compares their current files, but some differences may come from the commits they started on. Review each worktree against a known shared starting commit before treating a difference as an agent’s work. For more on why each agent has a separate checkout, see Git worktrees explained.
Inventory each agent’s changes first
Git status separates differences in the index, differences in the working tree, and untracked paths. Inspect both worktrees, requesting individual untracked filenames rather than a single entry for an untracked directory:
git -C "$A" status --short --untracked-files=all
git -C "$B" status --short --untracked-files=all
In short status output, the first column describes the index and the second describes the working tree. ?? marks an untracked path. This tells you, for example, whether both agents edited an existing file or whether only one created a new file.
Next, inspect each agent’s changes against its own HEAD:
git -C "$A" diff --stat HEAD
git -C "$B" diff --stat HEAD
git -C "$A" diff HEAD
git -C "$B" diff HEAD
--stat gives a compact file summary; the plain commands show the patches. With a commit argument such as HEAD, git diff compares that commit with the working tree, including changes to tracked files whether or not they are staged. An untracked file is absent from that patch because it has no tracked version to compare. That is why the status commands belong in the same review.
These commands answer two different questions:
| Command | Question it answers |
|---|---|
git -C "$A" diff HEAD | What changed in A’s tracked files since A’s current commit? |
git -C "$B" diff HEAD | What changed in B’s tracked files since B’s current commit? |
git diff --no-index -- "$A/src" "$B/src" | How do the current files in these two directories differ? |
The first two patches show each agent’s work relative to a commit. The last shows one current directory against another; it does not label a change as A’s or B’s contribution.
Compare the current files side by side
For example, if the relevant code is under src in both worktrees, begin with file names and a summary before reading the full patch:
git diff --no-index --name-status -- "$A/src" "$B/src"
git diff --no-index --stat -- "$A/src" "$B/src"
git diff --no-index -- "$A/src" "$B/src"
The left path is the before side of the patch and the right path is the after side. If both agents changed the same line differently, the full patch puts those versions opposite each other. If a file exists on only one side of the selected directories, the comparison presents it as an addition or deletion relative to that direction. Swap the paths if you prefer to read the patch from B toward A.
--no-index reads file contents from the paths you supply. It therefore shows the current contents of a staged file even if the agent edited it again after staging. It can also show untracked files inside the selected directories. It does not use the staging area as a snapshot of either side.
Select the smallest directory that covers the decision you are making. Comparing both worktree roots is possible, but a filesystem comparison does not apply Git’s ignore rules. It can include dependency directories, build output, local secrets, and the .git entries that link the worktrees to Git. A narrower directory reduces that noise, but it may leave out relevant changes elsewhere; check status first and compare additional directories where needed.
A difference is an expected exit status here. --no-index implies --exit-code: Git returns 0 when the selected paths match and 1 when they differ. If a script treats every nonzero status as failure, handle 1 as “differences found” while still investigating other errors. Do not interpret an empty patch from a narrow directory as proof that the entire worktrees match.
Account for untracked and ignored files
To get a dedicated list of untracked files that Git does not ignore, use git ls-files --others --exclude-standard in each worktree:
git -C "$A" ls-files --others --exclude-standard
git -C "$B" ls-files --others --exclude-standard
This is useful when git diff HEAD looks small but one agent has written new source files. Compare the relevant parent directory with --no-index to read those files alongside the other agent’s version. A newly created file does not need to be staged just to appear in that filesystem comparison.
Ignore patterns describe intentionally untracked files that Git should ignore. The --exclude-standard list follows those rules; a --no-index directory comparison does not. If the latter is full of generated files, narrow its paths using the status and untracked-file lists rather than assuming the noise is part of the proposed change. Conversely, if an agent produced a file that is ignored but matters to your decision, compare that file’s contents deliberately.
Turn the comparison into a review decision
Read the two diff HEAD patches to understand each agent’s proposal, then use the directory comparison to locate disagreements in the resulting files. Check whether one version includes a new file the other never wrote, whether an agent changed a file outside the area you intended, and whether the two versions make different assumptions about the same interface. A direct diff identifies differences; it does not establish which behavior is correct.
When the worktree HEAD values differ, compare both against the same known commit as well. git diff accepts a commit argument in place of HEAD, so substituting the shared starting commit shows each worktree’s tracked files relative to that point. Keep the untracked-file inventory beside those patches: changing the commit argument does not add untracked files to git diff.
For a quick check of tracked changes before choosing either version, run git diff --check HEAD separately in each worktree. It reports introduced conflict markers and whitespace errors; it does not review behavior or cover untracked files. Then review the code paths and tests relevant to the task. The AI-generated code review workflow offers a broader checklist for that step.
Where Parallel Code fits
Parallel Code is our free, open-source desktop app for macOS and Linux. It runs agents in separate git worktrees and provides a diff-first review surface. Its Arena mode races agents on one task so you can keep the winning diff; the Git commands above remain useful when you want to inspect the working directories directly.
Frequently asked questions
Can I compare two worktrees without committing or staging?
Yes. git diff --no-index -- "$A/src" "$B/src" compares the current filesystem contents of those directories. Check both worktrees’ status too, so the comparison’s scope and any untracked files are clear.
Why does git diff branch-a branch-b miss the agents’ edits?
That form compares commits at the branch tips. Working-tree edits made after those commits are outside the comparison; use git diff HEAD inside each worktree or git diff --no-index across their current files.
Why is git diff HEAD empty when an agent wrote a new file?
A new, untracked file has no entry in the commit for that diff to compare. Find it with git status --short --untracked-files=all or git ls-files --others --exclude-standard, then include its directory in the filesystem comparison.
Does exit code 1 mean the directory comparison failed?
For git diff --no-index, exit code 1 means the selected paths differ; 0 means they match. Investigate an error message or another exit status separately, especially when using the command in automation.