Skip to main content

Merge and Close Semantics

Merge and close are separate operations. A close call never merges, and a merge call never closes without merging.

Merge methods​

MergeMethod has three values:

MergeMethodGitHubGitLabAzure DevOpsGitea
MergemergeMerge commit when the project uses mergenoFastForwarddo = merge when allow_merge_commits
Squashsquashsquash = true, subject to the project squash settingsquashdo = squash when allow_squash_merge
RebaserebaseRejected with VcsUnsupportedOperationExceptionrebasedo = rebase when allow_rebase or allow_rebase_explicit

The provider never changes repository settings. A method that the repository does not allow fails with VcsConflictException or VcsUnsupportedOperationException; it never falls back to another method.

Provider conditions​

  • GitHub. The repository must allow the requested method. Branch protection, required checks, and merge queues can still block the merge. DeleteSourceBranch removes the source Git reference after a successful merge. A fork branch is not deleted.
  • GitLab. The project merge_method and squash settings control the outcome. Rebase is not available in v1 because the provider cannot verify the project settings per call. Failed merges return VcsConflictException.
  • Azure DevOps. Completion reads the pull request and sends its lastMergeSourceCommit. Branch policies, required reviewers, and build validation can block completion. Reviewer votes are separate from completion.
  • Gitea. Repository settings allow_merge_commits, allow_squash_merge, allow_rebase, and allow_rebase_explicit control success. A disabled style, conflict, archived repository, or invalid transition returns VcsConflictException.

Merge a pull request​

using VcsManager;

var merged = await provider.MergePullRequestAsync(
repository,
pullRequest.Number,
new MergePullRequestRequest
{
Method = MergeMethod.Squash,
DeleteSourceBranch = true,
CommitTitle = "Add health endpoint",
CommitMessage = "Squash the feature branch into one commit.",
});

MergePullRequestRequest properties:

PropertyDefaultDescription
MethodMergeMethod.MergeMerge, squash, or rebase.
DeleteSourceBranchfalseDelete the source branch after a successful merge where supported.
CommitTitlenullMerge or squash commit title.
CommitMessagenullMerge or squash commit message.

Merge is not automatically retried. A failed merge can have a side effect on the provider, so retrying it must be a caller decision.

Close a pull request​

ClosePullRequestAsync transitions an open or draft pull request to closed without merging it.

Current stateResult
Open or draftBecomes closed; the updated pull request is returned.
ClosedNo-op; the current pull request is returned.
Merged or completedNo-op; the current pull request is returned unchanged.

Close is idempotent. It does not throw because the pull request is already closed or merged, and it never merges as a side effect.

var closed = await provider.ClosePullRequestAsync(repository, pullRequest.Number);

if (closed.State == PullRequestState.Merged)
{
Console.WriteLine("The pull request was already merged.");
}

State mapping​

PullRequestState values:

ValueMeaning
OpenOpen for review.
DraftOpen but marked as a draft.
MergedMerged or completed.
ClosedClosed without merging.

A merged pull request reports Merged even when the provider uses a closed state internally. Use MergedAt to observe the merge time.