mirror of
https://github.com/stablyai/orca.git
synced 2026-10-19 08:03:13 +00:00
Fall back to a merge when a divergent pull has no reconciliation strateg
- Git 2.27+ refuses `git pull` on divergent branches unless pull.rebase or pull.ff is configured. Retry with `--no-rebase` (Git's historical default) so pulls succeed out of the box on fresh hosts. - Skip the fallback whenever the caller already specified a reconciliation strategy (e.g. --ff-only, --rebase) so explicit policies still fail as expected on divergence. - Applied identically in the local git pull path and the relay/SSH git handler so both surfaces behave the same way.
This commit is contained in:
@@ -20,6 +20,15 @@ const NORMALIZED_SUBMODULE_PUSH_FAILURE_PATTERN =
|
||||
/(?:^|:\s)((?:Submodule '[^'\n]+'|A submodule) (?:has remote changes\. Pull inside the submodule, then try again\.|could not be pushed\. Resolve the submodule push error, then try again\.))(?:$|\s)/i
|
||||
const DIVERGENT_PULL_RECONCILIATION_PATTERN =
|
||||
/Need to specify how to reconcile divergent branches|divergent branches and need to specify how to reconcile them/i
|
||||
// Why: any of these already pin a reconciliation strategy, so the merge
|
||||
// fallback must not override an explicit caller/user choice (e.g. --ff-only).
|
||||
const RECONCILIATION_PULL_ARG_PATTERN =
|
||||
/^(--rebase|--no-rebase|--ff-only|--ff|--no-ff|--merge|-r)(=|$)/
|
||||
// Why: merge is Git's historical pre-2.27 default. Falling back to it lets
|
||||
// divergent pulls reconcile on fresh hosts that never configured pull.rebase
|
||||
// or pull.ff, instead of failing outright. `--no-rebase` predates the 2.25
|
||||
// baseline, so it is safe across all supported Git binaries.
|
||||
export const MERGE_RECONCILIATION_PULL_ARGS = ['--no-rebase']
|
||||
|
||||
export function stripCredentialsFromMessage(message: string): string {
|
||||
return message.replace(USERPASS_URL_PATTERN, '$1').replace(HTTPS_TOKEN_URL_PATTERN, '$1')
|
||||
@@ -81,6 +90,22 @@ function* iterateLinesFromEnd(value: string): Generator<string> {
|
||||
yield value.slice(0, lineEnd)
|
||||
}
|
||||
|
||||
// Why: a fresh host may lack any pull.rebase/pull.ff policy, so Git 2.27+
|
||||
// refuses to reconcile divergent branches. Detect that specific failure so the
|
||||
// caller can retry with an explicit merge instead of surfacing a config error.
|
||||
export function isDivergentPullReconciliationError(error: unknown): boolean {
|
||||
if (!(error instanceof Error)) {
|
||||
return false
|
||||
}
|
||||
return DIVERGENT_PULL_RECONCILIATION_PATTERN.test(stripCredentialsFromMessage(error.message))
|
||||
}
|
||||
|
||||
// Whether the pull already specifies how to reconcile (rebase/merge/ff-only),
|
||||
// in which case the caller's choice must win over the merge fallback.
|
||||
export function pullArgsSpecifyReconciliation(pullArgs: string[]): boolean {
|
||||
return pullArgs.some((arg) => RECONCILIATION_PULL_ARG_PATTERN.test(arg))
|
||||
}
|
||||
|
||||
export type GitRemoteOperation = 'push' | 'pull' | 'fetch' | 'upstream'
|
||||
|
||||
export function normalizeGitErrorMessage(error: unknown, operation?: GitRemoteOperation): string {
|
||||
|
||||
Reference in New Issue
Block a user