Document git-wrapper for ifcmerge: Forgejo uses git merge-file not merge-tree

This commit is contained in:
Bruno Postle 2026-05-17 23:37:14 +01:00
parent 0e855d8413
commit b23b210f76
2 changed files with 92 additions and 16 deletions

View file

@ -268,21 +268,32 @@ automatically merge IFC pull requests instead of marking them as conflicted.
### How Forgejo checks mergeability ### How Forgejo checks mergeability
Forgejo (with git ≥ 2.38) uses `git merge-tree --write-tree` to perform a Forgejo checks PR mergeability by calling `git merge-file current base other`
trial merge in the bare repository. This command **does** invoke configured directly for each conflicting file. This command bypasses gitattributes merge
merge drivers — confirmed by testing. With ifcmerge set up correctly, drivers entirely — `/etc/gitconfig` and `core.attributesFile` have no effect
the "can be automatically merged" indicator on a PR reflects ifcmerge's on this code path.
actual result, not a naive text-conflict check.
**Important:** bare repositories do not read committed `.gitattributes` files The solution is a **git wrapper** at `/usr/bin/git` (with the original binary
from the tree. The merge driver must be declared via a system-wide moved to `/usr/bin/git.real`) that intercepts `merge-file` calls, detects IFC
`core.attributesFile` setting in `/etc/gitconfig`. files by their ISO-10303 STEP header, and delegates to `ifcmerge` instead.
The `/etc/gitconfig` merge driver registration and `/etc/gitattributes` are
still useful for client-side `git merge` operations on developer machines, but
they do not affect Forgejo's server-side conflict check.
**Important:** the git package in apt will overwrite `/usr/bin/git` on upgrade.
Reinstall the wrapper (`server-config/git-wrapper`) after any git package upgrade.
### Prerequisites ### Prerequisites
`ifcmerge` is a single Perl script from `ifcmerge` is a Perl script — install Perl's DateTime module first:
[github.com/brunopostle/ifcmerge](https://github.com/brunopostle/ifcmerge).
Download and install it on the Forgejo server: ```bash
apt install -y libdatetime-perl
```
Then download ifcmerge from
[github.com/brunopostle/ifcmerge](https://github.com/brunopostle/ifcmerge):
```bash ```bash
curl -o /usr/local/bin/ifcmerge \ curl -o /usr/local/bin/ifcmerge \
@ -290,19 +301,24 @@ curl -o /usr/local/bin/ifcmerge \
chmod +x /usr/local/bin/ifcmerge chmod +x /usr/local/bin/ifcmerge
``` ```
Verify it is on `PATH` for the `forgejo` system user: ### Install the git wrapper
The git wrapper intercepts `git merge-file` for IFC files and routes them to
ifcmerge. Install it by replacing the git binary:
```bash ```bash
sudo -u forgejo which ifcmerge mv /usr/bin/git /usr/bin/git.real
cp forgejo/server-config/git-wrapper /usr/bin/git
chmod +x /usr/bin/git
``` ```
### Deploy the config files ### Deploy the config files (for client-side merges)
```bash ```bash
# System-wide gitattributes (the critical piece for bare repos) # System-wide gitattributes
sudo cp forgejo/server-config/gitattributes /etc/gitattributes sudo cp forgejo/server-config/gitattributes /etc/gitattributes
# Append merge driver registration + core.attributesFile to /etc/gitconfig # Merge driver registration in /etc/gitconfig
sudo git config --system include.path /path/to/ifcurl/forgejo/server-config/gitconfig-ifcmerge sudo git config --system include.path /path/to/ifcurl/forgejo/server-config/gitconfig-ifcmerge
``` ```

View file

@ -0,0 +1,60 @@
#!/bin/bash
# Drop this at /usr/bin/git (move original to /usr/bin/git.real).
#
# Forgejo checks PR mergeability by calling 'git merge-file current base other'
# directly. This bypasses gitattributes merge drivers entirely — there is no
# way to configure ifcmerge via /etc/gitconfig for this code path.
#
# This wrapper intercepts 'git merge-file' calls where the file being merged
# is an IFC/STEP file (identified by the ISO-10303 header) and delegates to
# ifcmerge instead of git's built-in text merge.
#
# Installation:
# mv /usr/bin/git /usr/bin/git.real
# cp git-wrapper /usr/bin/git
# chmod +x /usr/bin/git
#
# The wrapper is transparent for all other git commands.
#
# NOTE: apt upgrades to the git package will overwrite /usr/bin/git.
# After any git package upgrade, reinstall this wrapper.
is_merge_file=false
for arg in "$@"; do
[ "$arg" = "merge-file" ] && is_merge_file=true && break
done
if $is_merge_file; then
files=()
past_subcommand=false
skip_next=false
for arg in "$@"; do
if ! $past_subcommand; then
[ "$arg" = "merge-file" ] && past_subcommand=true
continue
fi
if $skip_next; then skip_next=false; continue; fi
case "$arg" in
-L|--marker-size) skip_next=true ;;
-p|-q|--quiet|--ours|--theirs|--union|--diff3|--zdiff3) ;;
--) ;;
-*) ;;
*) files+=("$arg") ;;
esac
done
if [ ${#files[@]} -eq 3 ]; then
current="${files[0]}"
base="${files[1]}"
other="${files[2]}"
if [ -f "$current" ] && head -c 20 "$current" 2>/dev/null | grep -q "ISO-10303"; then
dir=$(dirname "$current")
[[ "$base" != /* ]] && base="$dir/$base"
[[ "$other" != /* ]] && other="$dir/$other"
ifcmerge --prioritise-local "$base" "$current" "$other" "$current"
exit $?
fi
fi
fi
exec /usr/bin/git.real "$@"