From 5213cc704dc8524a121253e10e99267692e2f51a Mon Sep 17 00:00:00 2001 From: Pawel Lipski Date: Tue, 24 Sep 2024 15:33:58 +0200 Subject: [PATCH] Add `-H`/`--sync-github-prs` and `-L`/`--sync-gitlab-mrs` flags to `traverse` --- RELEASE_NOTES.md | 4 +- completion/git-machete.completion.bash | 4 +- completion/git-machete.completion.zsh | 2 + completion/git-machete.fish | 34 +++++++------ docs/man/git-machete.1 | 18 ++++++- docs/source/cli/traverse.rst | 12 +++++ git_machete/__init__.py | 2 +- git_machete/cli.py | 14 ++++-- git_machete/client.py | 56 ++++++++++++++++++++- git_machete/generated_docs.py | 10 ++++ tests/completion_e2e/test_completion_e2e.py | 12 +++-- 11 files changed, 137 insertions(+), 31 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index d393e6308..eac08d5fe 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,6 +1,8 @@ # Release notes -## New in git-machete 3.31.2 +## New in git-machete 3.32.0 + +- added: flags `-H`/`--sync-github-prs` and `-L`/`--sync-gitlab-mrs` to `traverse` to automatically retarget PRs/MRs when traversing (suggested by @chriscz) ## New in git-machete 3.31.1 diff --git a/completion/git-machete.completion.bash b/completion/git-machete.completion.bash index 3f104747f..7a9806a9f 100644 --- a/completion/git-machete.completion.bash +++ b/completion/git-machete.completion.bash @@ -17,7 +17,7 @@ _git_machete() { local common_opts="--debug -h --help -v --verbose" local add_opts="-f --as-first-child -o --onto= -R --as-root -y --yes" local advance_opts="-y --yes" - local anno_opts="-b --branch= -H -L --sync-github-prs --sync-gitlab-mrs" + local anno_opts="-b --branch= -H --sync-github-prs -L --sync-gitlab-mrs" local delete_unmanaged_opts="-y --yes" local diff_opts="-s --stat" local discover_opts="-C --checked-out-since= -l --list-commits -r --roots= -y --yes" @@ -32,7 +32,7 @@ _git_machete() { local slide_out_opts="-d --down-fork-point= --delete -M --merge -n --no-edit-merge --no-interactive-rebase --removed-from-remote" local squash_opts="-f --fork-point=" local status_opts="--color= -L --list-commits-with-hashes -l --list-commits --no-detect-squash-merges" - local traverse_opts="-F --fetch -l --list-commits -M --merge -n --no-detect-squash-merges --no-edit-merge --no-interactive-rebase --no-push --no-push-untracked --push --push-untracked --return-to= --start-from= -w --whole -W -y --yes" + local traverse_opts="-F --fetch -H --sync-github-prs -L --sync-gitlab-mrs -l --list-commits -M --merge -n --no-detect-squash-merges --no-edit-merge --no-interactive-rebase --no-push --no-push-untracked --push --push-untracked --return-to= --start-from= -w --whole -W -y --yes" local update_opts="-f --fork-point= -M --merge -n --no-edit-merge --no-interactive-rebase" cur=${COMP_WORDS[$COMP_CWORD]} diff --git a/completion/git-machete.completion.zsh b/completion/git-machete.completion.zsh index 99b3ceb59..a8eaf7d35 100644 --- a/completion/git-machete.completion.zsh +++ b/completion/git-machete.completion.zsh @@ -140,6 +140,8 @@ _git-machete() { (t|traverse) _arguments \ '(-F --fetch)'{-F,--fetch}'[Fetch the remotes of all managed branches at the beginning of traversal]' \ + '(-H --sync-github-prs)'{-H,--sync-github-prs}'[Retarget GitHub PR when its base branch is different than in machete file]' \ + '(-L --sync-gitlab-mrs)'{-L,--sync-gitlab-mrs}'[Retarget GitLab MR when its target branch is different than in machete file]' \ '(-l --list-commits)'{-l,--list-commits}'[List the messages of commits introduced on each branch]' \ '(-M --merge)'{-M,--merge}'[Update by merge rather than by rebase]' \ '(-n)'-n'[If updating by rebase, equivalent to --no-interactive-rebase. If updating by merge, equivalent to --no-edit-merge]' \ diff --git a/completion/git-machete.fish b/completion/git-machete.fish index 7cd803fb2..18f287b05 100644 --- a/completion/git-machete.fish +++ b/completion/git-machete.fish @@ -213,22 +213,24 @@ complete -c git-machete -n "__fish_seen_subcommand_from status s; and not __fish # git machete traverse complete -c git-machete -n "not __fish_seen_subcommand_from $__machete_commands" -f -a traverse -d 'Walk through the tree of branch dependencies and rebase, merge, slide out, push and/or pull each branch one by one' -complete -c git-machete -n "__fish_seen_subcommand_from traverse t; and not __fish_seen_subcommand_from --fetch -F" -f -l fetch -s F -d 'Fetch the remotes of all managed branches at the beginning of traversal (no git pull involved, only git fetch)' -complete -c git-machete -n "__fish_seen_subcommand_from traverse t; and not __fish_seen_subcommand_from --list-commits -l" -f -l list-commits -s l -d 'When printing the status, additionally list the messages of commits introduced on each branch' -complete -c git-machete -n "__fish_seen_subcommand_from traverse t; and not __fish_seen_subcommand_from --merge -M" -f -l merge -s M -d 'Update by merge rather than by rebase' -complete -c git-machete -n "__fish_seen_subcommand_from traverse t; and not __fish_seen_subcommand_from --yes -y" -f -s n -d 'If updating by rebase, equivalent to --no-interactive-rebase. If updating by merge, equivalent to --no-edit-merge' -complete -c git-machete -n "__fish_seen_subcommand_from traverse t; and not __fish_seen_subcommand_from --no-detect-squash-merges" -f -l no-detect-squash-merges -d 'Only consider "strict" (fast-forward or 2-parent) merges, rather than rebase/squash merges, when detecting if a branch is merged into its upstream (parent)' -complete -c git-machete -n "__fish_seen_subcommand_from traverse t; and not __fish_seen_subcommand_from --no-edit-merge" -f -l no-edit-merge -d 'If updating by merge, skip opening the editor for merge commit message while doing git merge (i.e. pass --no-edit flag to underlying git merge). Not allowed if updating by rebase' -complete -c git-machete -n "__fish_seen_subcommand_from traverse t; and not __fish_seen_subcommand_from --no-interactive-rebase" -f -l no-interactive-rebase -d 'If updating by rebase, run git rebase in non-interactive mode (without -i/--interactive flag). Not allowed if updating by merge' -complete -c git-machete -n "__fish_seen_subcommand_from traverse t; and not __fish_seen_subcommand_from --no-push" -f -l no-push -d 'Do not push any (neither tracked nor untracked) branches to remote, re-enable via --push' -complete -c git-machete -n "__fish_seen_subcommand_from traverse t; and not __fish_seen_subcommand_from --no-push-untracked" -f -l no-push-untracked -d 'Do not push untracked branches to remote, re-enable via --push-untracked' -complete -c git-machete -n "__fish_seen_subcommand_from traverse t; and not __fish_seen_subcommand_from --push" -f -l push -d 'Push all (both tracked and untracked) branches to remote - default behavior' -complete -c git-machete -n "__fish_seen_subcommand_from traverse t; and not __fish_seen_subcommand_from --push-untracked" -f -l push-untracked -d 'Push untracked branches to remote - default behavior' -complete -c git-machete -n "__fish_seen_subcommand_from traverse t; and not __fish_seen_subcommand_from --return-to" -x -l return-to -a 'stay here nearest-remaining' -d 'Specifies the branch to return after traversal is successfully completed' -complete -c git-machete -n "__fish_seen_subcommand_from traverse t; and not __fish_seen_subcommand_from --start-from" -x -l start-from -a 'here root first-root' -d 'Specifies the branch to start the traversal from' -complete -c git-machete -n "__fish_seen_subcommand_from traverse t; and not __fish_seen_subcommand_from --whole -w" -f -l whole -s w -d 'Equivalent to -n --start-from=first-root --return-to=nearest-remaining' -complete -c git-machete -n "__fish_seen_subcommand_from traverse t; and not __fish_seen_subcommand_from -W" -f -s W -d 'Equivalent to --fetch --whole; useful for even more automated traversal of all branches' -complete -c git-machete -n "__fish_seen_subcommand_from traverse t; and not __fish_seen_subcommand_from --yes -y" -f -l yes -s y -d 'Do not ask for any interactive input, including confirmation of rebase/push/pull. Implies -n' +complete -c git-machete -n "__fish_seen_subcommand_from traverse t; and not __fish_seen_subcommand_from --fetch -F" -f -l fetch -s F -d 'Fetch the remotes of all managed branches at the beginning of traversal (no git pull involved, only git fetch)' +complete -c git-machete -n "__fish_seen_subcommand_from traverse t; and not __fish_seen_subcommand_from --list-commits -l" -f -l list-commits -s l -d 'When printing the status, additionally list the messages of commits introduced on each branch' +complete -c git-machete -n "__fish_seen_subcommand_from traverse t; and not __fish_seen_subcommand_from --sync-gitlab-mrs" -f -l sync-github-prs -s H -d 'Retarget GitHub PR when its base branch is different than in machete file' +complete -c git-machete -n "__fish_seen_subcommand_from traverse t; and not __fish_seen_subcommand_from --sync-github-prs" -f -l sync-gitlab-mrs -s L -d 'Retarget GitLab MR when its target branch is different than in machete file' +complete -c git-machete -n "__fish_seen_subcommand_from traverse t; and not __fish_seen_subcommand_from --merge -M" -f -l merge -s M -d 'Update by merge rather than by rebase' +complete -c git-machete -n "__fish_seen_subcommand_from traverse t; and not __fish_seen_subcommand_from --yes -y" -f -s n -d 'If updating by rebase, equivalent to --no-interactive-rebase. If updating by merge, equivalent to --no-edit-merge' +complete -c git-machete -n "__fish_seen_subcommand_from traverse t; and not __fish_seen_subcommand_from --no-detect-squash-merges" -f -l no-detect-squash-merges -d 'Only consider "strict" (fast-forward or 2-parent) merges, rather than rebase/squash merges, when detecting if a branch is merged into its upstream (parent)' +complete -c git-machete -n "__fish_seen_subcommand_from traverse t; and not __fish_seen_subcommand_from --no-edit-merge" -f -l no-edit-merge -d 'If updating by merge, skip opening the editor for merge commit message while doing git merge (i.e. pass --no-edit flag to underlying git merge). Not allowed if updating by rebase' +complete -c git-machete -n "__fish_seen_subcommand_from traverse t; and not __fish_seen_subcommand_from --no-interactive-rebase" -f -l no-interactive-rebase -d 'If updating by rebase, run git rebase in non-interactive mode (without -i/--interactive flag). Not allowed if updating by merge' +complete -c git-machete -n "__fish_seen_subcommand_from traverse t; and not __fish_seen_subcommand_from --no-push" -f -l no-push -d 'Do not push any (neither tracked nor untracked) branches to remote, re-enable via --push' +complete -c git-machete -n "__fish_seen_subcommand_from traverse t; and not __fish_seen_subcommand_from --no-push-untracked" -f -l no-push-untracked -d 'Do not push untracked branches to remote, re-enable via --push-untracked' +complete -c git-machete -n "__fish_seen_subcommand_from traverse t; and not __fish_seen_subcommand_from --push" -f -l push -d 'Push all (both tracked and untracked) branches to remote - default behavior' +complete -c git-machete -n "__fish_seen_subcommand_from traverse t; and not __fish_seen_subcommand_from --push-untracked" -f -l push-untracked -d 'Push untracked branches to remote - default behavior' +complete -c git-machete -n "__fish_seen_subcommand_from traverse t; and not __fish_seen_subcommand_from --return-to" -x -l return-to -a 'stay here nearest-remaining' -d 'Specifies the branch to return after traversal is successfully completed' +complete -c git-machete -n "__fish_seen_subcommand_from traverse t; and not __fish_seen_subcommand_from --start-from" -x -l start-from -a 'here root first-root' -d 'Specifies the branch to start the traversal from' +complete -c git-machete -n "__fish_seen_subcommand_from traverse t; and not __fish_seen_subcommand_from --whole -w" -f -l whole -s w -d 'Equivalent to -n --start-from=first-root --return-to=nearest-remaining' +complete -c git-machete -n "__fish_seen_subcommand_from traverse t; and not __fish_seen_subcommand_from -W" -f -s W -d 'Equivalent to --fetch --whole; useful for even more automated traversal of all branches' +complete -c git-machete -n "__fish_seen_subcommand_from traverse t; and not __fish_seen_subcommand_from --yes -y" -f -l yes -s y -d 'Do not ask for any interactive input, including confirmation of rebase/push/pull. Implies -n' # git machete update complete -c git-machete -n "not __fish_seen_subcommand_from $__machete_commands" -f -a update -d 'Sync the current branch with its upstream (parent) branch via rebase or merge' diff --git a/docs/man/git-machete.1 b/docs/man/git-machete.1 index c79fb82b8..9f69fbf24 100644 --- a/docs/man/git-machete.1 +++ b/docs/man/git-machete.1 @@ -29,7 +29,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .. .TH "GIT-MACHETE" "1" "Dec 17, 2024" "" "git-machete" .SH NAME -git-machete \- git-machete 3.31.2 +git-machete \- git-machete 3.32.0 .sp git machete is a robust tool that \fBsimplifies your git workflows\fP\&. .sp @@ -2032,6 +2032,7 @@ by setting \fBgit config machete.status.extraSpaceBeforeBranchName true\fP\&. git machete t[raverse] [\-F|\-\-fetch] [\-l|\-\-list\-commits] [\-M|\-\-merge] [\-n|\-\-no\-edit\-merge|\-\-no\-interactive\-rebase] [\-\-[no\-]push] [\-\-[no\-]push\-untracked] [\-\-return\-to=WHERE] [\-\-start\-from=WHERE] [\-\-squash\-merge\-detection=MODE] + [\-H|\-\-sync\-github\-prs|\-L|\-\-sync\-gitlab\-mrs] [\-w|\-\-whole] [\-W] [\-y|\-\-yes] .EE .UNINDENT @@ -2078,6 +2079,13 @@ otherwise, if the branch is behind its remote counterpart: asks the user whether to \fBpull\fP the branch; .UNINDENT .IP \(bu 2 +if \fB\-H\fP/\fB\-\-sync\-github\-prs\fP or \fB\-L\fP/\fB\-\-sync\-gitlab\-mrs\fP option is present: +.INDENT 2.0 +.IP \(bu 2 +retargets the PR/MR if it exists for the given branch and has a different base/target branch in GitHub/GitLab than the upstream in machete file, +just as \fBgit machete github retarget\-pr\fP and \fBgit machete gitlab retarget\-mr\fP would do; +.UNINDENT +.IP \(bu 2 and finally, if any of the above operations has been successfully completed: .INDENT 2.0 .IP \(bu 2 @@ -2122,6 +2130,14 @@ when the current user is NOT the author of the PR/MR associated with that branch .B \-F\fP,\fB \-\-fetch Fetch the remotes of all managed branches at the beginning of traversal (no \fBgit pull\fP involved, only \fBgit fetch\fP). .TP +.B \-H\fP,\fB \-\-sync\-github\-prs +Retarget the PR if it exists for the given branch and has a different base branch in GitHub than the upstream in machete file, +just as \fBgit machete github retarget\-pr\fP would do +.TP +.B \-L\fP,\fB \-\-sync\-gitlab\-mrs +Retarget the MR if it exists for the given branch and has a different target branch in GitLab than the upstream in machete file, +just as \fBgit machete gitlab retarget\-mr\fP would do +.TP .B \-l\fP,\fB \-\-list\-commits When printing the status, additionally list the messages of commits introduced on each branch. .TP diff --git a/docs/source/cli/traverse.rst b/docs/source/cli/traverse.rst index 9d350ff64..1df72fe35 100644 --- a/docs/source/cli/traverse.rst +++ b/docs/source/cli/traverse.rst @@ -21,6 +21,7 @@ traverse git machete t[raverse] [-F|--fetch] [-l|--list-commits] [-M|--merge] [-n|--no-edit-merge|--no-interactive-rebase] [--[no-]push] [--[no-]push-untracked] [--return-to=WHERE] [--start-from=WHERE] [--squash-merge-detection=MODE] + [-H|--sync-github-prs|-L|--sync-gitlab-mrs] [-w|--whole] [-W] [-y|--yes] Traverses the branches in the order as they occur in branch layout file. @@ -52,6 +53,11 @@ For each branch, the command: - asks the user whether to **pull** the branch; +* if ``-H``/``--sync-github-prs`` or ``-L``/``--sync-gitlab-mrs`` option is present: + + - retargets the PR/MR if it exists for the given branch and has a different base/target branch in GitHub/GitLab than the upstream in machete file, + just as ``git machete github retarget-pr`` and ``git machete gitlab retarget-mr`` would do; + * and finally, if any of the above operations has been successfully completed: - prints the updated ``status``. @@ -88,6 +94,12 @@ when the current user is NOT the author of the PR/MR associated with that branch -F, --fetch Fetch the remotes of all managed branches at the beginning of traversal (no ``git pull`` involved, only ``git fetch``). +-H, --sync-github-prs Retarget the PR if it exists for the given branch and has a different base branch in GitHub than the upstream in machete file, + just as ``git machete github retarget-pr`` would do + +-L, --sync-gitlab-mrs Retarget the MR if it exists for the given branch and has a different target branch in GitLab than the upstream in machete file, + just as ``git machete gitlab retarget-mr`` would do + -l, --list-commits When printing the status, additionally list the messages of commits introduced on each branch. -M, --merge Update by merge rather than by rebase. diff --git a/git_machete/__init__.py b/git_machete/__init__.py index 06bad3f9b..c657b2862 100644 --- a/git_machete/__init__.py +++ b/git_machete/__init__.py @@ -1 +1 @@ -__version__ = '3.31.2' +__version__ = '3.32.0' diff --git a/git_machete/cli.py b/git_machete/cli.py index 4414a9ec1..2a636971a 100644 --- a/git_machete/cli.py +++ b/git_machete/cli.py @@ -380,21 +380,23 @@ def add_code_hosting_parser(command: str, pr_or_mr: str, include_sync: bool) -> add_help=False, parents=[common_args_parser]) traverse_parser.add_argument('-F', '--fetch', action='store_true') + traverse_parser.add_argument('-H', '--sync-github-prs', action='store_true') traverse_parser.add_argument('-l', '--list-commits', action='store_true') + traverse_parser.add_argument('-L', '--sync-gitlab-mrs', action='store_true') traverse_parser.add_argument('-M', '--merge', action='store_true') traverse_parser.add_argument('-n', action='store_true') + traverse_parser.add_argument('--no-detect-squash-merges', action='store_true') traverse_parser.add_argument('--no-edit-merge', action='store_true') traverse_parser.add_argument('--no-interactive-rebase', action='store_true') - traverse_parser.add_argument('--no-detect-squash-merges', action='store_true') - traverse_parser.add_argument('--squash-merge-detection') - traverse_parser.add_argument('--push', action='store_true') traverse_parser.add_argument('--no-push', action='store_true') - traverse_parser.add_argument('--push-untracked', action='store_true') traverse_parser.add_argument('--no-push-untracked', action='store_true') + traverse_parser.add_argument('--push', action='store_true') + traverse_parser.add_argument('--push-untracked', action='store_true') traverse_parser.add_argument('--return-to') + traverse_parser.add_argument('--squash-merge-detection') traverse_parser.add_argument('--start-from') - traverse_parser.add_argument('-w', '--whole', action='store_true') traverse_parser.add_argument('-W', action='store_true') + traverse_parser.add_argument('-w', '--whole', action='store_true') traverse_parser.add_argument('-y', '--yes', action='store_true') update_parser = subparsers.add_parser( @@ -960,6 +962,8 @@ def strip_remote_name(remote_branch: RemoteBranchShortName) -> LocalBranchShortN opt_return_to=opt_return_to, opt_squash_merge_detection=opt_squash_merge_detection, opt_start_from=opt_start_from, + opt_sync_github_prs=cli_opts.opt_sync_github_prs, + opt_sync_gitlab_mrs=cli_opts.opt_sync_gitlab_mrs, opt_yes=cli_opts.opt_yes) elif cmd == "update": machete_client.read_branch_layout_file(perform_interactive_slide_out=should_perform_interactive_slide_out) diff --git a/git_machete/client.py b/git_machete/client.py index e5375ff47..734fdf3ca 100644 --- a/git_machete/client.py +++ b/git_machete/client.py @@ -27,6 +27,8 @@ GitFormatPatterns, GitLogEntry, LocalBranchShortName, RemoteBranchShortName, SyncToRemoteStatus) +from .github import GitHubClient +from .gitlab import GitLabClient from .utils import (AnsiEscapeCodes, PopenResult, bold, colored, debug, dim, excluding, flat_map, fmt, get_pretty_choices, get_right_arrow, get_second, tupled, underline, warn) @@ -780,6 +782,8 @@ def traverse( opt_return_to: TraverseReturnTo, opt_squash_merge_detection: SquashMergeDetection, opt_start_from: TraverseStartFrom, + opt_sync_github_prs: bool, + opt_sync_gitlab_mrs: bool, opt_yes: bool ) -> None: self.expect_at_least_one_managed_branch() @@ -795,6 +799,12 @@ def traverse( if self.__git.get_remotes(): print("") + code_hosting_client: Optional[CodeHostingClient] = None + current_user: Optional[str] = None + if opt_sync_github_prs or opt_sync_gitlab_mrs: + spec = GitHubClient.spec() if opt_sync_github_prs else GitLabClient.spec() + self.__init_code_hosting_client(spec) + initial_branch = nearest_remaining_branch = self.__git.get_current_branch() if opt_start_from == TraverseStartFrom.ROOT: @@ -839,6 +849,19 @@ def traverse( else: needs_remote_sync = False + if opt_sync_github_prs or opt_sync_gitlab_mrs: + prs = list(filter(lambda pr: pr.head == branch, self.get_all_open_prs())) + if len(prs) > 1: + assert code_hosting_client is not None + spec = code_hosting_client._spec + raise MacheteException( + f"Multiple {spec.pr_short_name}s have {branch} as its {spec.head_branch_name} branch: " + + ", ".join(_pr.short_display_text() for _pr in prs)) + pr = prs[0] if prs else None + needs_retarget_pr = pr and upstream and pr.base != upstream + else: + needs_retarget_pr = False + use_merge = opt_merge or (branch in self.annotations and self.annotations[branch].qualifiers.update_with_merge) if needs_slide_out: @@ -864,7 +887,7 @@ def traverse( if needs_parent_sync and branch in self.annotations: needs_parent_sync = self.annotations[branch].qualifiers.rebase - if branch != current_branch and (needs_slide_out or needs_parent_sync or needs_remote_sync): + if branch != current_branch and (needs_slide_out or needs_parent_sync or needs_remote_sync or needs_retarget_pr): self.__print_new_line(False) print(f"Checking out {bold(branch)}") self.__git.checkout(branch) @@ -986,6 +1009,37 @@ def traverse( elif ans in ('q', 'quit'): return + if needs_retarget_pr: + any_action_suggested = True + assert pr is not None + assert upstream is not None + assert code_hosting_client is not None + spec = code_hosting_client._spec + ans_intro = f"Branch {bold(str(branch))} has a different {spec.pr_short_name} {spec.base_branch_name} ({bold(pr.base)}) " \ + f"in {spec.display_name} than in machete file ({bold(str(upstream))}). " + ans = self.ask_if( + ans_intro + f"Retarget {pr.display_text()} to {bold(str(upstream))}?" + get_pretty_choices('y', 'N', 'q', 'yq'), + ans_intro + f"Retargeting {pr.display_text()} to {bold(str(upstream))}...", + opt_yes=opt_yes) + if ans in ('y', 'yes', 'yq'): + code_hosting_client.set_base_of_pull_request(pr.number, base=upstream) + print(f'{spec.base_branch_name.capitalize()} branch of {pr.display_text()} has been switched to {bold(str(upstream))}') + pr.base = upstream + + new_description = self.__get_updated_pull_request_description(pr) + if pr.description != new_description: + code_hosting_client.set_description_of_pull_request(pr.number, description=new_description) + print(f'Description of {pr.display_text()} has been updated') + pr.description = new_description + + anno = self.__annotations.get(branch) + self.__annotations[branch] = Annotation(self.__pull_request_annotation(spec, pr, current_user), + anno.qualifiers if anno else Qualifiers()) + self.save_branch_layout_file() + + elif ans in ('q', 'quit'): + return + if needs_remote_sync: any_action_suggested = True try: diff --git a/git_machete/generated_docs.py b/git_machete/generated_docs.py index 8ae69fe6d..ff293e788 100644 --- a/git_machete/generated_docs.py +++ b/git_machete/generated_docs.py @@ -1436,6 +1436,7 @@ git machete t[raverse] [-F|--fetch] [-l|--list-commits] [-M|--merge] [-n|--no-edit-merge|--no-interactive-rebase] [--[no-]push] [--[no-]push-untracked] [--return-to=WHERE] [--start-from=WHERE] [--squash-merge-detection=MODE] + [-H|--sync-github-prs|-L|--sync-gitlab-mrs] [-w|--whole] [-W] [-y|--yes] Traverses the branches in the order as they occur in branch layout file. @@ -1456,6 +1457,9 @@ - asks the user whether to reset (`git reset --keep`) the branch to its remote counterpart * otherwise, if the branch is behind its remote counterpart: - asks the user whether to pull the branch; + * if `-H`/`--sync-github-prs` or `-L`/`--sync-gitlab-mrs` option is present: + - retargets the PR/MR if it exists for the given branch and has a different base/target branch in GitHub/GitLab than the upstream in machete file, + just as `git machete github retarget-pr` and `git machete gitlab retarget-mr` would do; * and finally, if any of the above operations has been successfully completed: - prints the updated `status`. @@ -1488,6 +1492,12 @@ Options: -F, --fetch Fetch the remotes of all managed branches at the beginning of traversal (no `git pull` involved, only `git fetch`). + -H, --sync-github-prs + Retarget the PR if it exists for the given branch and has a different base branch in GitHub than the upstream in machete file, + just as `git machete github retarget-pr` would do + -L, --sync-gitlab-mrs + Retarget the MR if it exists for the given branch and has a different target branch in GitLab than the upstream in machete file, + just as `git machete gitlab retarget-mr` would do -l, --list-commits When printing the status, additionally list the messages of commits introduced on each branch. -M, --merge diff --git a/tests/completion_e2e/test_completion_e2e.py b/tests/completion_e2e/test_completion_e2e.py index 9ba472f53..27b66baf5 100644 --- a/tests/completion_e2e/test_completion_e2e.py +++ b/tests/completion_e2e/test_completion_e2e.py @@ -129,11 +129,15 @@ "git machete status --color=": "always auto never", "git machete t -": - "-F -M -W --debug --fetch -h --help -l --list-commits --merge -n --no-detect-squash-merges --no-edit-merge --no-interactive-rebase " - "--no-push --no-push-untracked --push --push-untracked --return-to --start-from -v --verbose -w --whole -y --yes", + "-F -H -L -M -W --debug --fetch -h --help -l --list-commits --merge " + "-n --no-detect-squash-merges --no-edit-merge --no-interactive-rebase " + "--no-push --no-push-untracked --push --push-untracked --return-to --start-from " + "--sync-github-prs --sync-gitlab-mrs -v --verbose -w --whole -y --yes", "git machete traverse -": - "-F -M -W --debug --fetch -h --help -l --list-commits --merge -n --no-detect-squash-merges --no-edit-merge --no-interactive-rebase " - "--no-push --no-push-untracked --push --push-untracked --return-to --start-from -v --verbose -w --whole -y --yes", + "-F -H -L -M -W --debug --fetch -h --help -l --list-commits --merge " + "-n --no-detect-squash-merges --no-edit-merge --no-interactive-rebase " + "--no-push --no-push-untracked --push --push-untracked --return-to --start-from " + "--sync-github-prs --sync-gitlab-mrs -v --verbose -w --whole -y --yes", "git machete update -": "-M --debug -f --fork-point -h --help --merge -n --no-edit-merge --no-interactive-rebase -v --verbose", "git machete update -f ":