diff --git a/core/commands/branch.py b/core/commands/branch.py index c7548f289..f8ec471e8 100644 --- a/core/commands/branch.py +++ b/core/commands/branch.py @@ -32,6 +32,12 @@ GitSavvy: Deleted branch ({0}), in case you want to undo, run: $ git branch {0} {1} """ +BRANCH_ALREADY_EXISTS_MESSAGE = "a branch named '{0}' already exists" +RECREATE_BRANCH_UNDO_MESSAGE = """\ +GitSavvy: Re-created branch '{0}', in case you want to undo, run: + $ git branch --force {0} {1} +""" + EXTRACT_COMMIT = re.compile(r"\(was (.+)\)") NOT_MERGED_WARNING = re.compile(r"The branch.*is not fully merged\.") CANT_DELETE_CURRENT_BRANCH = re.compile(r"Cannot delete branch .+ checked out at ") @@ -79,9 +85,40 @@ class gs_create_branch(GsWindowCommand): "branch_name": ask_for_name(), } - def run(self, branch_name, start_point=None): - # type: (str, str) -> None - self.git("branch", branch_name, start_point) + def run(self, branch_name, start_point=None, force=False): + # type: (str, str, bool) -> None + try: + self.git_throwing_silently( + "branch", + "--force" if force else None, + branch_name, + start_point + ) + except GitSavvyError as e: + if BRANCH_ALREADY_EXISTS_MESSAGE.format(branch_name) in e.stderr and not force: + def overwrite_action(): + old_hash = self.git("rev-parse", branch_name).strip() + uprint(RECREATE_BRANCH_UNDO_MESSAGE.format(branch_name, old_hash)) + + self.window.run_command("gs_create_branch", { + "branch_name": branch_name, + "start_point": start_point, + "force": True, + }) + + show_actions_panel(self.window, [ + noop(f"Abort, a branch named '{branch_name}' already exists."), + ( + f'Re-create the branch at {start_point or "HEAD"}.', + overwrite_action + ) + ]) + return + + else: + e.show_error_panel() + raise + self.window.status_message("Created {}{}".format( branch_name, " at {}".format(start_point) if start_point else "") diff --git a/core/commands/checkout.py b/core/commands/checkout.py index 3b136a79a..330a58a50 100644 --- a/core/commands/checkout.py +++ b/core/commands/checkout.py @@ -8,13 +8,13 @@ from .log import LogMixin from ..git_command import GitCommand, GitSavvyError from ..ui_mixins.quick_panel import show_branch_panel +from ..utils import uprint from ..view import replace_view_content from ...common import util from GitSavvy.core import store from GitSavvy.core.base_commands import ask_for_branch, GsWindowCommand from GitSavvy.core.utils import noop, show_actions_panel - __all__ = ( "gs_checkout_branch", "gs_checkout_new_branch", @@ -25,6 +25,11 @@ DIRTY_WORKTREE_MESSAGE = "Please commit your changes or stash them before you switch branches" +BRANCH_ALREADY_EXISTS_MESSAGE = "a branch named '{0}' already exists" +RECREATE_BRANCH_UNDO_MESSAGE = """\ +GitSavvy: Re-created branch '{0}', in case you want to undo, run: + $ git checkout -B {0} {1} +""" class gs_checkout_branch(WindowCommand, GitCommand): @@ -105,6 +110,28 @@ def run(self, branch_name, start_point=None, force=False, merge=False): ) ]) return + + elif BRANCH_ALREADY_EXISTS_MESSAGE.format(branch_name) in e.stderr and not force: + def overwrite_action(): + old_hash = self.git("rev-parse", branch_name).strip() + uprint(RECREATE_BRANCH_UNDO_MESSAGE.format(branch_name, old_hash)) + + self.window.run_command("gs_checkout_new_branch", { + "branch_name": branch_name, + "start_point": start_point, + "force": True, + "merge": merge + }) + + show_actions_panel(self.window, [ + noop(f"Abort, a branch named '{branch_name}' already exists."), + ( + f'Re-create the branch at {start_point or "HEAD"}.', + overwrite_action + ) + ]) + return + else: e.show_error_panel() raise