Since #65, a diff whose content comes from outside the working tree — a commit, a stash entry, or (once a compare view exists) two arbitrary revisions — correctly offers no staging. But it offers nothing else either, so the panel is inert.
Browsing an old commit and wanting this hunk, in my working tree is a normal thing to want. Sublime Merge covers it by writing a .patch and applying it. rgitui has no equivalent, at any granularity: the only way to recover one hunk from history is to copy the lines out by hand.
Note this is not only about history. The case that matters most is comparing across branches and pulling the difference into the working tree — the same operation, with the source being a ref pair rather than a commit. Modelling it as "historical content is read-only" would make cross-branch apply a special case bolted on later, so it should be one mechanism from the start.
What's missing
- Apply a hunk from a commit, stash or ref pair into the working tree — the hunk-level equivalent of cherry-pick. (Git has no hunk-level cherry-pick; this is
git apply.)
- Revert a hunk in the working tree — the hunk-level equivalent of revert (
git apply -R).
- The same at the granularity the user is actually working at: the hunk by default, the selected lines when a line selection exists (matching how partial staging already behaves), and the whole file from a menu.
Why it isn't just git apply
Worth recording, because both obvious routes are wrong for this case:
- libgit2's
repo.apply is a plain patch applier with no three-way fallback, and fails when hunk context does not line up. A dirty working tree is the normal case here — you compare against another branch precisely because you are mid-change — and an uncommitted edit anywhere in a hunk's context window is enough to make it fail.
git apply --3way merges into the index, and refuses with does not match index whenever the working-tree file differs from its index entry. That is exactly the dirty tree the fallback would exist for. It also leaves conflict markers and an unmerged index entry behind on failure.
PR #69 implements this by reconstructing the two sides and letting libgit2 merge them, so unrelated local edits merge cleanly, overlapping edits conflict, and the index is never touched.
Since #65, a diff whose content comes from outside the working tree — a commit, a stash entry, or (once a compare view exists) two arbitrary revisions — correctly offers no staging. But it offers nothing else either, so the panel is inert.
Browsing an old commit and wanting this hunk, in my working tree is a normal thing to want. Sublime Merge covers it by writing a
.patchand applying it. rgitui has no equivalent, at any granularity: the only way to recover one hunk from history is to copy the lines out by hand.Note this is not only about history. The case that matters most is comparing across branches and pulling the difference into the working tree — the same operation, with the source being a ref pair rather than a commit. Modelling it as "historical content is read-only" would make cross-branch apply a special case bolted on later, so it should be one mechanism from the start.
What's missing
git apply.)git apply -R).Why it isn't just
git applyWorth recording, because both obvious routes are wrong for this case:
repo.applyis a plain patch applier with no three-way fallback, and fails when hunk context does not line up. A dirty working tree is the normal case here — you compare against another branch precisely because you are mid-change — and an uncommitted edit anywhere in a hunk's context window is enough to make it fail.git apply --3waymerges into the index, and refuses withdoes not match indexwhenever the working-tree file differs from its index entry. That is exactly the dirty tree the fallback would exist for. It also leaves conflict markers and an unmerged index entry behind on failure.PR #69 implements this by reconstructing the two sides and letting libgit2 merge them, so unrelated local edits merge cleanly, overlapping edits conflict, and the index is never touched.