Auto-reconcile subrepo history when josh filter changes
When the exclude list changes, josh-proxy recomputes filtered history with new SHAs, breaking common ancestry with the subrepo. Instead of requiring a manual reset (force-push), forward sync now detects the filter change and creates a reconciliation merge commit that connects the old and new histories — no force-push, no re-clone needed. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
79
lib/sync.sh
79
lib/sync.sh
@@ -128,6 +128,85 @@ ${BOT_TRAILER}: forward/${mono_branch}/$(date -u +%Y-%m-%dT%H:%M:%SZ)" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
# ─── Filter Change Reconciliation ─────────────────────────────────
|
||||
# When the josh filter changes (e.g., exclude patterns added/removed),
|
||||
# josh-proxy recomputes filtered history with new SHAs. This creates a
|
||||
# merge commit on the subrepo that connects old and new histories,
|
||||
# re-establishing shared ancestry without a destructive force-push.
|
||||
# Returns: reconciled | lease-rejected
|
||||
|
||||
reconcile_filter_change() {
|
||||
local mono_branch="$SYNC_BRANCH_MONO"
|
||||
local subrepo_branch="$SYNC_BRANCH_SUBREPO"
|
||||
local work_dir
|
||||
work_dir=$(mktemp -d)
|
||||
# shellcheck disable=SC2064 # Intentional early expansion — work_dir is local
|
||||
trap "rm -rf '$work_dir'" EXIT
|
||||
|
||||
log "INFO" "=== Filter change reconciliation: ${mono_branch} ==="
|
||||
|
||||
# 1. Clone subrepo
|
||||
git clone "$(subrepo_auth_url)" \
|
||||
--branch "$subrepo_branch" --single-branch \
|
||||
"${work_dir}/subrepo" || die "Failed to clone subrepo"
|
||||
|
||||
cd "${work_dir}/subrepo" || exit
|
||||
git config user.name "$BOT_NAME"
|
||||
git config user.email "$BOT_EMAIL"
|
||||
|
||||
local subrepo_head
|
||||
subrepo_head=$(git rev-parse HEAD)
|
||||
log "INFO" "Subrepo HEAD: ${subrepo_head:0:12}"
|
||||
|
||||
# 2. Fetch josh-proxy filtered view (new filter)
|
||||
git remote add josh-filtered "$(josh_auth_url)"
|
||||
git fetch josh-filtered "$mono_branch" || die "Failed to fetch from josh-proxy"
|
||||
|
||||
local josh_head josh_tree
|
||||
josh_head=$(git rev-parse "josh-filtered/${mono_branch}")
|
||||
# shellcheck disable=SC1083 # {tree} is git syntax, not shell brace expansion
|
||||
josh_tree=$(git rev-parse "josh-filtered/${mono_branch}^{tree}")
|
||||
log "INFO" "Josh-proxy HEAD (new filter): ${josh_head:0:12}"
|
||||
|
||||
# 3. Check if trees are already identical (filter change had no effect)
|
||||
local subrepo_tree
|
||||
# shellcheck disable=SC1083
|
||||
subrepo_tree=$(git rev-parse "HEAD^{tree}")
|
||||
if [ "$josh_tree" = "$subrepo_tree" ]; then
|
||||
log "INFO" "Trees identical after filter change — no reconciliation needed"
|
||||
echo "skip"
|
||||
return
|
||||
fi
|
||||
|
||||
# 4. Create merge commit: subrepo HEAD + josh-proxy HEAD, with josh-proxy's tree
|
||||
local merge_commit
|
||||
merge_commit=$(git commit-tree "$josh_tree" \
|
||||
-p "$subrepo_head" \
|
||||
-p "$josh_head" \
|
||||
-m "Sync: filter configuration updated
|
||||
|
||||
${BOT_TRAILER}: filter-change/${mono_branch}/$(date -u +%Y-%m-%dT%H:%M:%SZ)")
|
||||
|
||||
git reset --hard "$merge_commit" >&2
|
||||
log "INFO" "Created reconciliation merge: ${merge_commit:0:12}"
|
||||
|
||||
# 5. Record lease and push
|
||||
local subrepo_sha
|
||||
subrepo_sha=$(subrepo_ls_remote "$subrepo_branch")
|
||||
|
||||
if git push \
|
||||
--force-with-lease="refs/heads/${subrepo_branch}:${subrepo_sha}" \
|
||||
"$(subrepo_auth_url)" \
|
||||
"HEAD:refs/heads/${subrepo_branch}"; then
|
||||
|
||||
log "INFO" "Filter change reconciled — shared ancestry re-established"
|
||||
echo "reconciled"
|
||||
else
|
||||
log "WARN" "Force-with-lease rejected — subrepo changed during reconciliation"
|
||||
echo "lease-rejected"
|
||||
fi
|
||||
}
|
||||
|
||||
# ─── Reverse Sync: Subrepo → Monorepo ──────────────────────────────
|
||||
#
|
||||
# Always creates a PR on the monorepo — never pushes directly.
|
||||
|
||||
Reference in New Issue
Block a user