mirror of
https://github.com/lukaszraczylo/harness-sync.git
synced 2026-10-12 00:45:22 +00:00
73 lines
1.7 KiB
Go
73 lines
1.7 KiB
Go
// Package merge wraps git merge-file for three-way file merges.
|
|
package merge
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
)
|
|
|
|
// Inputs holds the three versions required for a three-way merge.
|
|
//
|
|
// Base = last-rendered snapshot (state/...)
|
|
// Ours = new rendered output (what we'd write now)
|
|
// Theirs = current target file contents (what's on disk at the destination)
|
|
type Inputs struct {
|
|
Base []byte
|
|
Ours []byte
|
|
Theirs []byte
|
|
}
|
|
|
|
type Result struct {
|
|
Body []byte
|
|
Conflict bool
|
|
}
|
|
|
|
// ThreeWay runs `git merge-file -p ours base theirs` and returns the
|
|
// merged body. When Conflict is true, Body contains conflict markers.
|
|
func ThreeWay(in Inputs) (*Result, error) {
|
|
tmp, err := os.MkdirTemp("", "harness-sync-merge-")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer func() { _ = os.RemoveAll(tmp) }()
|
|
|
|
oursPath := filepath.Join(tmp, "ours")
|
|
basePath := filepath.Join(tmp, "base")
|
|
theirsPath := filepath.Join(tmp, "theirs")
|
|
|
|
if err := os.WriteFile(oursPath, in.Ours, 0o600); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := os.WriteFile(basePath, in.Base, 0o600); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := os.WriteFile(theirsPath, in.Theirs, 0o600); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
cmd := exec.Command(
|
|
"git", "merge-file",
|
|
"-L", "harness-sync (new)",
|
|
"-L", "harness-sync (base)",
|
|
"-L", "harness-sync (current)",
|
|
"-p",
|
|
oursPath, basePath, theirsPath,
|
|
)
|
|
out, runErr := cmd.Output()
|
|
|
|
res := &Result{Body: out}
|
|
if runErr != nil {
|
|
if ee, ok := runErr.(*exec.ExitError); ok {
|
|
// git merge-file exits with conflict-count on conflict; body still valid
|
|
if ee.ExitCode() > 0 {
|
|
res.Conflict = true
|
|
return res, nil
|
|
}
|
|
}
|
|
return nil, fmt.Errorf("git merge-file: %w", runErr)
|
|
}
|
|
return res, nil
|
|
}
|