diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index c4ad714717..b1c3247315 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -1568,14 +1568,7 @@ pulls.squash_merge_pull_request = Create squash commit
 pulls.merge_manually = Manually merged
 pulls.merge_commit_id = The merge commit ID
 pulls.require_signed_wont_sign = The branch requires signed commits but this merge will not be signed
-pulls.merge_pull_request_now = Merge Pull Request Now
-pulls.rebase_merge_pull_request_now = Rebase and Merge Now
-pulls.rebase_merge_commit_pull_request_now = Rebase and Merge Now (--no-ff)
-pulls.squash_merge_pull_request_now = Squash and Merge Now
-pulls.merge_pull_request_on_status_success = Merge Pull Request When All Checks Succeed
-pulls.rebase_merge_pull_request_on_status_success = Rebase and Merge When All Checks Succeed
-pulls.rebase_merge_commit_pull_request_on_status_success = Rebase and Merge (--no-ff) When All Checks Succeed
-pulls.squash_merge_pull_request_on_status_success = Squash and Merge When All Checks Succeed
+
 pulls.invalid_merge_option = You cannot use this merge option for this pull request.
 pulls.merge_conflict = Merge Failed: There was a conflict whilst merging. Hint: Try a different strategy
 pulls.merge_conflict_summary = Error Message
