Repository: git-town/git-town

Issue:
`sync --stack` stuck in infinite loop due to merge queues
### Steps to reproduce

While working in a repo hosted on GitHub with [merge queues](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-a-merge-queue#about-merge-queues) enabled, and you have a branch setup like this:

```mermaid
gitGraph
   commit
   branch feature/one
   checkout feature/one
   commit
   commit
   branch feature/two
   checkout feature/two
   commit
   commit
   checkout main
   commit
```

- Open a PR for `feature/one` and add it to the merge queue
- While it is still in the merge queue:
  - `git switch feature/two`
  - `git sync` or `git sync --stack` (shouldn't really matter which one since we are on the "top" of the stack, I think
  - Git town will be stuck in an infinite loop trying and failing to rebase `feature/one` onto the latest from `main`

The command output posted will repeat indefinitely as it retries. Another unexpected behavior is that pressing Ctrl+c seems to cancel the currently running git command (either `rebase` or `push`), instead of canceling the whole `git town sync` command. In other words, Ctrl+c doesn't break the loop.

### Command output

```shell
[feature/one] git rebase main --no-update-refs
summary: (done in 0.15 seconds)
Successfully rebased and updated refs/heads/feature/one.

[feature/one] git push --force-with-lease --force-if-includes --no-verify
remote: error: GH006: Protected branch update failed for refs/heads/feature/one.
remote:
remote: - A pull request for this branch has been added to a merge queue. Branches that
remote:   are queued for merging cannot be updated. To modify this branch, dequeue the
remote:   associated pull request.
To github.com:REDACTED/REDACTED.git
 ! [remote rejected]           feature/one -> feature/one (protected branch hook declined)
error: failed to push some refs to 'github.com:REDACTED/REDACTED.git'
```

### Additional information

In a sense, it's user error to try to update `feature/one` while its in the merge queue. It slipped my mind that this branch would be protected, but it really doesn't seem possible to update `feature/two` while `feature/one` is in the queue.

Perhaps git town can catch the protected branch error and abort with an explanatory error message.

Discussion:
@ianjsikes: It might be relevant that I have `rebase.updateRefs` set to true in my gitconfig. So rebasing `feature/two` _also_ updates which commit `feature/one` is pointing to@kevgo: Thanks for reporting this! This happens because of some cleverness I introduced a while ago to optimize a few Git operations away. Time to de-optimize and keep it simple and straightforward. Fix coming soon!

Solution patch:
diff --git a/features/prepend/beam/propose.feature b/features/prepend/beam/propose.feature
index 97ce86da7..8a7093a9c 100644
--- a/features/prepend/beam/propose.feature
+++ b/features/prepend/beam/propose.feature
@@ -27,10 +27,8 @@ Feature: propose a newly prepended branch
       | (none)   | Looking for proposal online ... ok                                      |
       | existing | git checkout parent                                                     |
       | parent   | git rebase main --no-update-refs                                        |
-      |          | git push --force-with-lease --force-if-includes                         |
       |          | git checkout existing                                                   |
       | existing | git rebase parent --no-update-refs                                      |
-      |          | git push --force-with-lease --force-if-includes                         |
       |          | git checkout -b new parent                                              |
       | new      | git cherry-pick {{ sha-before-run 'unrelated commit' }}                 |
       |          | git checkout existing                                                   |
diff --git a/features/prepend/beam/propose_with_title_and_body.feature b/features/prepend/beam/propose_with_title_and_body.feature
index 45947d2a6..4756c68ec 100644
--- a/features/prepend/beam/propose_with_title_and_body.feature
+++ b/features/prepend/beam/propose_with_title_and_body.feature
@@ -25,7 +25,6 @@ Feature: propose a newly prepended branch
       | existing | git fetch --prune --tags                                                                               |
       | (none)   | Looking for proposal online ... ok                                                                     |
       | existing | git rebase main --no-update-refs                                                                       |
-      |          | git push --force-with-lease --force-if-includes                                                        |
       |          | git checkout -b new main                                                                               |
       | new      | git cherry-pick {{ sha-before-run 'unrelated commit' }}                                                |
       |          | git checkout existing                                                                                  |
diff --git a/features/prepend/beam/rebase.feature b/features/prepend/beam/rebase.feature
index b013fbcba..fc6be23bc 100644
--- a/features/prepend/beam/rebase.feature
+++ b/features/prepend/beam/rebase.feature
@@ -23,7 +23,6 @@ Feature: prepend a branch to a feature branch using the "rebase" sync strategy
       | BRANCH | COMMAND                                         |
       | old    | git fetch --prune --tags                        |
       |        | git rebase main --no-update-refs                |
-      |        | git push --force-with-lease --force-if-includes |
       |        | git checkout -b parent main                     |
       | parent | git cherry-pick {{ sha-before-run 'commit 2' }} |
       |        | git cherry-pick {{ sha-before-run 'commit 4' }} |
diff --git a/features/sync/all_branches/merge_sync_strategy/happy_path.feature b/features/sync/all_branches/merge_sync_strategy/happy_path.feature
index 9d627b09b..71633d1fa 100644
--- a/features/sync/all_branches/merge_sync_strategy/happy_path.feature
+++ b/features/sync/all_branches/merge_sync_strategy/happy_path.feature
@@ -77,9 +77,11 @@ Feature: sync all feature branches
       | main       | git rebase origin/main --no-update-refs         |
       |            | git checkout alpha                              |
       | alpha      | git rebase main --no-update-refs                |
+      |            | git rebase origin/alpha --no-update-refs        |
       |            | git push --force-with-lease --force-if-includes |
       |            | git checkout beta                               |
       | beta       | git rebase main --no-update-refs                |
+      |            | git rebase origin/beta --no-update-refs         |
       |            | git push --force-with-lease --force-if-includes |
       |            | git checkout observed                           |
       | observed   | git rebase origin/observed --no-update-refs     |
@@ -96,7 +98,9 @@ Feature: sync all feature branches
       | BRANCH     | LOCATION      | MESSAGE                  |
       | main       | local, origin | main commit              |
       | alpha      | local, origin | alpha commit             |
+      |            |               | main commit              |
       | beta       | local, origin | beta commit              |
+      |            |               | main commit              |
       | observed   | local, origin | origin observed commit   |
       |            | local         | local observed commit    |
       | parked     | local         | local parked commit      |
diff --git a/features/sync/current_branch/feature_branch/mixed_sync_strategies/two_collaborators_different_sync_strategies.feature b/features/sync/current_branch/feature_branch/mixed_sync_strategies/two_collaborators_different_sync_strategies.feature
index 5879d8085..bd11d3bf3 100644
--- a/features/sync/current_branch/feature_branch/mixed_sync_strategies/two_collaborators_different_sync_strategies.feature
+++ b/features/sync/current_branch/feature_branch/mixed_sync_strategies/two_collaborators_different_sync_strategies.feature
@@ -22,6 +22,7 @@ Feature: compatibility between different sync-feature-strategy settings
       | BRANCH  | COMMAND                                         |
       | feature | git fetch --prune --tags                        |
       |         | git rebase main --no-update-refs                |
+      |         | git rebase origin/feature --no-update-refs      |
       |         | git push --force-with-lease --force-if-includes |
     And these commits exist now
       | BRANCH  | LOCATION      | MESSAGE         | FILE NAME | FILE CONTENT |
@@ -62,11 +63,10 @@ Feature: compatibility between different sync-feature-strategy settings
       | my second commit | file.txt  | my new content |
     When I run "git-town sync"
     Then Git Town runs the commands
-      | BRANCH  | COMMAND                                         |
-      | feature | git fetch --prune --tags                        |
-      |         | git rebase main --no-update-refs                |
-      |         | git push --force-with-lease --force-if-includes |
-      |         | git rebase origin/feature --no-update-refs      |
+      | BRANCH  | COMMAND                                    |
+      | feature | git fetch --prune --tags                   |
+      |         | git rebase main --no-update-refs           |
+      |         | git rebase origin/feature --no-update-refs |
     And Git Town prints the error:
       """
       To continue after having resolved conflicts, run "git town continue".
@@ -77,6 +77,7 @@ Feature: compatibility between different sync-feature-strategy settings
       | BRANCH  | COMMAND                                         |
       | feature | git -c core.editor=true rebase --continue       |
       |         | git push --force-with-lease --force-if-includes |
+    And no rebase is now in progress
     And all branches are now synchronized
     And these commits exist now
       | BRANCH  | LOCATION                | MESSAGE                                                    | FILE NAME | FILE CONTENT                |
diff --git a/features/sync/current_branch/feature_branch/rebase_sync_strategy/detached/enabled.feature b/features/sync/current_branch/feature_branch/rebase_sync_strategy/detached/enabled.feature
index 7a53aa652..bab3212c9 100644
--- a/features/sync/current_branch/feature_branch/rebase_sync_strategy/detached/enabled.feature
+++ b/features/sync/current_branch/feature_branch/rebase_sync_strategy/detached/enabled.feature
@@ -20,7 +20,6 @@ Feature: detached sync the current feature branch using the "rebase" feature syn
       | BRANCH  | COMMAND                                         |
       | feature | git fetch --prune --tags                        |
       |         | git rebase main --no-update-refs                |
-      |         | git push --force-with-lease --force-if-includes |
       |         | git rebase origin/feature --no-update-refs      |
       |         | git push --force-with-lease --force-if-includes |
     And the current branch is still "feature"
diff --git a/features/sync/current_branch/feature_branch/rebase_sync_strategy/modified_commits/amended_commit.feature b/features/sync/current_branch/feature_branch/rebase_sync_strategy/modified_commits/amended_commit.feature
index f6bdd828a..1d8b2fed6 100644
--- a/features/sync/current_branch/feature_branch/rebase_sync_strategy/modified_commits/amended_commit.feature
+++ b/features/sync/current_branch/feature_branch/rebase_sync_strategy/modified_commits/amended_commit.feature
@@ -1,5 +1,8 @@
 Feature: rebase a branch that contains amended commits
 
+# This test demonstrates how Git Town currently does not sync branches that contain amended commits correctly.
+# This will be fixed by implementing https://github.com/git-town/git-town/issues/4586.
+
   Background:
     Given a Git repo with origin
     And I ran "git-town hack feature-1"
@@ -22,13 +25,11 @@ Feature: rebase a branch that contains amended commits
 
   Scenario: result
     Then Git Town runs the commands
-      | BRANCH    | COMMAND                                         |
-      | feature-2 | git fetch --prune --tags                        |
-      |           | git checkout feature-1                          |
-      | feature-1 | git rebase main --no-update-refs                |
-      |           | git push --force-with-lease --force-if-includes |
-      |           | git checkout feature-2                          |
-      | feature-2 | git rebase feature-1 --no-update-refs           |
+      | BRANCH    | COMMAND                                      |
+      | feature-2 | git fetch --prune --tags                     |
+      |           | git checkout feature-1                       |
+      | feature-1 | git rebase main --no-update-refs             |
+      |           | git rebase origin/feature-1 --no-update-refs |
     And Git Town prints the error:
       """
       CONFLICT (add/add): Merge conflict in file_1
@@ -40,20 +41,26 @@ Feature: rebase a branch that contains amended commits
     And I run "git-town continue" and close the editor
     Then Git Town runs the commands
       | BRANCH    | COMMAND                                         |
-      | feature-2 | git -c core.editor=true rebase --continue       |
+      | feature-1 | git -c core.editor=true rebase --continue       |
+      |           | git push --force-with-lease --force-if-includes |
+      |           | git checkout feature-2                          |
+      | feature-2 | git rebase feature-1 --no-update-refs           |
+      |           | git rebase origin/feature-2 --no-update-refs    |
       |           | git push --force-with-lease --force-if-includes |
     And the current branch is still "feature-2"
     And these commits exist now
       | BRANCH    | LOCATION      | MESSAGE   | FILE NAME | FILE CONTENT |
-      | feature-1 | local, origin | commit 1b | file_1    | another one  |
+      | feature-1 | local, origin | commit 1a | file_1    | one          |
+      |           |               | commit 1b | file_1    | another one  |
       | feature-2 | local, origin | commit 2  | file_2    | two          |
+      |           |               | commit 1b | file_1    | another one  |
 
   Scenario: undo
     When I run "git-town undo"
     Then Git Town runs the commands
-      | BRANCH    | COMMAND                                                            |
-      | feature-2 | git rebase --abort                                                 |
-      |           | git push --force-with-lease origin {{ sha 'commit 1a' }}:feature-1 |
+      | BRANCH    | COMMAND                |
+      | feature-1 | git rebase --abort     |
+      |           | git checkout feature-2 |
     And the current branch is still "feature-2"
     And these commits exist now
       | BRANCH    | LOCATION      | MESSAGE   |
diff --git a/features/sync/current_branch/feature_branch/rebase_sync_strategy/subfolder/subfolder_only_on_feature/happy_path.feature b/features/sync/current_branch/feature_branch/rebase_sync_strategy/subfolder/subfolder_only_on_feature/happy_path.feature
index 9246dfa73..09e35a59a 100644
--- a/features/sync/current_branch/feature_branch/rebase_sync_strategy/subfolder/subfolder_only_on_feature/happy_path.feature
+++ b/features/sync/current_branch/feature_branch/rebase_sync_strategy/subfolder/subfolder_only_on_feature/happy_path.feature
@@ -6,12 +6,12 @@ Feature: sync inside a folder that doesn't exist on the main branch
       | NAME  | TYPE    | PARENT | LOCATIONS     |
       | alpha | feature | main   | local, origin |
       | beta  | feature | main   | local, origin |
-    And Git setting "git-town.sync-feature-strategy" is "rebase"
     And the commits
       | BRANCH | LOCATION      | MESSAGE       | FILE NAME        |
       | main   | local, origin | main commit   | main_file        |
       | alpha  | local, origin | folder commit | new_folder/file1 |
       | beta   | local, origin | beta commit   | file2            |
+    And Git setting "git-town.sync-feature-strategy" is "rebase"
     And the current branch is "alpha"
     When I run "git-town sync --all" in the "new_folder" folder
 
@@ -20,19 +20,27 @@ Feature: sync inside a folder that doesn't exist on the main branch
       | BRANCH | COMMAND                                         |
       | alpha  | git fetch --prune --tags                        |
       |        | git rebase main --no-update-refs                |
+      |        | git rebase origin/alpha --no-update-refs        |
       |        | git push --force-with-lease --force-if-includes |
       |        | git checkout beta                               |
       | beta   | git rebase main --no-update-refs                |
+      |        | git rebase origin/beta --no-update-refs         |
       |        | git push --force-with-lease --force-if-includes |
       |        | git checkout alpha                              |
       | alpha  | git push --tags                                 |
     And all branches are now synchronized
     And the current branch is still "alpha"
+    And this lineage exists now
+      | BRANCH | PARENT |
+      | alpha  | main   |
+      | beta   | main   |
     And these commits exist now
       | BRANCH | LOCATION      | MESSAGE       |
       | main   | local, origin | main commit   |
       | alpha  | local, origin | folder commit |
+      |        |               | main commit   |
       | beta   | local, origin | beta commit   |
+      |        |               | main commit   |
 
   Scenario: undo
     When I run "git-town undo"
diff --git a/features/sync/current_branch/feature_branch/rebase_sync_strategy/tracking_branch/with/conflict_feature_branch_tracking_branch.feature b/features/sync/current_branch/feature_branch/rebase_sync_strategy/tracking_branch/with/conflict_feature_branch_tracking_branch.feature
index 42bda6239..6dae182df 100644
--- a/features/sync/current_branch/feature_branch/rebase_sync_strategy/tracking_branch/with/conflict_feature_branch_tracking_branch.feature
+++ b/features/sync/current_branch/feature_branch/rebase_sync_strategy/tracking_branch/with/conflict_feature_branch_tracking_branch.feature
@@ -16,11 +16,10 @@ Feature: handle conflicts between the current feature branch and its tracking br
 
   Scenario: result
     Then Git Town runs the commands
-      | BRANCH  | COMMAND                                         |
-      | feature | git fetch --prune --tags                        |
-      |         | git rebase main --no-update-refs                |
-      |         | git push --force-with-lease --force-if-includes |
-      |         | git rebase origin/feature --no-update-refs      |
+      | BRANCH  | COMMAND                                    |
+      | feature | git fetch --prune --tags                   |
+      |         | git rebase main --no-update-refs           |
+      |         | git rebase origin/feature --no-update-refs |
     And Git Town prints the error:
       """
       CONFLICT (add/add): Merge conflict in conflicting_file
diff --git a/features/sync/current_branch/feature_branch/rebase_sync_strategy/tracking_branch/with/conflict_feature_vs_main.feature b/features/sync/current_branch/feature_branch/rebase_sync_strategy/tracking_branch/with/conflict_feature_vs_main.feature
index 3af208750..20d2fbdd8 100644
--- a/features/sync/current_branch/feature_branch/rebase_sync_strategy/tracking_branch/with/conflict_feature_vs_main.feature
+++ b/features/sync/current_branch/feature_branch/rebase_sync_strategy/tracking_branch/with/conflict_feature_vs_main.feature
@@ -64,10 +64,9 @@ Feature: handle conflicts between the current feature branch and the main branch
     When I resolve the conflict in "conflicting_file"
     And I run "git-town continue" and enter "resolved conflict between main and feature branch" for the commit message
     Then Git Town runs the commands
-      | BRANCH  | COMMAND                                         |
-      | feature | git -c core.editor=true rebase --continue       |
-      |         | git push --force-with-lease --force-if-includes |
-      |         | git rebase origin/feature --no-update-refs      |
+      | BRANCH  | COMMAND                                    |
+      | feature | git -c core.editor=true rebase --continue  |
+      |         | git rebase origin/feature --no-update-refs |
     When I resolve the conflict in "conflicting_file"
     And I run "git-town continue" and enter "resolved conflict between feature and origin/feature branch" for the commit message
     Then Git Town runs the commands
@@ -88,9 +87,8 @@ Feature: handle conflicts between the current feature branch and the main branch
     And I run "git rebase --continue" and enter "resolved conflict between main and feature branch" for the commit message
     And I run "git-town continue"
     Then Git Town runs the commands
-      | BRANCH  | COMMAND                                         |
-      | feature | git push --force-with-lease --force-if-includes |
-      |         | git rebase origin/feature --no-update-refs      |
+      | BRANCH  | COMMAND                                    |
+      | feature | git rebase origin/feature --no-update-refs |
     When I resolve the conflict in "conflicting_file"
     And I run "git-town continue" and enter "resolved conflict between feature and origin/feature branch" for the commit message
     Then Git Town runs the commands
diff --git a/features/sync/current_branch/feature_branch/rebase_sync_strategy/tracking_branch/with/conflict_main_local_vs_main_tracking.feature b/features/sync/current_branch/feature_branch/rebase_sync_strategy/tracking_branch/with/conflict_main_local_vs_main_tracking.feature
index 98b018054..0588a6393 100644
--- a/features/sync/current_branch/feature_branch/rebase_sync_strategy/tracking_branch/with/conflict_main_local_vs_main_tracking.feature
+++ b/features/sync/current_branch/feature_branch/rebase_sync_strategy/tracking_branch/with/conflict_main_local_vs_main_tracking.feature
@@ -58,6 +58,7 @@ Feature: handle conflicts between the main branch and its tracking branch
       |         | git push                                        |
       |         | git checkout feature                            |
       | feature | git rebase main --no-update-refs                |
+      |         | git rebase origin/feature --no-update-refs      |
       |         | git push --force-with-lease --force-if-includes |
     And all branches are now synchronized
     And the current branch is still "feature"
@@ -76,6 +77,7 @@ Feature: handle conflicts between the main branch and its tracking branch
       | main    | git push                                        |
       |         | git checkout feature                            |
       | feature | git rebase main --no-update-refs                |
+      |         | git rebase origin/feature --no-update-refs      |
       |         | git push --force-with-lease --force-if-includes |
     And all branches are now synchronized
     And the current branch is still "feature"
diff --git a/features/sync/current_branch/feature_branch/rebase_sync_strategy/tracking_branch/with/happy_path.feature b/features/sync/current_branch/feature_branch/rebase_sync_strategy/tracking_branch/with/happy_path.feature
index bccb91179..d70bc7763 100644
--- a/features/sync/current_branch/feature_branch/rebase_sync_strategy/tracking_branch/with/happy_path.feature
+++ b/features/sync/current_branch/feature_branch/rebase_sync_strategy/tracking_branch/with/happy_path.feature
@@ -24,7 +24,6 @@ Feature: sync the current feature branch using the "rebase" feature sync strateg
       |         | git push                                        |
       |         | git checkout feature                            |
       | feature | git rebase main --no-update-refs                |
-      |         | git push --force-with-lease --force-if-includes |
       |         | git rebase origin/feature --no-update-refs      |
       |         | git push --force-with-lease --force-if-includes |
     And all branches are now synchronized
diff --git a/features/sync/current_branch/feature_branch/rebase_sync_strategy/tracking_branch/without/conflict_feature_vs_main.feature b/features/sync/current_branch/feature_branch/rebase_sync_strategy/tracking_branch/without/conflict_feature_vs_main.feature
index d91f8af18..4125b7e54 100644
--- a/features/sync/current_branch/feature_branch/rebase_sync_strategy/tracking_branch/without/conflict_feature_vs_main.feature
+++ b/features/sync/current_branch/feature_branch/rebase_sync_strategy/tracking_branch/without/conflict_feature_vs_main.feature
@@ -64,6 +64,7 @@ Feature: handle conflicts between the current feature branch and the main branch
     Then Git Town runs the commands
       | BRANCH  | COMMAND                                         |
       | feature | git -c core.editor=true rebase --continue       |
+      |         | git rebase origin/feature --no-update-refs      |
       |         | git push --force-with-lease --force-if-includes |
     And all branches are now synchronized
     And the current branch is still "feature"
@@ -79,6 +80,7 @@ Feature: handle conflicts between the current feature branch and the main branch
     Then Git Town runs the commands
       | BRANCH  | COMMAND                                         |
       | feature | git -c core.editor=true rebase --continue       |
+      |         | git rebase origin/feature --no-update-refs      |
       |         | git push --force-with-lease --force-if-includes |
     And the current branch is still "feature"
     And all branches are now synchronized
@@ -94,7 +96,8 @@ Feature: handle conflicts between the current feature branch and the main branch
     And I run "git-town continue"
     Then Git Town runs the commands
       | BRANCH  | COMMAND                                         |
-      | feature | git push --force-with-lease --force-if-includes |
+      | feature | git rebase origin/feature --no-update-refs      |
+      |         | git push --force-with-lease --force-if-includes |
     And the current branch is still "feature"
     And all branches are now synchronized
     And no merge is in progress
diff --git a/features/sync/current_branch/feature_branch/rebase_sync_strategy/tracking_branch/without/conflict_main_local_vs_main_tracking.feature b/features/sync/current_branch/feature_branch/rebase_sync_strategy/tracking_branch/without/conflict_main_local_vs_main_tracking.feature
index d5a60b53f..593046ff2 100644
--- a/features/sync/current_branch/feature_branch/rebase_sync_strategy/tracking_branch/without/conflict_main_local_vs_main_tracking.feature
+++ b/features/sync/current_branch/feature_branch/rebase_sync_strategy/tracking_branch/without/conflict_main_local_vs_main_tracking.feature
@@ -75,6 +75,7 @@ Feature: handle conflicts between the main branch and its tracking branch
       |         | git push                                        |
       |         | git checkout feature                            |
       | feature | git rebase main --no-update-refs                |
+      |         | git rebase origin/feature --no-update-refs      |
       |         | git push --force-with-lease --force-if-includes |
     And all branches are now synchronized
     And the current branch is still "feature"
@@ -93,6 +94,7 @@ Feature: handle conflicts between the main branch and its tracking branch
       | main    | git push                                        |
       |         | git checkout feature                            |
       | feature | git rebase main --no-update-refs                |
+      |         | git rebase origin/feature --no-update-refs      |
       |         | git push --force-with-lease --force-if-includes |
     And all branches are now synchronized
     And the current branch is still "feature"
diff --git a/features/sync/current_branch/feature_branch/rebase_sync_strategy/two_collaborators/conflicting_commits.feature b/features/sync/current_branch/feature_branch/rebase_sync_strategy/two_collaborators/conflicting_commits.feature
index 25be1920e..96ba891f1 100644
--- a/features/sync/current_branch/feature_branch/rebase_sync_strategy/two_collaborators/conflicting_commits.feature
+++ b/features/sync/current_branch/feature_branch/rebase_sync_strategy/two_collaborators/conflicting_commits.feature
@@ -29,6 +29,7 @@ Feature: two people using rebase make conflicting changes to a branch
       | BRANCH  | COMMAND                                         |
       | feature | git fetch --prune --tags                        |
       |         | git rebase main --no-update-refs                |
+      |         | git rebase origin/feature --no-update-refs      |
       |         | git push --force-with-lease --force-if-includes |
     And these commits exist now
       | BRANCH  | LOCATION      | MESSAGE         | FILE NAME | FILE CONTENT |
@@ -41,11 +42,10 @@ Feature: two people using rebase make conflicting changes to a branch
       | coworker first commit | file.txt  | coworker content |
     When the coworker runs "git-town sync"
     Then Git Town runs the commands
-      | BRANCH  | COMMAND                                         |
-      | feature | git fetch --prune --tags                        |
-      |         | git rebase main --no-update-refs                |
-      |         | git push --force-with-lease --force-if-includes |
-      |         | git rebase origin/feature --no-update-refs      |
+      | BRANCH  | COMMAND                                    |
+      | feature | git fetch --prune --tags                   |
+      |         | git rebase main --no-update-refs           |
+      |         | git rebase origin/feature --no-update-refs |
     And Git Town prints the error:
       """
       To continue after having resolved conflicts, run "git town continue".
@@ -68,11 +68,10 @@ Feature: two people using rebase make conflicting changes to a branch
       | my second commit | file.txt  | my new content |
     When I run "git-town sync"
     Then Git Town runs the commands
-      | BRANCH  | COMMAND                                         |
-      | feature | git fetch --prune --tags                        |
-      |         | git rebase main --no-update-refs                |
-      |         | git push --force-with-lease --force-if-includes |
-      |         | git rebase origin/feature --no-update-refs      |
+      | BRANCH  | COMMAND                                    |
+      | feature | git fetch --prune --tags                   |
+      |         | git rebase main --no-update-refs           |
+      |         | git rebase origin/feature --no-update-refs |
     And Git Town prints the error:
       """
       To continue after having resolved conflicts, run "git town continue".
diff --git a/features/sync/current_branch/feature_branch/rebase_sync_strategy/two_collaborators/happy_path.feature b/features/sync/current_branch/feature_branch/rebase_sync_strategy/two_collaborators/happy_path.feature
index eb4e52642..208ffb18a 100644
--- a/features/sync/current_branch/feature_branch/rebase_sync_strategy/two_collaborators/happy_path.feature
+++ b/features/sync/current_branch/feature_branch/rebase_sync_strategy/two_collaborators/happy_path.feature
@@ -27,6 +27,7 @@ Feature: two people with rebase strategy sync changes made by them
       | BRANCH  | COMMAND                                         |
       | feature | git fetch --prune --tags                        |
       |         | git rebase main --no-update-refs                |
+      |         | git rebase origin/feature --no-update-refs      |
       |         | git push --force-with-lease --force-if-includes |
     And these commits exist now
       | BRANCH  | LOCATION      | MESSAGE         |
@@ -40,7 +41,6 @@ Feature: two people with rebase strategy sync changes made by them
       | BRANCH  | COMMAND                                         |
       | feature | git fetch --prune --tags                        |
       |         | git rebase main --no-update-refs                |
-      |         | git push --force-with-lease --force-if-includes |
       |         | git rebase origin/feature --no-update-refs      |
       |         | git push --force-with-lease --force-if-includes |
     And all branches are now synchronized
@@ -52,12 +52,11 @@ Feature: two people with rebase strategy sync changes made by them
     Given the current branch is "feature"
     When I run "git-town sync"
     Then Git Town runs the commands
-      | BRANCH  | COMMAND                                         |
-      | feature | git fetch --prune --tags                        |
-      |         | git rebase main --no-update-refs                |
-      |         | git push --force-with-lease --force-if-includes |
-      |         | git rebase origin/feature --no-update-refs      |
-      |         | git push --force-with-lease --force-if-includes |
+      | BRANCH  | COMMAND                                    |
+      | feature | git fetch --prune --tags                   |
+      |         | git rebase main --no-update-refs           |
+      |         | git rebase origin/feature --no-update-refs |
+    And no rebase is now in progress
     And all branches are now synchronized
     And these commits exist now
       | BRANCH  | LOCATION                | MESSAGE         |
diff --git a/features/sync/current_branch/feature_branch/rebase_sync_strategy/upstream/happy_path.feature b/features/sync/current_branch/feature_branch/rebase_sync_strategy/upstream/happy_path.feature
index 1ea6940ee..9a0bda559 100644
--- a/features/sync/current_branch/feature_branch/rebase_sync_strategy/upstream/happy_path.feature
+++ b/features/sync/current_branch/feature_branch/rebase_sync_strategy/upstream/happy_path.feature
@@ -24,6 +24,7 @@ Feature: with upstream repo
       |         | git push                                        |
       |         | git checkout feature                            |
       | feature | git rebase main --no-update-refs                |
+      |         | git rebase origin/feature --no-update-refs      |
       |         | git push --force-with-lease --force-if-includes |
     And all branches are now synchronized
     And the current branch is still "feature"
diff --git a/features/sync/current_branch/feature_branch/rebase_sync_strategy/worktree/conflict_in_linked_worktree.feature b/features/sync/current_branch/feature_branch/rebase_sync_strategy/worktree/conflict_in_linked_worktree.feature
index 412585a0b..1496fc2ed 100644
--- a/features/sync/current_branch/feature_branch/rebase_sync_strategy/worktree/conflict_in_linked_worktree.feature
+++ b/features/sync/current_branch/feature_branch/rebase_sync_strategy/worktree/conflict_in_linked_worktree.feature
@@ -50,7 +50,8 @@ Feature: sync a branch in a "linked worktree" that has a merge conflict
     And I run "git-town continue" in the other worktree
     Then Git Town runs the commands
       | BRANCH  | COMMAND                                         |
-      | feature | git push --force-with-lease --force-if-includes |
+      | feature | git rebase origin/feature --no-update-refs      |
+      |         | git push --force-with-lease --force-if-includes |
     And these commits exist now
       | BRANCH  | LOCATION         | MESSAGE                 | FILE NAME        | FILE CONTENT     |
       | main    | origin           | conflicting main commit | conflicting_file | main content     |
diff --git a/features/sync/current_branch/feature_branch/rebase_sync_strategy/worktree/feature_branch_in_other_worktree.feature b/features/sync/current_branch/feature_branch/rebase_sync_strategy/worktree/feature_branch_in_other_worktree.feature
index 223abca7b..210c0d6ce 100644
--- a/features/sync/current_branch/feature_branch/rebase_sync_strategy/worktree/feature_branch_in_other_worktree.feature
+++ b/features/sync/current_branch/feature_branch/rebase_sync_strategy/worktree/feature_branch_in_other_worktree.feature
@@ -20,7 +20,6 @@ Feature: Sync a feature branch that is in another worktree than the main branch
       | BRANCH  | COMMAND                                         |
       | feature | git fetch --prune --tags                        |
       |         | git rebase origin/main --no-update-refs         |
-      |         | git push --force-with-lease --force-if-includes |
       |         | git rebase origin/feature --no-update-refs      |
       |         | git push --force-with-lease --force-if-includes |
     And the current branch in the other worktree is still "feature"
diff --git a/features/sync/current_branch/feature_branch/rebase_sync_strategy/worktree/happy_path.feature b/features/sync/current_branch/feature_branch/rebase_sync_strategy/worktree/happy_path.feature
index 73c75e20f..3bbda5eb3 100644
--- a/features/sync/current_branch/feature_branch/rebase_sync_strategy/worktree/happy_path.feature
+++ b/features/sync/current_branch/feature_branch/rebase_sync_strategy/worktree/happy_path.feature
@@ -28,7 +28,6 @@ Feature: sync a branch whose parent is active in another worktree
       |        | git push                                        |
       |        | git checkout child                              |
       | child  | git rebase origin/parent --no-update-refs       |
-      |        | git push --force-with-lease --force-if-includes |
       |        | git rebase origin/child --no-update-refs        |
       |        | git push --force-with-lease --force-if-includes |
     And the current branch is still "child"
diff --git a/features/sync/current_branch/feature_branch/rebase_sync_strategy/worktree/parent_in_other_worktree.feature b/features/sync/current_branch/feature_branch/rebase_sync_strategy/worktree/parent_in_other_worktree.feature
index deed32a96..e160148bf 100644
--- a/features/sync/current_branch/feature_branch/rebase_sync_strategy/worktree/parent_in_other_worktree.feature
+++ b/features/sync/current_branch/feature_branch/rebase_sync_strategy/worktree/parent_in_other_worktree.feature
@@ -28,7 +28,6 @@ Feature: sync a branch whose parent is active in another worktree
       |        | git push                                        |
       |        | git checkout child                              |
       | child  | git rebase origin/parent --no-update-refs       |
-      |        | git push --force-with-lease --force-if-includes |
       |        | git rebase origin/child --no-update-refs        |
       |        | git push --force-with-lease --force-if-includes |
     And the current branch is still "child"
diff --git a/features/sync/current_branch/prototype_branch/no_sync_prototype_strategy/feature_sync_strategy_rebase/tracking_branch/conflict.feature b/features/sync/current_branch/prototype_branch/no_sync_prototype_strategy/feature_sync_strategy_rebase/tracking_branch/conflict.feature
index 9ffd5411c..e8963fd14 100644
--- a/features/sync/current_branch/prototype_branch/no_sync_prototype_strategy/feature_sync_strategy_rebase/tracking_branch/conflict.feature
+++ b/features/sync/current_branch/prototype_branch/no_sync_prototype_strategy/feature_sync_strategy_rebase/tracking_branch/conflict.feature
@@ -15,11 +15,10 @@ Feature: handle conflicts between the current prototype branch and its tracking
 
   Scenario: result
     Then Git Town runs the commands
-      | BRANCH    | COMMAND                                         |
-      | prototype | git fetch --prune --tags                        |
-      |           | git rebase main --no-update-refs                |
-      |           | git push --force-with-lease --force-if-includes |
-      |           | git rebase origin/prototype --no-update-refs    |
+      | BRANCH    | COMMAND                                      |
+      | prototype | git fetch --prune --tags                     |
+      |           | git rebase main --no-update-refs             |
+      |           | git rebase origin/prototype --no-update-refs |
     And Git Town prints the error:
       """
       CONFLICT (add/add): Merge conflict in conflicting_file
diff --git a/features/sync/current_branch/prototype_branch/tracking_branch/with.feature b/features/sync/current_branch/prototype_branch/tracking_branch/with.feature
index 68b2ee8e5..e4ecdd98f 100644
--- a/features/sync/current_branch/prototype_branch/tracking_branch/with.feature
+++ b/features/sync/current_branch/prototype_branch/tracking_branch/with.feature
@@ -23,7 +23,6 @@ Feature: sync the current prototype branch that has a tracking branch
       |           | git push                                        |
       |           | git checkout prototype                          |
       | prototype | git rebase main --no-update-refs                |
-      |           | git push --force-with-lease --force-if-includes |
       |           | git rebase origin/prototype --no-update-refs    |
       |           | git push --force-with-lease --force-if-includes |
     And these commits exist now
diff --git a/features/sync/stack/rebase_sync_strategy/branches_gone/ancestor_shipped_and_main_updated.feature b/features/sync/stack/rebase_sync_strategy/branches_gone/ancestor_shipped_and_main_updated.feature
index d6d654c90..60e8c50e3 100644
--- a/features/sync/stack/rebase_sync_strategy/branches_gone/ancestor_shipped_and_main_updated.feature
+++ b/features/sync/stack/rebase_sync_strategy/branches_gone/ancestor_shipped_and_main_updated.feature
@@ -35,25 +35,24 @@ Feature: shipped the head branch of a synced stack with dependent changes while
 
   Scenario: result
     Then Git Town runs the commands
-      | BRANCH   | COMMAND                                         |
-      | branch-4 | git fetch --prune --tags                        |
-      |          | git checkout main                               |
-      | main     | git rebase origin/main --no-update-refs         |
-      |          | git push                                        |
-      |          | git checkout branch-2                           |
-      | branch-2 | git rebase --onto main branch-1                 |
-      |          | git checkout branch-3                           |
-      | branch-3 | git pull                                        |
-      |          | git rebase --onto main branch-2                 |
-      |          | git push --force-with-lease                     |
-      |          | git checkout branch-4                           |
-      | branch-4 | git pull                                        |
-      |          | git rebase --onto main branch-2                 |
-      |          | git push --force-with-lease                     |
-      |          | git rebase branch-3 --no-update-refs            |
-      |          | git push --force-with-lease --force-if-includes |
-      |          | git branch -D branch-1                          |
-      |          | git branch -D branch-2                          |
+      | BRANCH   | COMMAND                                 |
+      | branch-4 | git fetch --prune --tags                |
+      |          | git checkout main                       |
+      | main     | git rebase origin/main --no-update-refs |
+      |          | git push                                |
+      |          | git checkout branch-2                   |
+      | branch-2 | git rebase --onto main branch-1         |
+      |          | git checkout branch-3                   |
+      | branch-3 | git pull                                |
+      |          | git rebase --onto main branch-2         |
+      |          | git push --force-with-lease             |
+      |          | git checkout branch-4                   |
+      | branch-4 | git pull                                |
+      |          | git rebase --onto main branch-2         |
+      |          | git push --force-with-lease             |
+      |          | git rebase branch-3 --no-update-refs    |
+      |          | git branch -D branch-1                  |
+      |          | git branch -D branch-2                  |
     And the current branch is now "branch-4"
     And all branches are now synchronized
     And these commits exist now
diff --git a/features/sync/stack/rebase_sync_strategy/branches_gone/ancestors_missing_all.feature b/features/sync/stack/rebase_sync_strategy/branches_gone/ancestors_missing_all.feature
index a30006f54..5ef7596e7 100644
--- a/features/sync/stack/rebase_sync_strategy/branches_gone/ancestors_missing_all.feature
+++ b/features/sync/stack/rebase_sync_strategy/branches_gone/ancestors_missing_all.feature
@@ -28,7 +28,6 @@ Feature: stacked changes where all ancestor branches aren't local
       |        | git rebase origin/beta --no-update-refs         |
       |        | git rebase origin/alpha --no-update-refs        |
       |        | git rebase origin/main --no-update-refs         |
-      |        | git push --force-with-lease --force-if-includes |
       |        | git rebase origin/gamma --no-update-refs        |
       |        | git push --force-with-lease --force-if-includes |
     And all branches are now synchronized
diff --git a/features/sync/stack/rebase_sync_strategy/branches_gone/ancestors_missing_some.feature b/features/sync/stack/rebase_sync_strategy/branches_gone/ancestors_missing_some.feature
index b9b7d3021..480a23843 100644
--- a/features/sync/stack/rebase_sync_strategy/branches_gone/ancestors_missing_some.feature
+++ b/features/sync/stack/rebase_sync_strategy/branches_gone/ancestors_missing_some.feature
@@ -27,13 +27,11 @@ Feature: stacked changes where an ancestor branch isn't local
       | gamma  | git fetch --prune --tags                        |
       |        | git checkout alpha                              |
       | alpha  | git rebase origin/main --no-update-refs         |
-      |        | git push --force-with-lease --force-if-includes |
       |        | git rebase origin/alpha --no-update-refs        |
       |        | git push --force-with-lease --force-if-includes |
       |        | git checkout gamma                              |
       | gamma  | git rebase origin/beta --no-update-refs         |
       |        | git rebase alpha --no-update-refs               |
-      |        | git push --force-with-lease --force-if-includes |
       |        | git rebase origin/gamma --no-update-refs        |
       |        | git push --force-with-lease --force-if-includes |
     And all branches are now synchronized
diff --git a/features/sync/stack/rebase_sync_strategy/branches_gone/ancestors_shipped.feature b/features/sync/stack/rebase_sync_strategy/branches_gone/ancestors_shipped.feature
index 776375602..2e63637cf 100644
--- a/features/sync/stack/rebase_sync_strategy/branches_gone/ancestors_shipped.feature
+++ b/features/sync/stack/rebase_sync_strategy/branches_gone/ancestors_shipped.feature
@@ -34,24 +34,23 @@ Feature: shipped parent branches in a stacked change
 
   Scenario: result
     Then Git Town runs the commands
-      | BRANCH    | COMMAND                                         |
-      | feature-4 | git fetch --prune --tags                        |
-      |           | git checkout main                               |
-      | main      | git rebase origin/main --no-update-refs         |
-      |           | git checkout feature-2                          |
-      | feature-2 | git rebase --onto main feature-1                |
-      |           | git checkout feature-3                          |
-      | feature-3 | git pull                                        |
-      |           | git rebase --onto main feature-2                |
-      |           | git push --force-with-lease                     |
-      |           | git checkout feature-4                          |
-      | feature-4 | git pull                                        |
-      |           | git rebase --onto main feature-2                |
-      |           | git push --force-with-lease                     |
-      |           | git rebase feature-3 --no-update-refs           |
-      |           | git push --force-with-lease --force-if-includes |
-      |           | git branch -D feature-1                         |
-      |           | git branch -D feature-2                         |
+      | BRANCH    | COMMAND                                 |
+      | feature-4 | git fetch --prune --tags                |
+      |           | git checkout main                       |
+      | main      | git rebase origin/main --no-update-refs |
+      |           | git checkout feature-2                  |
+      | feature-2 | git rebase --onto main feature-1        |
+      |           | git checkout feature-3                  |
+      | feature-3 | git pull                                |
+      |           | git rebase --onto main feature-2        |
+      |           | git push --force-with-lease             |
+      |           | git checkout feature-4                  |
+      | feature-4 | git pull                                |
+      |           | git rebase --onto main feature-2        |
+      |           | git push --force-with-lease             |
+      |           | git rebase feature-3 --no-update-refs   |
+      |           | git branch -D feature-1                 |
+      |           | git branch -D feature-2                 |
     And Git Town prints:
       """
       deleted branch "feature-1"
diff --git a/features/sync/stack/rebase_sync_strategy/branches_gone/parent_shipped_remotely_and_deleted_locally.feature b/features/sync/stack/rebase_sync_strategy/branches_gone/parent_shipped_remotely_and_deleted_locally.feature
index b16bcfe10..be2b6b5b4 100644
--- a/features/sync/stack/rebase_sync_strategy/branches_gone/parent_shipped_remotely_and_deleted_locally.feature
+++ b/features/sync/stack/rebase_sync_strategy/branches_gone/parent_shipped_remotely_and_deleted_locally.feature
@@ -24,6 +24,7 @@ Feature: syncing a branch whose parent was shipped and the local branch deleted
       | main   | git rebase origin/main --no-update-refs         |
       |        | git checkout child                              |
       | child  | git rebase main --no-update-refs                |
+      |        | git rebase origin/child --no-update-refs        |
       |        | git push --force-with-lease --force-if-includes |
     And the current branch is still "child"
     And the branches are now
diff --git a/features/sync/stack/rebase_sync_strategy/detached/detached.feature b/features/sync/stack/rebase_sync_strategy/detached/detached.feature
index b1f1ec00d..5edff1ce3 100644
--- a/features/sync/stack/rebase_sync_strategy/detached/detached.feature
+++ b/features/sync/stack/rebase_sync_strategy/detached/detached.feature
@@ -38,12 +38,13 @@ Feature: sync the entire stack
       | BRANCH | COMMAND                                         |
       | alpha  | git fetch --prune --tags                        |
       |        | git rebase main --no-update-refs                |
-      |        | git push --force-with-lease --force-if-includes |
       |        | git checkout beta                               |
       | beta   | git rebase alpha --no-update-refs               |
+      |        | git rebase origin/beta --no-update-refs         |
       |        | git push --force-with-lease --force-if-includes |
       |        | git checkout gamma                              |
       | gamma  | git rebase beta --no-update-refs                |
+      |        | git rebase origin/gamma --no-update-refs        |
       |        | git push --force-with-lease --force-if-includes |
       |        | git checkout alpha                              |
     And the current branch is still "alpha"
@@ -52,7 +53,10 @@ Feature: sync the entire stack
       | main       | origin        | main commit              |
       | alpha      | local, origin | alpha commit             |
       | beta       | local, origin | beta commit              |
+      |            |               | alpha commit             |
       | gamma      | local, origin | gamma commit             |
+      |            |               | beta commit              |
+      |            |               | alpha commit             |
       | observed   | local         | local observed commit    |
       |            | origin        | origin observed commit   |
       | one        | local, origin | one commit               |
diff --git a/features/sync/stack/rebase_sync_strategy/git_rebase_updaterefs/enabled.feature b/features/sync/stack/rebase_sync_strategy/git_rebase_updaterefs/enabled.feature
index 7632b8e5b..97085eecc 100644
--- a/features/sync/stack/rebase_sync_strategy/git_rebase_updaterefs/enabled.feature
+++ b/features/sync/stack/rebase_sync_strategy/git_rebase_updaterefs/enabled.feature
@@ -28,12 +28,10 @@ Feature: stacked changes
       |        | git push                                        |
       |        | git checkout parent                             |
       | parent | git rebase main --no-update-refs                |
-      |        | git push --force-with-lease --force-if-includes |
       |        | git rebase origin/parent --no-update-refs       |
       |        | git push --force-with-lease --force-if-includes |
       |        | git checkout child                              |
       | child  | git rebase parent --no-update-refs              |
-      |        | git push --force-with-lease --force-if-includes |
       |        | git rebase origin/child --no-update-refs        |
       |        | git push --force-with-lease --force-if-includes |
     And all branches are now synchronized
diff --git a/features/sync/stack/rebase_sync_strategy/independent_changes.feature b/features/sync/stack/rebase_sync_strategy/independent_changes.feature
index ae262e386..29b5a1262 100644
--- a/features/sync/stack/rebase_sync_strategy/independent_changes.feature
+++ b/features/sync/stack/rebase_sync_strategy/independent_changes.feature
@@ -27,12 +27,10 @@ Feature: stacked changes where each branch makes independent changes
       |        | git push                                        |
       |        | git checkout parent                             |
       | parent | git rebase main --no-update-refs                |
-      |        | git push --force-with-lease --force-if-includes |
       |        | git rebase origin/parent --no-update-refs       |
       |        | git push --force-with-lease --force-if-includes |
       |        | git checkout child                              |
       | child  | git rebase parent --no-update-refs              |
-      |        | git push --force-with-lease --force-if-includes |
       |        | git rebase origin/child --no-update-refs        |
       |        | git push --force-with-lease --force-if-includes |
     And all branches are now synchronized
diff --git a/internal/cmd/sync/sync_feature_branch.go b/internal/cmd/sync/sync_feature_branch.go
index a298204f7..1519fbe7c 100644
--- a/internal/cmd/sync/sync_feature_branch.go
+++ b/internal/cmd/sync/sync_feature_branch.go
@@ -84,8 +84,9 @@ func FeatureTrackingBranchProgram(trackingBranch gitdomain.RemoteBranchName, syn
 		if args.Offline.IsFalse() {
 			args.Program.Value.Add(
 				&opcodes.RebaseTrackingBranch{
-					RemoteBranch: trackingBranch,
-					PushBranches: args.PushBranches,
+					RemoteBranch:  trackingBranch,
+					PushBranches:  args.PushBranches,
+					CurrentBranch: args.LocalName,
 				},
 			)
 		}
diff --git a/internal/vm/opcodes/rebase_tracking_branch.go b/internal/vm/opcodes/rebase_tracking_branch.go
index d3e8e37a1..ee2abd754 100644
--- a/internal/vm/opcodes/rebase_tracking_branch.go
+++ b/internal/vm/opcodes/rebase_tracking_branch.go
@@ -8,32 +8,31 @@ import (
 
 // RebaseTrackingBranch rebases the current feature branch against its tracking branch.
 type RebaseTrackingBranch struct {
+	CurrentBranch           gitdomain.LocalBranchName
 	PushBranches            configdomain.PushBranches
 	RemoteBranch            gitdomain.RemoteBranchName
 	undeclaredOpcodeMethods `exhaustruct:"optional"`
 }
 
 func (self *RebaseTrackingBranch) Run(args shared.RunArgs) error {
-	// Try to force-push the local branch with lease and includes to the remote branch.
+	inSync, err := args.Git.BranchInSyncWithTracking(args.Backend, self.CurrentBranch, args.Config.Value.NormalConfig.DevRemote)
+	if err != nil {
+		return err
+	}
+	if inSync {
+		return nil
+	}
+	opcodes := []shared.Opcode{
+		&RebaseBranch{
+			Branch:                  self.RemoteBranch.BranchName(),
+			undeclaredOpcodeMethods: undeclaredOpcodeMethods{},
+		},
+	}
 	if self.PushBranches {
-		err := args.Git.ForcePushBranchSafely(args.Frontend, args.Config.Value.NormalConfig.NoPushHook(), true)
-		if err == nil {
-			// The force-push succeeded --> the remote branch didn't contain new commits, we are done.
-			return nil
-		}
-		// Here the force-push failed --> the remote branch contains new commits.
-		// We need to integrate them into the local branch.
-		args.PrependOpcodes(
-			// Rebase the local commits against the remote commits.
-			&RebaseBranch{Branch: self.RemoteBranch.BranchName()},
-			// Now try force-pushing again.
-			&RebaseTrackingBranch{
-				PushBranches: self.PushBranches,
-				RemoteBranch: self.RemoteBranch,
-			},
-		)
-	} else {
-		args.PrependOpcodes(&RebaseBranch{Branch: self.RemoteBranch.BranchName()})
+		opcodes = append(opcodes, &PushCurrentBranchForceIfNeeded{
+			ForceIfIncludes: true,
+		})
 	}
+	args.PrependOpcodes(opcodes...)
 	return nil
 }



Test patch:
diff --git a/internal/vm/statefile/save_load_test.go b/internal/vm/statefile/save_load_test.go
index f0df49827..e42362a94 100644
--- a/internal/vm/statefile/save_load_test.go
+++ b/internal/vm/statefile/save_load_test.go
@@ -118,7 +118,7 @@ func TestLoadSave(t *testing.T) {
 				&opcodes.RebaseOntoKeepDeleted{BranchToRebaseOnto: "branch-2", CommitsToRemove: "branch-1"},
 				&opcodes.RebaseOntoRemoveDeleted{BranchToRebaseOnto: "branch-2", CommitsToRemove: "branch-1", Upstream: Some(gitdomain.NewLocalBranchName("upstream"))},
 				&opcodes.RebaseParentIfNeeded{Branch: "branch"},
-				&opcodes.RebaseTrackingBranch{RemoteBranch: "origin/branch"},
+				&opcodes.RebaseTrackingBranch{RemoteBranch: "origin/branch", CurrentBranch: "branch", PushBranches: true},
 				&opcodes.RegisterUndoablePerennialCommit{Parent: "parent"},
 				&opcodes.SnapshotInitialUpdateLocalSHA{Branch: "branch", SHA: "111111"},
 				&opcodes.SnapshotInitialUpdateLocalSHAIfNeeded{Branch: "branch"},
@@ -622,7 +622,8 @@ func TestLoadSave(t *testing.T) {
     },
     {
       "data": {
-        "PushBranches": false,
+        "CurrentBranch": "branch",
+        "PushBranches": true,
         "RemoteBranch": "origin/branch"
       },
       "type": "RebaseTrackingBranch"