Home / Alt manpages / git-merge-index(1)

  • git-merge-index(1)
  • User command
  • linux

Drive a Merge Program with git merge-index

git merge-index hands each unmerged index entry to a merge program you name. That is exactly what you want when debugging why an automated merge step went wrong. Allow about fifteen minutes. You need Git 2.43.0 or a nearby version, a repository with an unresolved merge, and a clean recovery point such as a disposable branch or a recent commit.

This is an ordinary user command and needs no elevated privileges. It can change files once the merge program changes them, so do not experiment in a valuable working tree without a backup or a way to abort the surrounding merge.

1. Confirm the command and find unmerged paths

Check the installed version and the index state first:

$ git --version
git version 2.43.0
$ git status --short
UU path/to/file.txt
$ git ls-files -u
100644 <original-id> 1	path/to/file.txt
100644 <our-id> 2	path/to/file.txt
100644 <their-id> 3	path/to/file.txt

The UU entry and stage 1, 2 and 3 records mean the index still holds three versions of the path. Swap the example path for one that git ls-files -u actually prints. Nothing printed means there is no unmerged index entry for git merge-index to process.

Checkpoint

Preserve the current state before trying a merge program. If this is an active merge and you want to discard it, the normal recovery command is:

$ git merge --abort

That recovery applies to a merge started by Git's own merge workflow. It is not a universal undo for arbitrary changes made by a custom program, so take a snapshot first.

2. Understand what Git passes to the merge program

The synopsis:

$ git merge-index [-o] [-q] <merge-program> (-a | ([--] <file>...))

For each path needing a merge, Git invokes the named program with seven positional arguments: the original object ID, our object ID, their object ID, the path, and the original, our and their file modes. A missing side is represented by an empty argument. The installed manual describes the object IDs as SHA-1 hashes; treat them as opaque object names in scripts rather than assuming a fixed width.

Write this order down, because it trips people up: the original version is argument 1, our version is argument 2, their version is argument 3. That is not the order every traditional three-way merge tool expects. A program that silently assumes a different order produces a plausible but wrong result.

3. Inspect one invocation without editing the file

Use the installed echo program to see the seven arguments. Apart from the command's normal diagnostics, this step is read-only:

$ git merge-index echo -- path/to/file.txt
<original-id> <our-id> <their-id> path/to/file.txt 100644 100644 100644

The fields print in positional order, so compare them against the contract above. The -- tells git merge-index to stop treating later arguments as options; keep it when a path starts with a hyphen or a generated path list might contain one.

Do not mistake this inspection for conflict resolution. The index stays unmerged until a real merge program writes an appropriate result and updates it.

4. Run Git's supplied one-file merge program

Git 2.43.0 installs git-merge-one-file, whose interface matches the seven arguments above and suits the normal single-file merge workflow:

$ git merge-index git-merge-one-file -a
$ status=$?
$ printf 'git merge-index exit status: %s\n' "$status"
git merge-index exit status: 0

-a selects every path currently needing a merge. The supplied program can update the working tree and index, so this is the state-changing step. Do not run it with sudo: elevated privileges can leave root-owned files in the repository and will not fix a Git index problem.

Verify the result straight away:

$ git status --short
$ git ls-files -u

A successful resolution has no entries from git ls-files -u. If the path still appears, the merge program did not resolve it. Review its output and run git diff before staging or committing anything.

5. Choose how failures are handled

With several files, the default is to stop at the first non-zero status from the merge program, which makes that first failure easy to investigate:

$ git merge-index git-merge-one-file path/to/first.txt path/to/second.txt
fatal: merge program failed

Use -o when you deliberately want every selected path attempted before Git reports the final error status:

$ git merge-index -o git-merge-one-file -a
$ printf 'exit status: %s\n' "$?"
exit status: 1

The command still reports failure overall if any merge failed. Reach for -q only when another program is going to provide the diagnostics: it suppresses complaints about a failed merge program, it does not make the merge succeed.

Checkpoint

After either form, run git status --short and git ls-files -u. Resolve remaining paths manually, restore the pre-command snapshot, or use git merge --abort if the work belongs to an active merge that should be abandoned.

Done means

  • git --version identified the Git release in use.
  • git ls-files -u showed the paths before processing.
  • You verified the seven merge-program arguments before using a state-changing program.
  • The chosen merge program returned success, or its failures are understood.
  • git ls-files -u is empty before you stage and commit the result.