Home / Alt manpages / git-mergetool--lib(1)

  • git-mergetool--lib(1)
  • User command
  • linux

Source Git's mergetool library safely in a shell script

You will use Git's git-mergetool--lib as a shell library, rather than trying to run it as a command. The guide takes about 15 minutes and assumes a POSIX-style shell, Git, and a script you can test without touching a real merge.

1. Confirm the installed interface

This is an internal scriptlet for people studying Git's scripts or writing a new one. It is not a replacement for the user-facing git mergetool command. On this machine, the installed package is git-man version 2.43.0-1ubuntu7.3 and git --version reports Git 2.43.0. The local manual page documents the same 2.43.0 interface.

$ git --version
git version 2.43.0
$ command -v git
/usr/bin/git
$ test -f "$(git --exec-path)/git-mergetool--lib" && echo library-found
library-found

The path is derived from Git's executable path, so do not hard-code /usr/lib/git-core into a portable script. The library is intended to be sourced with the shell's dot command.

2. Set the mode before sourcing

Set TOOL_MODE to exactly merge or diff before loading the file. This choice controls which configuration keys and tool functions the library selects. Keep the source operation in the same shell process: running it in a separate command would define functions only in that child shell.

#!/bin/sh
TOOL_MODE=merge
. "$(git --exec-path)/git-mergetool--lib"

tool=$(get_merge_tool) || exit $?
printf 'selected merge tool: %s\n' "$tool"

For a diff helper, use TOOL_MODE=diff instead. An unset value, a spelling such as merging, or sourcing first and setting it afterwards is a script error. The documented functions are get_merge_tool, get_merge_tool_cmd, get_merge_tool_path, initialize_merge_tool, and run_merge_tool.

3. Test selection without changing Git configuration

Git normally reads merge.tool, then validates that named tool through its built-in tool definitions or a configured command. To test the library without writing global or repository configuration, Git's temporary configuration environment can provide a tool name and command for one process.

$ lib="$(git --exec-path)/git-mergetool--lib"
$ GIT_CONFIG_COUNT=2 \
  GIT_CONFIG_KEY_0=merge.tool GIT_CONFIG_VALUE_0=demo \
  GIT_CONFIG_KEY_1=mergetool.demo.cmd GIT_CONFIG_VALUE_1='printf demo-run' \
  TOOL_MODE=merge sh -c '. "$0"; printf "tool="; get_merge_tool; printf " status=%s\n" "$?"; printf "cmd="; get_merge_tool_cmd demo; printf "\n"' "$lib"
tool=demo status=0
cmd=printf demo-run

get_merge_tool prints the selected name. Its return status is 0 for a configured tool. If no suitable tool is configured, the library tries candidates based on the environment and returns status 1 when it has guessed one. That non-zero status is easy to lose if your script only captures standard output, so handle it explicitly.

For diff mode, the custom command lookup first considers difftool.demo.cmd and can fall back to mergetool.demo.cmd. Merge mode uses mergetool.demo.cmd. This is a lookup helper, not a safe parser: commands are later evaluated as shell code by the tool runner.

4. Initialise and run a tool only with complete inputs

Call initialize_merge_tool TOOL when your script needs the tool-specific functions in scope, including functions it may override. To launch the selected tool, run_merge_tool needs the tool name and a true or false flag saying whether a merge base exists.

initialize_merge_tool "$tool" || exit 1

# Set these to real temporary or worktree paths before the call.
LOCAL=/path/to/local-file
REMOTE=/path/to/remote-file
MERGED=/path/to/merged-file
BASE=/path/to/base-file
export LOCAL REMOTE MERGED BASE

run_merge_tool "$tool" true

The manual requires MERGED, LOCAL, REMOTE, and BASE to be defined for the merge tool. The BASE path still needs a deliberate value when the flag is false, because individual tool scripts may interpret the environment differently. Read the relevant file under Git's mergetools directory before relying on that detail.

Do not point this example at a valuable worktree until the complete workflow is tested. A merge tool can edit MERGED, and the library is allowed to launch it. Make a copy or use a disposable directory first. Recovery is to discard the disposable directory and rerun from the original files; for a real worktree, preserve a commit or stash before experimenting.

5. Understand how success is decided

The library does not blindly trust every tool's exit status. For an untrusted tool it touches BACKUP, runs the command, then checks whether MERGED is newer than that backup. If it does not look changed, it asks whether the merge was successful. A non-interactive script can hang or fail here if it has not selected a tool whose exit code is trusted.

mergetool.<tool>.trustExitCode can make Git trust a configured tool's status. Built-in tools can also advertise that their status is reliable. Treat this as a correctness decision, not a convenience switch: setting it for a command that exits successfully without writing the merged file can mark an incomplete merge as finished.

GUI selection is another source of surprises. With GIT_MERGETOOL_GUI=true, the library searches GUI configuration. If that variable is unset, the relevant mergetool.guiDefault or difftool.guiDefault setting is used; with auto, the presence of DISPLAY decides. A terminal job may therefore select a different tool from an interactive desktop session.

6. Check the failure boundaries

  • If sourcing fails, verify TOOL_MODE and the path printed by git --exec-path.
  • If the named tool is unknown, check its built-in definition or provide mergetool.<tool>.cmd. A configured path alone is not always enough.
  • If a diff tool is rejected for merge mode, or a merge-only tool is rejected for diff mode, check the mode before changing the tool.
  • If a guessed tool is selected, inspect the return status from get_merge_tool and decide whether guessing is acceptable for automation.
  • If a GUI tool fails in a service or SSH session, check DISPLAY and force a suitable non-GUI configuration rather than adding a display workaround blindly.

No command in this guide needs elevated privileges. Do not use sudo to source the library or to launch a merge tool. Privilege would give a faulty custom command a wider blast radius without fixing its inputs or exit-status handling.

Done means

  • Your script sets TOOL_MODE before sourcing the library from $(git --exec-path).
  • You distinguish configured tool selection from a guessed fallback and check its return status.
  • You tested custom command lookup without writing persistent Git configuration.
  • You provide all four merge paths before calling run_merge_tool.
  • You understand whether the selected tool's exit code or merged-file timestamp determines success.
  • Real merge files are protected by a disposable test directory, commit, stash, or backup.