chore(release): use force push and clean up git helpers in prep tool (#3873)

This change fixes an edge case in the release preparation tool by using
force push when pushing the preparation branch, resolving failures when
the remote branch already exists. It also cleans up git helpers to use
long option names and fail-fast on errors, with corresponding test
updates.
diff --git a/tests/tools/private/release/release_test.py b/tests/tools/private/release/release_test.py
index a1467d8..293b82b 100644
--- a/tests/tools/private/release/release_test.py
+++ b/tests/tools/private/release/release_test.py
@@ -591,6 +591,10 @@
         self.mock_get_latest_version = patch(
             "tools.private.release.utils.get_latest_version"
         ).start()
+        self.mock_get_current_branch = patch(
+            "tools.private.release.git.get_current_branch"
+        ).start()
+        self.mock_get_current_branch.return_value = "main"
         self.addCleanup(patch.stopall)
 
     def test_no_markers(self):
@@ -825,7 +829,7 @@
         self.mock_git.checkout.assert_called_once_with("prepare-2.0.0")
         self.mock_git.commit.assert_not_called()
         self.mock_git.push.assert_called_once_with(
-            "origin", "prepare-2.0.0", set_upstream=True
+            "origin", "prepare-2.0.0", set_upstream=True, force=True
         )
         self.mock_gh.get_open_pr.assert_called_once_with("prepare-2.0.0")
         self.mock_gh.create_pr.assert_not_called()  # Should NOT create a new PR
@@ -855,7 +859,7 @@
         self.mock_git.checkout.assert_called_once_with("prepare-2.0.0")
         self.mock_git.commit.assert_not_called()
         self.mock_git.push.assert_called_once_with(
-            "origin", "prepare-2.0.0", set_upstream=True
+            "origin", "prepare-2.0.0", set_upstream=True, force=True
         )
         self.mock_gh.get_open_pr.assert_called_once_with("prepare-2.0.0")
         self.mock_gh.create_pr.assert_called_once_with("2.0.0", 123)
@@ -886,7 +890,7 @@
         self.mock_git.checkout.assert_called_once_with("prepare-2.0.0")
         self.mock_git.commit.assert_not_called()
         self.mock_git.push.assert_called_once_with(
-            "origin", "prepare-2.0.0", set_upstream=True
+            "origin", "prepare-2.0.0", set_upstream=True, force=True
         )
         self.mock_gh.get_open_pr.assert_called_once_with("prepare-2.0.0")
         self.mock_gh.create_pr.assert_not_called()
diff --git a/tools/private/release/git.py b/tools/private/release/git.py
index 9c2662d..ed6e637 100644
--- a/tools/private/release/git.py
+++ b/tools/private/release/git.py
@@ -41,11 +41,13 @@
     run_cmd(*cmd, capture_output=False)
 
 
-def push(remote, ref, set_upstream=False):
+def push(remote, ref, set_upstream=False, force=False):
     """Pushes a reference to a remote repository."""
     cmd = ["git", "push"]
     if set_upstream:
-        cmd.append("-u")
+        cmd.append("--set-upstream")
+    if force:
+        cmd.append("--force")
     cmd.extend([remote, ref])
     run_cmd(*cmd, capture_output=False)
 
@@ -128,8 +130,5 @@
 
 
 def get_current_branch():
-    """Returns the current git branch name, or None if not in a git repo."""
-    try:
-        return run_cmd("git", "rev-parse", "--abbrev-ref", "HEAD")
-    except subprocess.CalledProcessError:
-        return None
+    """Returns the current git branch name."""
+    return run_cmd("git", "rev-parse", "--abbrev-ref", "HEAD")
diff --git a/tools/private/release/prepare.py b/tools/private/release/prepare.py
index c9012e0..2d32ee4 100644
--- a/tools/private/release/prepare.py
+++ b/tools/private/release/prepare.py
@@ -113,7 +113,8 @@
             print("No files modified by the release tool. Nothing to commit.")
 
         print(f"Pushing branch {branch_name} to origin...")
-        git.push("origin", branch_name, set_upstream=True)
+        # Force push to overwrite the remote branch if it already exists (e.g. from a previous run)
+        git.push("origin", branch_name, set_upstream=True, force=True)
 
     # --- Create PR ---
     # Determine if we need to create a PR or reuse an existing one