Implementation:Treeverse LakeFS MergeIntoBranch With Hooks
| Knowledge Sources | |
|---|---|
| Domains | Data_Quality, REST_API |
| Last Updated | 2026-02-08 00:00 GMT |
Overview
Concrete tool for performing merge operations with pre-merge and post-merge hook validation provided by the lakeFS REST API.
Description
This implementation documents the mergeIntoBranch API endpoint in the context of pre-merge and post-merge hook execution. When action hooks with pre-merge or post-merge events are configured on the destination branch, the merge operation triggers hook evaluation as part of its execution.
The merge direction is from a source reference (branch, tag, or commit ID) into a destination branch. Pre-merge hooks defined on the destination branch are evaluated before the merge is finalized. If any pre-merge hook fails, the merge is rejected with HTTP 412 Precondition Failed.
Post-merge hooks fire asynchronously after a successful merge. Their execution status can be queried via the Actions API (listRepositoryRuns).
The merge operation supports three strategies:
- dest-wins -- On conflict, keep the destination branch's version
- source-wins -- On conflict, keep the source reference's version
- default -- Fail on conflict (no automatic resolution)
Usage
Use this API when you need to:
- Promote data from a feature or staging branch to production with automated quality gates
- Merge validated data into a shared branch with pre-merge validation
- Trigger post-merge notifications and downstream pipeline execution
- Handle merge conflicts with explicit resolution strategies
Code Reference
Source Location
- Repository: lakeFS
- File:
api/swagger.yml(lines 4678-4742) - Hook integration:
esti/hooks.go(lines 183, 302)
Signature
# API Endpoint
POST /api/v1/repositories/{repository}/refs/{sourceRef}/merge/{destinationBranch}
# Operation ID
operationId: mergeIntoBranch
# Content Type
Content-Type: application/json
# Path Parameters
repository: string # Repository name
sourceRef: string # Source reference (branch, tag, or commit ID)
destinationBranch: string # Target branch for the merge
# Request Body: Merge
Merge:
message: string # Optional merge commit message
metadata: # Optional key-value metadata
key1: value1
key2: value2
strategy: string # Optional: "dest-wins", "source-wins", or default (fail on conflict)
force: boolean # Optional: force merge (default: false)
# Response 200: MergeResult
MergeResult:
reference: string # Resulting merge commit reference
summary:
added: integer # Number of objects added
removed: integer # Number of objects removed
changed: integer # Number of objects changed
conflict: integer # Number of conflicts (0 if resolved)
# Response 412: Precondition Failed (hook rejection)
Error:
message: string # Hook failure description
Import
import requests
# or
import lakefs_sdk
from lakefs_sdk.api import refs_api
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
repository |
string (path) | Yes | Name of the repository |
sourceRef |
string (path) | Yes | Source reference to merge from (branch name, tag, or commit ID) |
destinationBranch |
string (path) | Yes | Target branch to merge into |
message |
string (body) | No | Merge commit message (auto-generated if omitted) |
metadata |
map[string]string (body) | No | Key-value pairs attached to the merge commit |
strategy |
string (body) | No | Conflict resolution strategy: dest-wins, source-wins, or omit for default (fail on conflict)
|
force |
boolean (body) | No | Force merge even if branches have diverged (default: false) |
Outputs
| Name | Type | Description |
|---|---|---|
MergeResult (HTTP 200) |
object | Successful merge with reference ID and summary of changes (added, removed, changed, conflicts) |
| HTTP 400 | error | Bad request (e.g., invalid source reference) |
| HTTP 401 | error | Unauthorized (missing or invalid credentials) |
| HTTP 404 | error | Repository, source reference, or destination branch not found |
| HTTP 409 | error | Conflict (merge conflicts exist and no resolution strategy specified) |
| HTTP 412 | error | Precondition Failed -- a pre-merge hook rejected the merge |
Usage Examples
Merge Feature Branch to Main With Hook Validation
# Merge feature-ingest into main -- pre-merge hooks will execute automatically
curl -X POST \
"https://lakefs.example.com/api/v1/repositories/my-repo/refs/feature-ingest/merge/main" \
-H "Authorization: Basic $(echo -n 'AKIAIOSFODNN7EXAMPLE:wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY' | base64)" \
-H "Content-Type: application/json" \
-d '{
"message": "Promote validated sales data to production",
"metadata": {
"approved_by": "data-quality-team",
"ticket": "DATA-1234"
}
}'
# On success (HTTP 200): merge completed, post-merge hooks fire asynchronously
# On hook failure (HTTP 412): merge rejected, response contains failure details
# On conflict (HTTP 409): merge conflicts detected, specify strategy or resolve manually
Merge With Conflict Resolution Strategy
# Merge with source-wins strategy to override destination on conflicts
curl -X POST \
"https://lakefs.example.com/api/v1/repositories/my-repo/refs/feature-ingest/merge/main" \
-H "Authorization: Basic $(echo -n 'AKIAIOSFODNN7EXAMPLE:wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY' | base64)" \
-H "Content-Type: application/json" \
-d '{
"message": "Promote with source-wins conflict resolution",
"strategy": "source-wins"
}'
Handling Hook Rejection and Inspecting Results in Python
import lakefs_sdk
from lakefs_sdk.api import refs_api, actions_api
from lakefs_sdk.model.merge import Merge
from lakefs_sdk.exceptions import ApiException
configuration = lakefs_sdk.Configuration(
host="https://lakefs.example.com/api/v1",
username="AKIAIOSFODNN7EXAMPLE",
password="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
)
with lakefs_sdk.ApiClient(configuration) as api_client:
refs = refs_api.RefsApi(api_client)
actions = actions_api.ActionsApi(api_client)
try:
result = refs.merge_into_branch(
repository="my-repo",
source_ref="feature-ingest",
destination_branch="main",
merge=Merge(
message="Promote validated sales data to production",
metadata={
"approved_by": "data-quality-team",
"ticket": "DATA-1234"
}
)
)
print(f"Merge successful: {result.reference}")
print(f" Added: {result.summary.added}")
print(f" Changed: {result.summary.changed}")
print(f" Removed: {result.summary.removed}")
except ApiException as e:
if e.status == 412:
print(f"Pre-merge hook rejected the merge: {e.body}")
# Inspect hook results to find which hook failed
runs = actions.list_repository_runs(
repository="my-repo",
branch="main"
)
for run in runs.results:
if run.status == "failed":
hooks = actions.list_run_hooks(
repository="my-repo",
run_id=run.run_id
)
for hook in hooks.results:
if hook.status == "failed":
print(f" Failed hook: {hook.action}/{hook.hook_id}")
elif e.status == 409:
print(f"Merge conflict detected: {e.body}")
else:
raise