diff --git a/cherry_picker/cherry_picker.py b/cherry_picker/cherry_picker.py index a71a1ac..61919af 100755 --- a/cherry_picker/cherry_picker.py +++ b/cherry_picker/cherry_picker.py @@ -516,6 +516,12 @@ def cleanup_branch(self, branch): print(f"branch {branch} NOT deleted.") set_state(WORKFLOW_STATES.REMOVING_BACKPORT_BRANCH_FAILED) return + # Remember where the branch points so that the user can restore it, + # for example if pushing it failed and manual work would be lost. + try: + branch_sha = get_sha1_from(branch) + except ValueError: + branch_sha = None try: self.delete_branch(branch) except subprocess.CalledProcessError: @@ -523,6 +529,9 @@ def cleanup_branch(self, branch): set_state(WORKFLOW_STATES.REMOVING_BACKPORT_BRANCH_FAILED) else: print(f"branch {branch} has been deleted.") + if branch_sha: + print("To restore it, run:") + print(f"git branch {branch} {branch_sha}") set_state(WORKFLOW_STATES.REMOVED_BACKPORT_BRANCH) def unset_upstream(self, branch): diff --git a/cherry_picker/test_cherry_picker.py b/cherry_picker/test_cherry_picker.py index 35e8e14..a72f1a4 100644 --- a/cherry_picker/test_cherry_picker.py +++ b/cherry_picker/test_cherry_picker.py @@ -838,7 +838,7 @@ def _fetch(cmd, *args, **kwargs): assert get_state() == end_state -def test_cleanup_branch(tmp_git_repo_dir, git_checkout): +def test_cleanup_branch(tmp_git_repo_dir, git_checkout, capsys): assert get_state() == WORKFLOW_STATES.UNSET with mock.patch("cherry_picker.cherry_picker.validate_sha", return_value=True): @@ -846,9 +846,13 @@ def test_cleanup_branch(tmp_git_repo_dir, git_checkout): assert get_state() == WORKFLOW_STATES.UNSET git_checkout("-b", "some_branch") + branch_sha = get_sha1_from("some_branch") cherry_picker.cleanup_branch("some_branch") assert get_state() == WORKFLOW_STATES.REMOVED_BACKPORT_BRANCH assert get_current_branch() == "main" + out = capsys.readouterr().out + assert "branch some_branch has been deleted." in out + assert f"To restore it, run:\ngit branch some_branch {branch_sha}\n" in out def test_cleanup_branch_checkout_previous_branch( @@ -868,7 +872,7 @@ def test_cleanup_branch_checkout_previous_branch( assert get_current_branch() == "previous_branch" -def test_cleanup_branch_fail(tmp_git_repo_dir): +def test_cleanup_branch_fail(tmp_git_repo_dir, capsys): assert get_state() == WORKFLOW_STATES.UNSET with mock.patch("cherry_picker.cherry_picker.validate_sha", return_value=True): @@ -877,6 +881,9 @@ def test_cleanup_branch_fail(tmp_git_repo_dir): cherry_picker.cleanup_branch("some_branch") assert get_state() == WORKFLOW_STATES.REMOVING_BACKPORT_BRANCH_FAILED + out = capsys.readouterr().out + assert "branch some_branch NOT deleted." in out + assert "To restore it" not in out def test_cleanup_branch_checkout_fail(