Skip to content

Diffs from a commit, stash or ref pair cannot be applied to the working tree #70

Description

@adehad

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions