Repository navigation
fix(git-branch): read a jj repo's detached HEAD as no branch - #705
Open
eric-engberg wants to merge 2 commits into
Open
eric-engberg wants to merge 2 commits into
eric-engberg wants to merge 2 commits into
Conversation
Since Git Branch started showing a detached HEAD's commit, it shows one in every colocated jj repo: jj keeps git's HEAD detached on the working copy's parent, so the widget printed "⎇ (4227868)" where it used to show "no git", or hide with "hide no git". That commit is jj's bookkeeping, not something the user checked out, and users who pair Git Branch with the jj widgets and hide it outside git repos saw it come back in every jj repo. On a detached HEAD, check whether the directory is in a jj repo first. If it is, there's no branch: "no git", or hidden, as before. A plain git repo's detached HEAD (rebase, bisect, tag checkout) still shows its commit. The jj check only runs on a detached HEAD.
… branch On a detached HEAD, Git Branch took any successful `jj root` to mean the repo was a colocated jj repo, where jj keeps git's HEAD detached. But jj finds its workspace by walking up to the nearest .jj, and doesn't stop at a git repo's own root. So in a plain git repo anywhere under a jj workspace (a home or dotfiles tree managed by jj, a git checkout inside a jj monorepo), `jj root` succeeds too, and a rebase, bisect or tag checkout there showed "no git", or hid the widget, instead of the detached commit. Now the repo counts as colocated only when git's top-level directory holds the .jj. A git repo nested under a jj workspace shows its detached commit again, while a colocated repo, and a jj workspace with its own git worktree, still read as no branch. The extra git call only runs on a detached HEAD where `jj root` has already succeeded.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Relates to #517: it undoes the part of that issue's problem that showing detached commits (#679) added. Git Changes, which the issue is about, is unchanged; #499 covers that.
What
In a colocated jj repo, Git Branch goes back to what it showed before #679:
⎇ no git, or nothing with "hide no git". Any other git repo's detached HEAD (rebase, bisect, tag checkout) still shows its commit,⎇ (7d897a5). That includes a git repo nested inside a jj workspace, such as a submodule of a colocated repo or a clone under a jj-managed home directory.Why
jj keeps git's HEAD detached in a colocated repo, on the working copy's parent. Since #679, Git Branch shows a detached HEAD's commit, so it now shows one in every jj repo:
⎇ (4227868). That commit is jj's bookkeeping, not something the user checked out. #517's reporter pairs the Git widgets with the jj widgets and hides the Git ones outside git repos. Git Branch used to hide in jj repos for them, and since #679 it no longer does.Checked with jj 0.46.0: after
jj git init --colocateand a commit,git symbolic-ref HEADfails ("ref HEAD is not a symbolic ref"), andgit rev-parse --short HEADgives the commit the widget then printed.How
On a detached HEAD,
GitBranch.renderchecks that the repo is a colocated jj repo before looking up the commit. Two things must hold:jj rootsucceeds (isInsideJjRepo, the same check the jj widgets use), and git's top-level directory (git rev-parse --show-toplevel) holds a.jjdirectory.jj rootalone isn't enough. jj finds its workspace by walking up to the nearest.jjand doesn't stop at a git repo's root, so it also succeeds in a git repo nested anywhere under a jj workspace, whose HEAD jj doesn't manage. In a colocated repo the ref isnull, which takes the existing "no git" path.The checks only run on a detached HEAD, so a checked-out branch costs nothing more, and the top-level lookup only runs once
jj roothas succeeded. Outside a jj workspace, or without jj installed,jj rootfails and the commit shows as before. A second workspace fromjj workspace addgets its own git worktree with a.jjat its top level, so it reads as no branch like the first.isInsideJjRepoitself is unchanged, so the jj widgets aren't affected.Demo
Piped renders in a colocated jj repo (bookmark
demo), then in a plain git repo on a detached HEAD. Each has Git Branch as is on line 1, and with "hide no git" on line 2, next to Jj Bookmarks.Powerline
main)Plain
main)Update
These are piped renders against fake scratch repos built with jj 0.46.0, each on a detached HEAD: a colocated jj repo, a git submodule of that repo, and a plain git repo under a jj workspace that isn't colocated. In each group, line 1 shows Git Branch as is and line 2 shows it with "hide no git". Before this fix, both nested repos show "⎇ no git" or hide the widget. After it, they show their commits (973d5d1, 1642305), and the colocated repo still shows no branch, as before.
Powerline, before and after:
Plain, before and after:
Testing
GitBranch.test.ts:⎇ no git, or nothing with "hide no git", after exactly four commands: the work-tree probe,git symbolic-ref HEAD,jj rootandgit rev-parse --show-toplevel(no commit lookup). The test points them at a temp directory with a real.jjin it.jj rootgives the workspace, the top level iscode/appinside it) still renders its detached commit,⎇ (ddfb2de), with "hide no git" on.jj rootcall with "no jj repo" and still get the commit and its link.bun test: 3115 pass, 0 fail.bun run lintpasses. Under Node (Vitest),GitBranch.test.tspasses 29 of 29.Built CLI with real jj 0.46.0, piped renders on a detached HEAD, Git Branch as is / with "hide no git". Bun 1.4.2 and Node 26.10.0 print the same in every case. "First commit" is this PR's first commit, which checked
jj rootalone.jj git init --colocate, then a commit)⎇ no git/ hidden⎇ no git/ hiddenjj workspace add)⎇ no git/ hidden⎇ no git/ hidden⎇ no git/ hidden⎇ (87ae600)/⎇ (87ae600)⎇ no git/ hidden⎇ (8baf8cc)/⎇ (8baf8cc)⎇ (8baf8cc)/⎇ (8baf8cc)⎇ (8baf8cc)/⎇ (8baf8cc)Baseline configs (plain and Powerline, example payload), built CLI: identical to
mainunder both runtimes, and the TUI opens and exits under both.