Skip to content

internal/cmd: git_wrapper: wrap difftool and mergetool - #181

Merged
mroth merged 1 commit into
mroth:mainfrom
marcuslannister:feat/wrap-difftool-mergetool
Aug 8, 2026
Merged

internal/cmd: git_wrapper: wrap difftool and mergetool#181
mroth merged 1 commit into
mroth:mainfrom
marcuslannister:feat/wrap-difftool-mergetool

Conversation

@marcuslannister

Copy link
Copy Markdown
Contributor

Closes #83.

git diff 1 expands the shortcut, but git difftool 1 fails with
fatal: ambiguous argument '1'. The two commands take the same pathspec
arguments, so the difference is surprising. difftool simply is not in the
wrapper's dispatch list.

This adds difftool and mergetool to the --relative branch.

mergetool is included because scmpuff numbers conflicted files during a
merge — precisely when picking one by number is most useful. That is the
request in #83, where the suggested workaround was to use $e1 directly.

Neither command has the ambiguity that makes stash a special case in #160:
for stash pop 1 a number is a stash index, but difftool and mergetool
only ever take paths.

Tests

Two testscripts, covering bash, zsh and fish:

  • command-shell-wrapper-difftool-by-number.txtar — uses --extcmd=echo so
    no real diff tool is needed, and asserts the tool receives the relative
    worktree path.
  • command-shell-wrapper-mergetool-by-number.txtar — builds a real merge
    conflict and resolves it with a stub tool, so nothing interactive runs.

Note on zsh -f

The new scripts invoke zsh with -f, which the existing wrapper tests do not.

zsh reads /etc/zshenv for every shell, including non-interactive ones. On
some systems that file prepends profile directories to PATH — nix-darwin
does this, and I hit it locally. The effect is that the zsh leg silently runs
an installed scmpuff instead of the binary under test.

The current wrapper tests cannot detect this, because every subcommand they
cover (add, reset, restore) exists in both the installed and the
under-test version, so the results agree either way. A test for a newly added
subcommand is the first one that can catch the substitution — which is how I
found it. -f makes the zsh leg hermetic.

Happy to drop the -f if you would rather keep the scripts uniform, or to
apply it to the existing scripts in a separate change.

Both take diff's pathspecs, so a numeric shortcut should expand the same way
it does for `diff` today. Currently `git difftool 1` reaches git verbatim and
fails with "ambiguous argument '1'", while `git diff 1` works -- a surprising
inconsistency, since the two commands take the same arguments.

mergetool is included because scmpuff numbers conflicted files during a merge,
which is exactly when selecting one by number is most useful. This is the
request in mroth#83, where the workaround given was to use $e1 directly.

Neither command has stash's ambiguity: for `stash pop 1` a number is a stash
index, but difftool and mergetool only ever take paths.

The new testscripts invoke zsh with -f. zsh reads /etc/zshenv for every shell,
including non-interactive ones, and on some systems (nix-darwin, for one) that
file prepends profile directories to PATH. That shadows the scmpuff binary
under test with an installed copy, so the zsh leg silently exercises the wrong
binary. Existing wrapper tests do not notice, because every subcommand they
cover is present in both versions; a test for a newly added subcommand is the
first that can detect the substitution.
@mroth

mroth commented Aug 8, 2026

Copy link
Copy Markdown
Owner

@marcuslannister this looks great! I wasn't aware of the -f flag, that makes sense to make the integration tests more portable. A follow up PR to add it to the other scripts sounds great as well.

@mroth
mroth merged commit 1ae1ffa into mroth:main Aug 8, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Not working with git mergetool?

2 participants