WARSHALL
Docs/Git/Auto git and worktrees

Auto git and worktrees

Every terminal works in its own git worktree, on its own branch, and its work is committed when a run finishes. This page covers the checkout, the commits and the git popup in the terminal header.

The terminal checkout

A terminal does not edit your project folder. It works in a worktree, a separate checkout of the same repository on a branch of its own, cut from the project’s main branch. Two terminals can then work at the same time without touching each other’s files.

  • The checkout is made by the terminal’s first run, not when the terminal opens. A terminal that never runs costs nothing on disk.
  • Closing a terminal parks its checkout on disk. The next terminal on that project reuses it instead of making a new one, as long as it holds no work.
  • A new checkout starts with the same uncommitted changes your project folder has, so a run starts from what you are looking at. Modified, staged and new files are carried over. Nothing is committed in either place, and your project folder is left exactly as it was. A checkout that carried changes holds work, so it is not reused until those changes are committed or gone.
  • Git leaves ignored files out of a checkout, but the app under test often needs some of them. Files matching the Files copied into new task checkouts row in Settings > Projects are copied in. The default is .env*.
  • A project that holds other git repositories inside it gets a checkout for each repository, each on its own branch.

If the checkout cannot be made, the prompt is refused with Failed to create worktree. and nothing runs.

Installing dependencies

A new checkout has no installed dependencies. Warshall runs an install command in it once, the first time the agent runs a command that needs one, such as a package manager, a runtime, or a build or test tool. A terminal that only reads code never waits for an install.

The command is found in this order.

  1. A command set for that repository in settings.json, under worktrees.setupOverrides.
  2. A .worktreesetup file at the repository root. The whole file is the command.
  3. The global worktrees.setupCommand in settings.json, for the project root only.
  4. Detection from the repository’s own files. A JavaScript lock file or package.json gets the matching install, a Python lock file or requirements.txt gets the Python one, and a Gemfile gets bundle install. Maven, Gradle, Cargo and Go fetch dependencies when they build, so nothing is run for them.

If the install fails, the terminal prints a line naming its log file, and the agent’s command still runs. A failed install is not retried. Files an install rewrites, such as a lock file, are put back so they never end up in a commit.

Folders that are not git repositories

A folder that is not a git repository has no worktrees to cut, so it can hold only one terminal. Opening a second one is refused, and the app says why. The git popup shows Not a git repository with an Initialize button that makes the folder a repository.

Automatic commits

When a Claude Code or Codex run finishes cleanly and the checkout has changes, those changes are committed on the terminal’s branch. A run that changed nothing commits nothing. Changes left over from an earlier run, including a run on a local endpoint model, go into the next commit.

The commit subject comes from the first of these that is available.

  1. The WorkMap requirement the terminal is working on, when it has one.
  2. A subject your fallback model writes in a separate background run, from your request, the changed files and the run’s final answer.
  3. The changed files themselves, for example Updating One.java, Two.java, and Three.java.

The commit message is that one line. Nothing about the terminal or the model is written into your repository’s history.

Anything that needs the commit right away does not wait for the fallback model. That is the next run in the terminal, a push, a pull, a squash, closing the terminal, or a combined build. The commit lands at once with the changed files as its subject.

The git popup

The terminal header has a control labeled auto. Hover it and the popup opens on this terminal’s checkout. The head reads Local, because none of its commands reach a remote, then how many commits the branch is behind the main branch. Before the first run it shows only the main branch’s name.

CommandWhat it does
CommitCommits every change the popup lists, staged or not. A box opens over the change lines for the message. Enter commits and Escape closes the box.
PushLands the branch on the main branch. The branch is replayed on top of main, then main moves forward to it, so main never gets a merge commit. If main is the branch your project folder has checked out, the folder’s uncommitted changes are set aside during the move and put back after.
PullReplays the branch on top of the latest main branch, inside the checkout. Your project folder never moves.
SquashFolds the branch’s own commits into one, named by the fallback model. With more than two commits it first asks how many, offering the newest two, the newest four when there are more, or all of them, up to the six the popup shows. Uncommitted work is left as it was.

If Push or Pull hits a conflict, the fallback model resolves it. If it cannot, the replay is undone, the branch is left as it was, and the popup names the conflicted files.

Each command reports in a note under the head, for example pulled main [local], pushed onto main [local] or squashed 3 commits.

When a command is not available, pointing at it says why.

  • The agent is working. holds Pull and Commit while a run is going.
  • Nothing to commit. means the checkout has no changes.
  • This terminal has no work yet. appears before the first run.

Changes and commits

  • A change line names the first file and counts the rest. Pointing at the count names every file. Clicking the line opens that file’s diff in the review window. The x on it throws away that one file’s uncommitted changes.
  • The graph shows the branch’s own commits above the main branch’s recent ones. Clicking a commit opens its changed files in the review window.
  • Double-click the newest commit to edit its message in place. Only the newest can be edited, because rewording an older one would rewrite every commit above it. Its x undoes it, which leaves its changes as unstaged edits.

When a project holds several repositories, the popup has a numbered footer, one number per repository. Pick a number to see that repository’s own changes and commits.

Uncommitted changes during a command

Settings > Git has Uncommitted changes on Push and Uncommitted changes on Pull. Each is Ask, Leave Modified or Commit, and Ask is the default.

With Ask, the command waits. The popup says how many files are not committed and offers three answers.

  • Leave Modified sets the changes aside while the command runs and puts them back after.
  • Commit commits them first.
  • Amend Last Commit folds them into the branch’s newest commit. It appears only when the branch has a commit to fold into.

The command then runs, and the note says what your answer did and what the command did. If putting set-aside changes back conflicts, the fallback model resolves it. Only if that fails do conflict markers stay in the files, and the note names them.

The main branch

Every command above works against one branch, the project’s main branch. Worktrees are cut from it, Push lands on it, and Pull brings it in.

Pick it in Settings > Projects under Main branch, the branch tasks fork from and land on. Left on Detected, the app uses the repository’s own main line, then a local main, then a local master, and otherwise the branch your project folder has checked out.