anthropics / anthropics/claude-code
[BUG] Cloud session can be checked out at a stale commit while git status reports the branch up to date
- Lingua principale
- Python
- Stelle
- 145k
- Fork
- 23.1k
- Metriche di merge delle PR
- Metriche PR in attesa
Descrizione
### Preflight Checklist
- [x] I have searched [existing issues](https://github.com/anthropics/claude-code/issues?q=is%3Aissue%20state%3Aopen%20label%3Abug) and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
### What's Wrong?
A cloud session can be checked out at an older commit than the branch's current head on the remote. Both `HEAD` and the remote-tracking ref are left at the older commit, so `git status` prints `Your branch is up to date with 'origin/'`. The session then reads and edits files from a superseded revision with nothing indicating it.
This was originally reported as an interaction of two session-creation fields. Further testing showed that framing is too narrow: **resolution of a branch name at session creation lags the remote**, and how far it lags varies by configuration. The staleness is therefore a function of both the configuration and how recently the head moved — a configuration that looks correct against a head that has been stable for hours can return the previous head when the push was minutes ago.
Observations, with the age of the remote head at session-creation time:
| source revision | outcome branch | head age | result | n |
|---|---|---|---|---|
| `refs/heads/` | set | 19 min – 8 h | **behind** | 5 |
| `` (bare) | set | ~7.5 h | current | 2 |
| `` (bare) | set | ~6 min | **behind** | 1 |
| `refs/heads/` | not set | ~8 h | current (detached) | 2 |
| `` (bare) | not set | ~7.5 h | current | 1 |
| explicit commit SHA | not set / set | ~8 h / ~6 min | current | 2 |
Only the explicit-SHA configuration has been observed correct against a freshly-pushed head. The two "outcome branch not set" configurations were never tested against a fresh head, so they are untested rather than immune.
Reflogs from a reproducing session show the fetch retrieved the current head correctly, and the tracking ref was then written backwards:
```
remote-tracking ref
-> fetch --no-progress --depth 50 origin refs/heads/: fast-forward
-> (no reflog message)
HEAD
-> (no reflog message)
-> checkout: moving from to
```
The local branch ref did not move at all during startup.
This is not a container-reuse or stale-snapshot effect: it reproduced in a newly created cloud environment containing no prior containers, and two sessions on the same container as a reproducing session — differing only in creation fields — were checked out at the current head.
Related but distinct: https://github.com/anthropics/claude-code/issues/89868 (stale state after container reclaim). See Additional Information.
### What Should Happen?
The session should be checked out at the branch's current head on the remote, which the startup fetch has already retrieved.
Failing that, the remote-tracking ref should be left at the fetched value so the discrepancy is visible — `git status` should report the branch as behind rather than up to date. Writing the tracking ref backwards to match a stale `HEAD` makes the condition undetectable without an explicit `git ls-remote` or `git fetch`.
### Error Messages/Logs
```shell
No error is raised. The environment-runner log (/tmp/env-manager.log) from a reproducing session, in order:
Starting repository fetch mode=resume
Fetching specific ref
Git command succeeded duration_ms=971
Processing branch from outcomes mode=resume
Resume mode: creating local branch directly
Branch doesn't exist on remote, creating new branch locally from current HEAD
Updated remote tracking branch
The branch did exist on the remote: the fetch of that exact ref had just succeeded, and git ls-remote origin from inside the session returned the current head.
Two timing observations about that sequence:
1. The gap between "Resume mode: creating local branch directly" and "Branch doesn't exist on remote..." is 50 microseconds.
2. No "Executing git command" entry appears anywhere between "Processing branch from outcomes" and "Updated remote tracking branch".
Resulting state inside the session:
$ git status
On branch
Your branch is up to date with 'origin/'.
nothing to commit, working tree clean
$ git rev-parse HEAD
$ git ls-remote origin
refs/heads/
```
### Steps to Reproduce
The reproduction has a timing dimension. Running only the first phase can produce false passes.
**Phase A — head stable for hours.**
1. Confirm the branch head on the remote has not moved for several hours.
2. Create cloud sessions against that repository and branch, in the same environment, varying only two creation fields:
- source revision `` (bare) | outcome branch not set
- source revision `` (bare) | outcome branch ``
- source revision `refs/heads/` | outcome branch not set
- source revision `refs/heads/` | outcome branch ``
3. In each session run:
```
git rev-parse HEAD
git status -sb
git ls-remote origin
```
Observed: only the fully-qualified-plus-outcome-branch configuration is behind.
**Phase B — head pushed minutes ago.**
4. Push a new commit to the branch.
5. Within a few minutes, create a session with the bare branch name and the outcome branch set — the configuration that passed Phase A.
Observed: checked out at the **previous** head, while `git status` reports the branch up to date.
**Control.** A session created with `source_revision` set to the explicit commit SHA returned that commit in both phases, and with an outcome branch set it lands on the branch rather than detached.
Sessions created through the web UI carry the fully-qualified form together with an outcome branch, which is the configuration that fails in both phases. Four such web-created sessions were all checked out at the older commit, one of them in a newly created environment.
**Workaround:** set `source_revision` to the explicit commit SHA rather than a branch name, with `outcome_branch` set to the branch. This is the only configuration observed correct against a recently-pushed head. Note this pins the session — commits pushed after creation will not appear.
### Claude Model
Not sure / Multiple models
### Is this a regression?
Not sure
### Last Working Version
_No response_
### Claude Code Version
2.1.247 (Claude Code)
### Platform
Anthropic API / Other.
Claude API (claude.ai subscription — Claude Code on the web)
### Operating System
Linux (Ubuntu 24.04.4 LTS, kernel 6.18.44-fc-v21, x86_64 — Anthropic-hosted cloud container)
### Terminal/Shell
Other. No terminal — Claude Code on the web; container shell is bash.
### Additional Information
**Correction history.** This report originally described the fault as an interaction of two creation fields and offered the bare branch name as a workaround. Retesting against a commit pushed ~6 minutes earlier reproduced the fault in that configuration, so the workaround was withdrawn and the framing widened to branch-name resolution lag. The observation that the bare form was correct had been taken when the branch head had been stable for ~7.5 hours.
**How the observations were gathered:**
- `.git/logs/HEAD`, `.git/logs/refs/heads/...` and `.git/logs/refs/remotes/origin/...` read inside affected sessions.
- `/tmp/env-manager.log` on the container, which records startup for every session that has run on that container.
- Session records read through the API, for the source-revision and outcome-branch fields as stored.
- Sessions created programmatically, varying those fields against a fixed repository, branch and environment, at two different head ages.
Observation counts are in the table above. Of the two fully-qualified-without-outcome-branch observations, one reported the resulting SHA explicitly and the other reported the checkout as confirmed without stating it.
**Relationship to https://github.com/anthropics/claude-code/issues/89868:**
That report describes stale working trees after container reclaims during a long-running session, attributed to restoring an out-of-date filesystem snapshot, with untracked files erased and background processes terminated. This report is distinct: it triggers at session creation, affects only `HEAD` and the remote-tracking ref, and loses no data — the fetch retrieves the current objects before the ref is written backwards.
One possible overlap worth checking: a session resuming after a reclaim runs the same branch-processing step (logged `mode=resume`), so a resumed session configured with an outcome branch may reach the same ref rewrite. That would account for a working tree landing behind commits the same session had previously pushed, without any snapshot being stale — though not for lost untracked files or terminated background processes.
**Version mismatch (unrelated to the above):** `claude --version` reports `2.1.247`, while the `CLAUDE_CODE_VERSION` environment variable in the same session evaluates to `2.1.42` — corroborating the mismatch noted in the other report.
**Not established:**
- Where the older commit value originates. In a newly created environment there is no prior local branch and no cached clone, so it does not come from the container.
- Why the lag differs between the branch-name forms, and whether the "outcome branch not set" configurations are genuinely unaffected or merely untested against a fresh head.
- Whether the branch-existence determination consults anything, and if so what. The 50-microsecond gap and the absence of a logged git command are the only observations bearing on it.
Session IDs for the reproducing and control sessions can be supplied on request.
Guida per i contributori
Nessuna guida per i contributori indicizzata per questo repository
Direzione di ricerca
Start by reproducing Phase B and inspect /tmp/env-manager.log alongside .git/logs/HEAD and .git/logs/refs/remotes/origin/... during startup. Trace the “Processing branch from outcomes” and “Updated remote tracking branch” steps; done means the session reaches the remote branch head, or leaves the fetched remote-tracking ref intact so git status exposes any mismatch.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Valutazione
- Stack tecnologico
- git, python
- Ambito
- cloud, devops, infrastructure
- Tipo di issue
- Bug
- Difficoltà
- 5/5
- Tempo stimato
- Più di una settimana
- Stato di attività
- Attiva
- Chiarezza
- Abbastanza chiara
- Idoneità per principianti
- 35/100