diff --git a/git_review/cmd.py b/git_review/cmd.py index e4b2dd5b..094abbae 100644 --- a/git_review/cmd.py +++ b/git_review/cmd.py @@ -900,7 +900,7 @@ def check_remote(branch, remote, scheme, hostname, port, project, raise -def rebase_changes(branch, remote, interactive=True): +def rebase_changes(branch, remote, interactive=True, keep=False): global _orig_head @@ -959,17 +959,35 @@ def rebase_changes(branch, remote, interactive=True): print("Errors running %s" % cmd) if interactive: print(output) - printwrap("It is likely that your change has a merge conflict. " - "You may resolve it in the working tree now as " - "described above and then run 'git review' again, or " - "if you do not want to resolve it yet (note that the " - "change can not merge until the conflict is resolved) " - "you may run 'git rebase --abort' then 'git review -R' " - "to upload the change without rebasing.") + if keep: + printwrap("It is likely that your change has a merge " + "conflict. You may resolve it in the working tree " + "now as described above and then run 'git review' " + "again, or if you do not want to resolve it yet " + "(note that the change can not merge until the " + "conflict is resolved) you may run 'git rebase " + "--abort' then 'git review -R' to upload the change " + "without rebasing.") + else: + printwrap("It is likely that your change has a merge " + "conflict, but the result of the test rebase has " + "been discarded. You may rebase it yourself and " + "review again, or use 'git review -R' to upload the " + "change without resolving the conflict, or use the " + "--keep-rebase option to leave the incomplete " + "rebase result in your working tree.") return False return True +def abort_rebase(): + cmd = "git rebase --abort" + (status, output) = run_command_status(cmd) + if status != 0: + print("Errors running %s" % cmd) + print(output) + + def undo_rebase(): global _orig_head if not _orig_head: @@ -1546,6 +1564,10 @@ additional information: action="store_true", help="Force and push a rebase even when not" " needed.") + rebase_group.add_argument("-K", "--keep-rebase", dest="keep_rebase", + action="store_true", + help="Keep the unfinished test rebase if a " + " merge conflict is detected.") track_group = parser.add_mutually_exclusive_group() track_group.add_argument("--track", dest="track", @@ -1768,7 +1790,9 @@ additional information: return if options.rebase or options.force_rebase: - if not rebase_changes(branch, remote): + if not rebase_changes(branch, remote, keep=options.keep_rebase): + if not options.keep_rebase: + abort_rebase() sys.exit(1) if not options.force_rebase and not undo_rebase(): sys.exit(1) diff --git a/git_review/tests/test_git_review.py b/git_review/tests/test_git_review.py index dcb92323..e437ea1e 100644 --- a/git_review/tests/test_git_review.py +++ b/git_review/tests/test_git_review.py @@ -328,8 +328,25 @@ class GitReviewTestCase(tests.BaseGitReviewTestCase): "Errors running git rebase --preserve-merges " "-i remotes/%s/master" % self._remote in exc.args[0]) self.assertTrue(rebased) - self.assertIn("It is likely that your change has a merge conflict.", + self.assertIn("It is likely that your change has a merge conflict", exc.args[0]) + output = self._run_git('rebase', '--abort') + self.assertIn("fatal: No rebase in progress?", output) + + def test_keep_aborted_rebase_state(self): + """Test git-review -K behavior when rebase is needed.""" + self._run_git_review('-s') + head_1 = self._run_git('rev-parse', 'HEAD^1') + + self._run_git('checkout', '-b', 'test_branch', head_1) + + self._simple_change('some other message', + 'create conflict with master') + + self._run_git_review('-K') + output = self._run_git('status') + self.assertIn( + "You are currently editing a commit while rebasing", output) def test_upload_without_rebase(self): """Test change not needing a rebase can upload without rebasing."""