@@ -1606,14 +1599,18 @@ pulls.reopened_at = `reopened this pull request <a id="%[1]s" href="#%[1]s">%[2]
 pulls.merge_instruction_hint = `You can also view <a class="show-instruction">command line instructions</a>.`
 pulls.merge_instruction_step1_desc = From your project repository, check out a new branch and test the changes.
 pulls.merge_instruction_step2_desc = Merge the changes and update on Gitea.
-pulls.merge_on_status_success = The pull request was scheduled to merge when all checks succeed.
-pulls.merge_on_status_success_already_scheduled = This pull request is already scheduled to merge when all checks succeed.
-pulls.pr_has_pending_merge_on_success = %[1]s scheduled this pull request to auto merge when all checks succeed %[2]s.
-pulls.merge_pull_on_success_cancel = Cancel auto merge
-pulls.pull_request_not_scheduled = This pull request is not scheduled to auto merge.
-pulls.pull_request_schedule_canceled = The auto merge was canceled for this pull request.
-pulls.pull_request_scheduled_auto_merge = `scheduled this pull request to auto merge when all checks succeed %[1]s`
-pulls.pull_request_canceled_scheduled_auto_merge = `canceled auto merging this pull request when all checks succeed %[1]s`
+
+pulls.auto_merge_button_when_succeed = (When checks succeed)
+pulls.auto_merge_when_succeed = Auto merge when all checks succeed
+pulls.auto_merge_newly_scheduled = The pull request was scheduled to merge when all checks succeed.
+pulls.auto_merge_has_pending_schedule = %[1]s scheduled this pull request to auto merge when all checks succeed %[2]s.
+
+pulls.auto_merge_cancel_schedule = Cancel auto merge
+pulls.auto_merge_not_scheduled = This pull request is not scheduled to auto merge.
+pulls.auto_merge_canceled_schedule = The auto merge was canceled for this pull request.
+
+pulls.auto_merge_newly_scheduled_comment = `scheduled this pull request to auto merge when all checks succeed %[1]s`
+pulls.auto_merge_canceled_schedule_comment = `canceled auto merging this pull request when all checks succeed %[1]s`
 
 milestones.new = New Milestone
 milestones.open_tab = %d Open
diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go
index 8df4ccc607..d698f1c49a 100644
--- a/routers/web/repo/pull.go
+++ b/routers/web/repo/pull.go
@@ -20,6 +20,7 @@ import (
 	"code.gitea.io/gitea/models/db"
 	"code.gitea.io/gitea/models/organization"
 	access_model "code.gitea.io/gitea/models/perm/access"
+	pull_model "code.gitea.io/gitea/models/pull"
 	repo_model "code.gitea.io/gitea/models/repo"
 	"code.gitea.io/gitea/models/unit"
 	user_model "code.gitea.io/gitea/models/user"
@@ -36,6 +37,7 @@ import (
 	"code.gitea.io/gitea/modules/web/middleware"
 	"code.gitea.io/gitea/routers/utils"
 	asymkey_service "code.gitea.io/gitea/services/asymkey"
+	"code.gitea.io/gitea/services/automerge"
 	"code.gitea.io/gitea/services/forms"
 	"code.gitea.io/gitea/services/gitdiff"
 	pull_service "code.gitea.io/gitea/services/pull"
@@ -966,6 +968,22 @@ func MergePullRequest(ctx *context.Context) {
 		message += "\n\n" + form.MergeMessageField
 	}
 
+	if form.MergeWhenChecksSucceed {
+		// delete all scheduled auto merges
+		_ = pull_model.DeleteScheduledAutoMerge(ctx, pr.ID)
+		// schedule auto merge
+		scheduled, err := automerge.ScheduleAutoMerge(ctx, ctx.Doer, pr, repo_model.MergeStyle(form.Do), message)
+		if err != nil {
+			ctx.ServerError("ScheduleAutoMerge", err)
+			return
+		} else if scheduled {
+			// nothing more to do ...
+			ctx.Flash.Success(ctx.Tr("repo.pulls.auto_merge_newly_scheduled"))
+			ctx.Redirect(fmt.Sprintf("%s/pulls/%d", ctx.Repo.RepoLink, pr.Index))
+			return
+		}
+	}
+
 	if err := pull_service.Merge(ctx, pr, ctx.Doer, ctx.Repo.GitRepo, repo_model.MergeStyle(form.Do), form.HeadCommitID, message); err != nil {
 		if models.IsErrInvalidMergeStyle(err) {
 			ctx.Flash.Error(ctx.Tr("repo.pulls.invalid_merge_option"))
@@ -1070,6 +1088,26 @@ func MergePullRequest(ctx *context.Context) {
 	ctx.Redirect(issue.Link())
 }
 
+// CancelAutoMergePullRequest cancels a scheduled pr
+func CancelAutoMergePullRequest(ctx *context.Context) {
+	issue := checkPullInfo(ctx)
+	if ctx.Written() {
+		return
+	}
+
+	if err := automerge.RemoveScheduledAutoMerge(ctx, ctx.Doer, issue.PullRequest); err != nil {
+		if db.IsErrNotExist(err) {
+			ctx.Flash.Error(ctx.Tr("repo.pulls.auto_merge_not_scheduled"))
+			ctx.Redirect(fmt.Sprintf("%s/pulls/%d", ctx.Repo.RepoLink, issue.Index))
+			return
+		}
+		ctx.ServerError("RemoveScheduledAutoMerge", err)
+		return
+	}
+	ctx.Flash.Success(ctx.Tr("repo.pulls.auto_merge_canceled_schedule"))
+	ctx.Redirect(fmt.Sprintf("%s/pulls/%d", ctx.Repo.RepoLink, issue.Index))
+}
+
 func stopTimerIfAvailable(user *user_model.User, issue *models.Issue) error {
 	if models.StopwatchExists(user.ID, issue.ID) {
 		if err := models.CreateOrStopIssueStopwatch(user, issue); err != nil {
diff --git a/routers/web/web.go b/routers/web/web.go
index bf4c4662af..88a446d067 100644
--- a/routers/web/web.go
+++ b/routers/web/web.go
@@ -1127,6 +1127,7 @@ func RegisterRoutes(m *web.Route) {
 			m.Get(".patch", repo.DownloadPullPatch)
 			m.Get("/commits", context.RepoRef(), repo.ViewPullCommits)
 			m.Post("/merge", context.RepoMustNotBeArchived(), bindIgnErr(forms.MergePullRequestForm{}), repo.MergePullRequest)
+			m.Post("/cancel_auto_merge", context.RepoMustNotBeArchived(), repo.CancelAutoMergePullRequest)
 			m.Post("/update", repo.UpdatePullRequest)
 			m.Post("/set_allow_maintainer_edit", bindIgnErr(forms.UpdateAllowEditsForm{}), repo.SetAllowEdits)
 			m.Post("/cleanup", context.RepoMustNotBeArchived(), context.RepoRef(), repo.CleanUpPullRequest)
diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl
index 235f4c8fc2..0258a9f969 100644
--- a/templates/repo/issue/view_content/comments.tmpl
+++ b/templates/repo/issue/view_content/comments.tmpl
@@ -843,8 +843,8 @@
 				<span class="badge">{{svg "octicon-git-merge" 16}}</span>
 				<span class="text grey">
 					<a class="author" href="{{.Poster.HomeLink}}">{{.Poster.GetDisplayName}}</a>
-					{{if eq .Type 34}}{{$.i18n.Tr "repo.pulls.pull_request_scheduled_auto_merge" $createdStr | Safe}}
-					{{else}}{{$.i18n.Tr "repo.pulls.pull_request_canceled_scheduled_auto_merge" $createdStr | Safe}}{{end}}
+					{{if eq .Type 34}}{{$.i18n.Tr "repo.pulls.auto_merge_newly_scheduled_comment" $createdStr | Safe}}
+					{{else}}{{$.i18n.Tr "repo.pulls.auto_merge_canceled_schedule_comment" $createdStr | Safe}}{{end}}
 				</span>
 			</div>
 		{{end}}
diff --git a/templates/repo/issue/view_content/pull.tmpl b/templates/repo/issue/view_content/pull.tmpl
index c764138fa0..d2282f07f6 100644
--- a/templates/repo/issue/view_content/pull.tmpl
+++ b/templates/repo/issue/view_content/pull.tmpl
@@ -251,8 +251,14 @@
 						{{$.i18n.Tr (printf "repo.signing.wont_sign.%s" .WontSignReason) }}
 					</div>
 				{{end}}
+
 				{{$notAllOverridableChecksOk := or .IsBlockedByApprovals .IsBlockedByRejection .IsBlockedByOfficialReviewRequests .IsBlockedByOutdatedBranch .IsBlockedByChangedProtectedFiles (and .EnableStatusCheck (not .RequiredStatusCheckState.IsSuccess))}}
-				{{if and (or $.IsRepoAdmin (not $notAllOverridableChecksOk)) (or (not .AllowMerge) (not .RequireSigned) .WillSign)}}
+
+				{{/* admin can merge without checks, writer can merge when checkes succeed */}}
+				{{$canMergeNow := and (or $.IsRepoAdmin (not $notAllOverridableChecksOk)) (or (not .AllowMerge) (not .RequireSigned) .WillSign)}}
+				{{/* admin and writer both can make an auto merge schedule */}}
+
+				{{if $canMergeNow}}
 					{{if $notAllOverridableChecksOk}}
 						<div class="item">
 							<i class="icon icon-octicon">{{svg "octicon-dot-fill"}}</i>
@@ -277,7 +283,6 @@
 					{{end}}
 				{{end}}
 
-				{{$canAutoMerge = true}}
 				{{if (gt .Issue.PullRequest.CommitsBehind 0)}}
 					<div class="ui divider"></div>
 					<div class="item item-section">
@@ -317,112 +322,111 @@
 					</div>
 				{{end}}
 
-				{{if and (or $.IsRepoAdmin (not $notAllOverridableChecksOk)) (or (not .AllowMerge) (not .RequireSigned) .WillSign)}}
-					{{if .AllowMerge}}
-						{{$prUnit := .Repository.MustGetUnit $.UnitTypePullRequests}}
-						{{$approvers := .Issue.PullRequest.GetApprovers}}
-						{{if or $prUnit.PullRequestsConfig.AllowMerge $prUnit.PullRequestsConfig.AllowRebase $prUnit.PullRequestsConfig.AllowRebaseMerge $prUnit.PullRequestsConfig.AllowSquash}}
+				{{if .AllowMerge}} {{/* user is allowed to merge */}}
+					{{$prUnit := .Repository.MustGetUnit $.UnitTypePullRequests}}
+					{{$approvers := .Issue.PullRequest.GetApprovers}}
+					{{if or $prUnit.PullRequestsConfig.AllowMerge $prUnit.PullRequestsConfig.AllowRebase $prUnit.PullRequestsConfig.AllowRebaseMerge $prUnit.PullRequestsConfig.AllowSquash}}
+						{{$hasPendingPullRequestMergeTip := ""}}
+						{{if .HasPendingPullRequestMerge}}
+							{{$createdPRMergeStr := TimeSinceUnix .PendingPullRequestMerge.CreatedUnix $.i18n.Lang}}
+							{{$hasPendingPullRequestMergeTip = $.i18n.Tr "repo.pulls.auto_merge_has_pending_schedule" .PendingPullRequestMerge.Doer.Name $createdPRMergeStr}}
+						{{end}}
+						<div class="ui divider"></div>
+						<script>
+							<!-- /* eslint-disable */ -->
+							(() => {
+								const defaultMergeTitle = {{.DefaultMergeMessage}};
+								const defaultSquashMergeTitle = {{.DefaultSquashMergeMessage}};
+								const defaultMergeMessage = 'Reviewed-on: ' + {{$.Issue.HTMLURL}} + '\n' + {{$approvers}};
+								const mergeForm = {
+									'baseLink': {{.Link}},
+									'textCancel': {{$.i18n.Tr "cancel"}},
+									'textDeleteBranch': {{$.i18n.Tr "repo.branch.delete" .HeadTarget}},
+									'textAutoMergeButtonWhenSucceed': {{$.i18n.Tr "repo.pulls.auto_merge_button_when_succeed"}},
+									'textAutoMergeWhenSucceed': {{$.i18n.Tr "repo.pulls.auto_merge_when_succeed"}},
+									'textAutoMergeCancelSchedule': {{$.i18n.Tr "repo.pulls.auto_merge_cancel_schedule"}},
 
-							<div class="ui divider"></div>
+									'canMergeNow': {{$canMergeNow}},
+									'allOverridableChecksOk': {{not $notAllOverridableChecksOk}},
+									'pullHeadCommitID': {{.PullHeadCommitID}},
+									'isPullBranchDeletable': {{.IsPullBranchDeletable}},
+									'defaultDeleteBranchAfterMerge': {{$prUnit.PullRequestsConfig.DefaultDeleteBranchAfterMerge}},
+									'mergeMessageFieldPlaceHolder': {{$.i18n.Tr "repo.editor.commit_message_desc"}},
 
-							<script>
-								<!-- /* eslint-disable */ -->
-								(() => {
-									const defaultMergeTitle = {{.DefaultMergeMessage}};
-									const defaultSquashMergeTitle = {{.DefaultSquashMergeMessage}};
-									const defaultMergeMessage = 'Reviewed-on: ' + {{$.Issue.HTMLURL}} + '\n' + {{$approvers}};
-									const mergeForm = {
-										'baseLink': {{.Link}},
-										'textCancel': {{$.i18n.Tr "cancel"}},
-										'textDeleteBranch': {{$.i18n.Tr "repo.branch.delete" .HeadTarget}},
+									'hasPendingPullRequestMerge': {{.HasPendingPullRequestMerge}},
+									'hasPendingPullRequestMergeTip': {{$hasPendingPullRequestMergeTip}},
+								};
 
-										'allOverridableChecksOk': {{not $notAllOverridableChecksOk}},
-										'pullHeadCommitID': {{.PullHeadCommitID}},
-										'isPullBranchDeletable': {{.IsPullBranchDeletable}},
-										'defaultDeleteBranchAfterMerge': {{$prUnit.PullRequestsConfig.DefaultDeleteBranchAfterMerge}},
-										'mergeMessageFieldPlaceHolder': {{$.i18n.Tr "repo.editor.commit_message_desc"}},
-									};
-									mergeForm['mergeStyles'] = [
-										{
-											'name': 'merge',
-											'allowed': {{$prUnit.PullRequestsConfig.AllowMerge}},
-											'textDoMerge': {{$.i18n.Tr "repo.pulls.merge_pull_request"}},
-											'mergeTitleFieldText': defaultMergeTitle,
-											'mergeMessageFieldText': defaultMergeMessage,
-										},
-										{
-											'name': 'rebase',
-											'allowed': {{$prUnit.PullRequestsConfig.AllowRebase}},
-											'textDoMerge': {{$.i18n.Tr "repo.pulls.rebase_merge_pull_request"}},
-											'hideMergeMessageTexts': true,
-										},
-										{
-											'name': 'rebase-merge',
-											'allowed': {{$prUnit.PullRequestsConfig.AllowRebaseMerge}},
-											'textDoMerge': {{$.i18n.Tr "repo.pulls.rebase_merge_commit_pull_request"}},
-											'mergeTitleFieldText': defaultMergeTitle,
-											'mergeMessageFieldText': defaultMergeMessage,
-										},
-										{
-											'name': 'squash',
-											'allowed': {{$prUnit.PullRequestsConfig.AllowSquash}},
-											'textDoMerge': {{$.i18n.Tr "repo.pulls.squash_merge_pull_request"}},
-											'mergeTitleFieldText': defaultSquashMergeTitle,
-											'mergeMessageFieldText': defaultMergeMessage,
-										},
-										{
-											'name': 'manually-merged',
-											'allowed': {{and $prUnit.PullRequestsConfig.AllowManualMerge $.IsRepoAdmin}},
-											'textDoMerge': {{$.i18n.Tr "repo.pulls.merge_manually"}},
-											'hideMergeMessageTexts': true,
-										}
-									];
-									window.config.pageData.pullRequestMergeForm = mergeForm;
-								})();
-							</script>
+								const generalHideAutoMerge = mergeForm.canMergeNow && mergeForm.allOverridableChecksOk; // if this PR can be merged now, then hide the auto merge
+								mergeForm['mergeStyles'] = [
+									{
+										'name': 'merge',
+										'allowed': {{$prUnit.PullRequestsConfig.AllowMerge}},
+										'textDoMerge': {{$.i18n.Tr "repo.pulls.merge_pull_request"}},
+										'mergeTitleFieldText': defaultMergeTitle,
+										'mergeMessageFieldText': defaultMergeMessage,
+										'hideAutoMerge': generalHideAutoMerge,
+									},
+									{
+										'name': 'rebase',
+										'allowed': {{$prUnit.PullRequestsConfig.AllowRebase}},
+										'textDoMerge': {{$.i18n.Tr "repo.pulls.rebase_merge_pull_request"}},
+										'hideMergeMessageTexts': true,
+										'hideAutoMerge': generalHideAutoMerge,
+									},
+									{
+										'name': 'rebase-merge',
+										'allowed': {{$prUnit.PullRequestsConfig.AllowRebaseMerge}},
+										'textDoMerge': {{$.i18n.Tr "repo.pulls.rebase_merge_commit_pull_request"}},
+										'mergeTitleFieldText': defaultMergeTitle,
+										'mergeMessageFieldText': defaultMergeMessage,
+										'hideAutoMerge': generalHideAutoMerge,
+									},
+									{
+										'name': 'squash',
+										'allowed': {{$prUnit.PullRequestsConfig.AllowSquash}},
+										'textDoMerge': {{$.i18n.Tr "repo.pulls.squash_merge_pull_request"}},
+										'mergeTitleFieldText': defaultSquashMergeTitle,
+										'mergeMessageFieldText': defaultMergeMessage,
+										'hideAutoMerge': generalHideAutoMerge,
+									},
+									{
+										'name': 'manually-merged',
+										'allowed': {{and $prUnit.PullRequestsConfig.AllowManualMerge $.IsRepoAdmin}},
+										'textDoMerge': {{$.i18n.Tr "repo.pulls.merge_manually"}},
+										'hideMergeMessageTexts': true,
+										'hideAutoMerge': true,
+									}
+								];
+								window.config.pageData.pullRequestMergeForm = mergeForm;
+							})();
+						</script>
 
-							<div id="pull-request-merge-form"></div>
+						<div id="pull-request-merge-form"></div>
 
-							{{if .ShowMergeInstructions}}
-								<div class="instruct-toggle mt-3"> {{$.i18n.Tr "repo.pulls.merge_instruction_hint" | Safe}} </div>
-								<div class="instruct-content" style="display:none">
-									<div class="ui divider"></div>
-									<div><h3 class="di">{{$.i18n.Tr "step1"}} </h3>{{$.i18n.Tr "repo.pulls.merge_instruction_step1_desc"}}</div>
-									<div class="ui secondary segment">
-										{{if eq .Issue.PullRequest.Flow 0}}
-											<div>git checkout -b {{if ne .Issue.PullRequest.HeadRepo.ID .Issue.PullRequest.BaseRepo.ID}}{{.Issue.PullRequest.HeadRepo.OwnerName}}-{{end}}{{.Issue.PullRequest.HeadBranch}} {{.Issue.PullRequest.BaseBranch}}</div>
-											<div>git pull {{if ne .Issue.PullRequest.HeadRepo.ID .Issue.PullRequest.BaseRepo.ID}}{{.Issue.PullRequest.HeadRepo.HTMLURL}}{{else}}origin{{end}} {{.Issue.PullRequest.HeadBranch}}</div>
-										{{else}}
-											<div>git fetch origin {{.Issue.PullRequest.GetGitRefName}}:{{.Issue.PullRequest.HeadBranch}}</div>
-										{{end}}
-									</div>
-									<div><h3 class="di">{{$.i18n.Tr "step2"}} </h3>{{$.i18n.Tr "repo.pulls.merge_instruction_step2_desc"}}</div>
-									<div class="ui secondary segment">
-										<div>git checkout {{.Issue.PullRequest.BaseBranch}}</div>
-										<div>git merge --no-ff {{if ne .Issue.PullRequest.HeadRepo.ID .Issue.PullRequest.BaseRepo.ID}}{{.Issue.PullRequest.HeadRepo.OwnerName}}-{{end}}{{.Issue.PullRequest.HeadBranch}}</div>
-										<div>git push origin {{.Issue.PullRequest.BaseBranch}}</div>
-									</div>
-								</div>
-							{{end}}
-						{{else}}
-							<div class="ui divider"></div>
-							<div class="item text red">
-								{{svg "octicon-x"}}
-								{{$.i18n.Tr "repo.pulls.no_merge_desc"}}
-							</div>
-							<div class="item">
-								{{svg "octicon-info"}}
-								{{$.i18n.Tr "repo.pulls.no_merge_helper"}}
-							</div>
+						{{if .ShowMergeInstructions}}
+							{{template "repo/issue/view_content/pull_merge_instruction" (dict "i18n" .i18n "Issue" .Issue)}}
 						{{end}}
 					{{else}}
+						{{/* no merge style was set in repo setting: not or ($prUnit.PullRequestsConfig.AllowMerge ...) */}}
 						<div class="ui divider"></div>
+						<div class="item text red">
+							{{svg "octicon-x"}}
+							{{$.i18n.Tr "repo.pulls.no_merge_desc"}}
+						</div>
 						<div class="item">
 							{{svg "octicon-info"}}
-							{{$.i18n.Tr "repo.pulls.no_merge_access"}}
+							{{$.i18n.Tr "repo.pulls.no_merge_helper"}}
 						</div>
-					{{end}}
-				{{end}}
+					{{end}} {{/* end if the repo was set to use any merge style */}}
+				{{else}}
+					{{/* user is not allowed to merge */}}
+					<div class="ui divider"></div>
+					<div class="item">
+						{{svg "octicon-info"}}
+						{{$.i18n.Tr "repo.pulls.no_merge_access"}}
+					</div>
+				{{end}} {{/* end if user is allowed to merge or not */}}
 			{{else}}
 				{{/* Merge conflict without specific file. Suggest manual merge, only if all reviews and status checks OK. */}}
 				{{if .IsBlockedByApprovals}}
diff --git a/templates/repo/issue/view_content/pull_merge_instruction.tmpl b/templates/repo/issue/view_content/pull_merge_instruction.tmpl
new file mode 100644
index 0000000000..0ed70860f3
--- /dev/null
+++ b/templates/repo/issue/view_content/pull_merge_instruction.tmpl
@@ -0,0 +1,19 @@
+<div class="instruct-toggle mt-3"> {{$.i18n.Tr "repo.pulls.merge_instruction_hint" | Safe}} </div>
+<div class="instruct-content" style="display:none">
+	<div class="ui divider"></div>
+	<div><h3 class="di">{{$.i18n.Tr "step1"}} </h3>{{$.i18n.Tr "repo.pulls.merge_instruction_step1_desc"}}</div>
+	<div class="ui secondary segment">
+		{{if eq $.Issue.PullRequest.Flow 0}}
+		<div>git checkout -b {{if ne $.Issue.PullRequest.HeadRepo.ID $.Issue.PullRequest.BaseRepo.ID}}{{$.Issue.PullRequest.HeadRepo.OwnerName}}-{{end}}{{$.Issue.PullRequest.HeadBranch}} {{$.Issue.PullRequest.BaseBranch}}</div>
+		<div>git pull {{if ne $.Issue.PullRequest.HeadRepo.ID $.Issue.PullRequest.BaseRepo.ID}}{{$.Issue.PullRequest.HeadRepo.HTMLURL}}{{else}}origin{{end}} {{$.Issue.PullRequest.HeadBranch}}</div>
+		{{else}}
+		<div>git fetch origin {{$.Issue.PullRequest.GetGitRefName}}:{{$.Issue.PullRequest.HeadBranch}}</div>
+		{{end}}
+	</div>
+	<div><h3 class="di">{{$.i18n.Tr "step2"}} </h3>{{$.i18n.Tr "repo.pulls.merge_instruction_step2_desc"}}</div>
+	<div class="ui secondary segment">
+		<div>git checkout {{$.Issue.PullRequest.BaseBranch}}</div>
+		<div>git merge --no-ff {{if ne $.Issue.PullRequest.HeadRepo.ID $.Issue.PullRequest.BaseRepo.ID}}{{$.Issue.PullRequest.HeadRepo.OwnerName}}-{{end}}{{$.Issue.PullRequest.HeadBranch}}</div>
+		<div>git push origin {{$.Issue.PullRequest.BaseBranch}}</div>
+	</div>
+</div>
diff --git a/web_src/js/components/PullRequestMergeForm.vue b/web_src/js/components/PullRequestMergeForm.vue
index 40398a65cb..75fbceb800 100644
--- a/web_src/js/components/PullRequestMergeForm.vue
+++ b/web_src/js/components/PullRequestMergeForm.vue
@@ -1,9 +1,23 @@
 <template>
+  <!--
+  if this component is shown, either the user is admin (can do merge without checks), or they is a writer who has the permission to do merge
+  if the user is a writer and can't do merge now (canMergeNow==false), then only show the Auto Merge for them
+  How to test the UI manually:
+  * Method 1: manually set some variables in pull.tmpl, eg: {{$notAllOverridableChecksOk = true}} {{$canMergeNow = false}}
+  * Method 2: make a protected branch, then set state=pending/success :
+    curl -X POST ${root_url}/api/v1/repos/${owner}/${repo}/statuses/${sha} \
+      -H "accept: application/json" -H "authorization: Basic $base64_auth" -H "Content-Type: application/json" \
+      -d '{"context": "test/context", "description": "description", "state": "${state}", "target_url": "http://localhost"}'
+  -->
   <div>
+    <!-- eslint-disable -->
+    <div v-if="mergeForm.hasPendingPullRequestMerge" v-html="mergeForm.hasPendingPullRequestMergeTip" class="ui info message"></div>
+
     <div class="ui form" v-if="showActionForm">
       <form :action="mergeForm.baseLink+'/merge'" method="post">
         <input type="hidden" name="_csrf" :value="csrfToken">
         <input type="hidden" name="head_commit_id" v-model="mergeForm.pullHeadCommitID">
+        <input type="hidden" name="merge_when_checks_succeed" v-model="autoMergeWhenSucceed">
 
         <template v-if="!mergeStyleDetail.hideMergeMessageTexts">
           <div class="field">
@@ -14,39 +28,72 @@
           </div>
         </template>
 
-        <button class="ui button" :class="[mergeForm.allOverridableChecksOk?'green':'red']" type="submit" name="do" :value="mergeStyle">
+        <button class="ui button" :class="mergeButtonStyleClass" type="submit" name="do" :value="mergeStyle">
           {{ mergeStyleDetail.textDoMerge }}
+          <template v-if="autoMergeWhenSucceed">
+            {{ mergeForm.textAutoMergeButtonWhenSucceed }}
+          </template>
         </button>
 
         <button class="ui button merge-cancel" @click="toggleActionForm(false)">
           {{ mergeForm.textCancel }}
         </button>
 
-        <div class="ui checkbox ml-2" v-if="mergeForm.isPullBranchDeletable">
+        <div class="ui checkbox ml-2" v-if="mergeForm.isPullBranchDeletable && !autoMergeWhenSucceed">
           <input name="delete_branch_after_merge" type="checkbox" v-model="deleteBranchAfterMerge" id="delete-branch-after-merge">
           <label for="delete-branch-after-merge">{{ mergeForm.textDeleteBranch }}</label>
         </div>
       </form>
     </div>
 
-    <template v-if="!showActionForm">
-      <div class="ui buttons merge-button" :class="[mergeForm.allOverridableChecksOk?'green':'red']" @click="toggleActionForm(true)">
+    <div v-if="!showActionForm" class="df">
+      <!-- the merge button -->
+      <div class="ui buttons merge-button" :class="mergeButtonStyleClass" @click="toggleActionForm(true)" >
         <button class="ui button">
           <svg-icon name="octicon-git-merge"/>
-          <span class="button-text">{{ mergeStyleDetail.textDoMerge }}</span>
+          <span class="button-text">
+            {{ mergeStyleDetail.textDoMerge }}
+            <template v-if="autoMergeWhenSucceed">
+              {{ mergeForm.textAutoMergeButtonWhenSucceed }}
+            </template>
+          </span>
         </button>
         <div class="ui dropdown icon button no-text" @click.stop="showMergeStyleMenu = !showMergeStyleMenu" v-if="mergeStyleAllowedCount>1">
           <svg-icon name="octicon-triangle-down" :size="14"/>
           <div class="menu" :class="{'show':showMergeStyleMenu}">
             <template v-for="msd in mergeForm.mergeStyles">
-              <div class="item" v-if="msd.allowed" :key="msd.name" @click.stop="mergeStyle=msd.name">
-                {{ msd.textDoMerge }}
+              <!-- if can merge now, show one action "merge now", and an action "auto merge when succeed" -->
+              <div class="item" v-if="msd.allowed && mergeForm.canMergeNow" :key="msd.name" @click.stop="switchMergeStyle(msd.name)">
+                <div class="action-text">
+                  {{ msd.textDoMerge }}
+                </div>
+                <div v-if="!msd.hideAutoMerge" class="auto-merge-small" @click.stop="switchMergeStyle(msd.name, true)">
+                  <svg-icon name="octicon-clock" :size="14"/>
+                  <div class="auto-merge-tip">
+                    {{ mergeForm.textAutoMergeWhenSucceed }}
+                  </div>
+                </div>
+              </div>
+
+              <!-- if can NOT merge now, only show one action "auto merge when succeed" -->
+              <div class="item" v-if="msd.allowed && !mergeForm.canMergeNow && !msd.hideAutoMerge" :key="msd.name" @click.stop="switchMergeStyle(msd.name, true)">
+                <div class="action-text">
+                  {{ msd.textDoMerge }} {{ mergeForm.textAutoMergeButtonWhenSucceed }}
+                </div>
               </div>
             </template>
           </div>
         </div>
       </div>
-    </template>
+
+      <!-- the cancel auto merge button -->
+      <form v-if="mergeForm.hasPendingPullRequestMerge" :action="mergeForm.baseLink+'/cancel_auto_merge'" method="post" class="ml-4">
+        <input type="hidden" name="_csrf" :value="csrfToken">
+        <button class="ui button">
+          {{ mergeForm.textAutoMergeCancelSchedule }}
+        </button>
+      </form>
+    </div>
   </div>
 </template>
 
@@ -68,6 +115,7 @@ export default {
     mergeTitleFieldValue: '',
     mergeMessageFieldValue: '',
     deleteBranchAfterMerge: false,
+    autoMergeWhenSucceed: false,
 
     mergeStyle: '',
     mergeStyleDetail: { // dummy only, these values will come from one of the mergeForm.mergeStyles
@@ -82,6 +130,13 @@ export default {
     showActionForm: false,
   }),
 
+  computed: {
+    mergeButtonStyleClass() {
+      if (this.mergeForm.allOverridableChecksOk) return 'green';
+      return this.autoMergeWhenSucceed ? 'blue' : 'red';
+    }
+  },
+
   watch: {
     mergeStyle(val) {
       this.mergeStyleDetail = this.mergeForm.mergeStyles.find((e) => e.name === val);
@@ -90,7 +145,7 @@ export default {
 
   created() {
     this.mergeStyleAllowedCount = this.mergeForm.mergeStyles.reduce((v, msd) => v + (msd.allowed ? 1 : 0), 0);
-    this.mergeStyle = this.mergeForm.mergeStyles.find((e) => e.allowed)?.name;
+    this.switchMergeStyle(this.mergeForm.mergeStyles.find((e) => e.allowed)?.name, !this.mergeForm.canMergeNow);
   },
 
   mounted() {
@@ -111,7 +166,11 @@ export default {
       this.deleteBranchAfterMerge = this.mergeForm.defaultDeleteBranchAfterMerge;
       this.mergeTitleFieldValue = this.mergeStyleDetail.mergeTitleFieldText;
       this.mergeMessageFieldValue = this.mergeStyleDetail.mergeMessageFieldText;
-    }
+    },
+    switchMergeStyle(name, autoMerge = false) {
+      this.mergeStyle = name;
+      this.autoMergeWhenSucceed = autoMerge;
+    },
   },
 };
 </script>
@@ -124,4 +183,59 @@ export default {
 .ui.checkbox label {
   cursor: pointer;
 }
+
+/* make the dropdown list left-aligned */
+.ui.merge-button {
+  position: relative;
+}
+.ui.merge-button .ui.dropdown {
+  position: static;
+}
+.ui.merge-button > .ui.dropdown:last-child > .menu:not(.left) {
+  left: 0;
+  right: auto;
+}
+.ui.merge-button .ui.dropdown .menu > .item {
+  display: flex;
+  align-items: stretch;
+  padding: 0 !important; /* polluted by semantic.css: .ui.dropdown .menu > .item { !important } */
+}
+
+/* merge style list item */
+.action-text {
+  padding: 0.8rem;
+  flex: 1
+}
+
+.auto-merge-small {
+  width: 40px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  position: relative;
+}
+.auto-merge-small .auto-merge-tip {
+  display: none;
+  left: 38px;
+  top: -1px;
+  bottom: -1px;
+  position: absolute;
+  align-items: center;
+  color: var(--color-info-text);
+  background-color: var(--color-info-bg);
+  border: 1px solid var(--color-info-border);
+  border-left: none;
+  padding-right: 1rem;
+}
+
+.auto-merge-small:hover {
+  color: var(--color-info-text);
+  background-color: var(--color-info-bg);
+  border: 1px solid var(--color-info-border);
+}
+
+.auto-merge-small:hover .auto-merge-tip {
+  display: flex;
+}
+
 </style>
diff --git a/web_src/js/svg.js b/web_src/js/svg.js
index 926f0a5d05..9c39852c30 100644
--- a/web_src/js/svg.js
+++ b/web_src/js/svg.js
@@ -1,6 +1,7 @@
 import octiconChevronDown from '../../public/img/svg/octicon-chevron-down.svg';
 import octiconChevronRight from '../../public/img/svg/octicon-chevron-right.svg';
 import octiconCopy from '../../public/img/svg/octicon-copy.svg';
+import octiconClock from '../../public/img/svg/octicon-clock.svg';
 import octiconGitMerge from '../../public/img/svg/octicon-git-merge.svg';
 import octiconGitPullRequest from '../../public/img/svg/octicon-git-pull-request.svg';
 import octiconIssueClosed from '../../public/img/svg/octicon-issue-closed.svg';
@@ -23,6 +24,7 @@ export const svgs = {
   'octicon-chevron-down': octiconChevronDown,
   'octicon-chevron-right': octiconChevronRight,
   'octicon-copy': octiconCopy,
+  'octicon-clock': octiconClock,
   'octicon-git-merge': octiconGitMerge,
   'octicon-git-pull-request': octiconGitPullRequest,
   'octicon-issue-closed': octiconIssueClosed,
diff --git a/web_src/less/_base.less b/web_src/less/_base.less
index c029cb9485..4d7f69e3b3 100644
--- a/web_src/less/_base.less
+++ b/web_src/less/_base.less
@@ -2003,14 +2003,6 @@ table th[data-sortt-desc] {
   margin-right: 0 !important;
 }
 
-/* limit width of all direct dropdown menu children */
-/* https://github.com/go-gitea/gitea/pull/10835 */
-.dropdown:not(.selection) > .menu:not(.review-box) > *:not(.header) {
-  max-width: 300px;
-  overflow-x: hidden;
-  text-overflow: ellipsis;
-}
-
 .ui.dropdown .menu .item {
   border-radius: 0;
 }
diff --git a/web_src/less/_repository.less b/web_src/less/_repository.less
index d73cb90330..37a5017fbd 100644
--- a/web_src/less/_repository.less
+++ b/web_src/less/_repository.less
@@ -1055,10 +1055,6 @@
         .merge-section {
           background-color: var(--color-box-body);
 
-          .item {
-            padding: .25rem 0;
-          }
-
           .item-section {
             display: flex;
             align-items: center;