| #!/usr/bin/env python3 | |
| import argparse | |
| import sys | |
| from typing import Set, List, Deque | |
| from collections import deque | |
| import os | |
| # Allow importing of root-relative modules. | |
| ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) | |
| sys.path.append(os.path.join(ROOT_DIR)) | |
| #pylint: disable=wrong-import-position | |
| from python.tools.git_utils import ( | |
| get_current_branch, | |
| get_all_branches, | |
| get_stack_branches_ordered, | |
| get_branch_parent, | |
| get_worktree_branches, | |
| run_git_command, | |
| MAINLINE_BRANCHES, | |
| ) | |
| #pylint: enable=wrong-import-position | |
| def main(): | |
| parser = argparse.ArgumentParser( | |
| description=( | |
| 'Updates target stack segment (target + ancestors + descendants) via merges.' | |
| ), | |
| formatter_class=argparse.RawTextHelpFormatter) | |
| parser.add_argument( | |
| '-t', | |
| '--target', | |
| metavar='branch_name', | |
| default=None, | |
| help='Target branch stack (default: current)') | |
| args = parser.parse_args() | |
| target_branch = args.target or get_current_branch() | |
| if not target_branch: | |
| print("Error: Cannot determine target branch.", file=sys.stderr) | |
| sys.exit(1) | |
| all_local_branches = get_all_branches() | |
| if target_branch not in all_local_branches: | |
| print( | |
| f"Error: Target branch '{target_branch}' not found locally.", | |
| file=sys.stderr) | |
| sys.exit(1) | |
| ordered_branches: List[str] = [] | |
| try: | |
| ordered_branches = get_stack_branches_ordered(target_branch, | |
| MAINLINE_BRANCHES, | |
| all_local_branches) | |
| except ValueError as e: | |
| print(f"Error determining stack order (Cycle?): {e}", file=sys.stderr) | |
| sys.exit(1) | |
| if not ordered_branches: | |
| print("No branches identified for update. Exiting.", file=sys.stderr) | |
| sys.exit(1) | |
| print( | |
| f"Branches to update (order: parent-first): {', '.join(ordered_branches)}" | |
| ) | |
| original_branch_to_restore = get_current_branch() | |
| worktree_branches = get_worktree_branches() | |
| for branch in ordered_branches: | |
| parent = get_branch_parent(branch) | |
| if parent: | |
| worktree_path = worktree_branches.get(branch) | |
| if worktree_path: | |
| print(f"\nUpdating '{branch}' by merging '{parent}' (in worktree)...") | |
| try: | |
| run_git_command(['-C', worktree_path, 'merge', parent]) | |
| print(f"Merge successful.") | |
| except SystemExit as e: | |
| print( | |
| f"MERGE FAILED: Conflicts merging '{parent}' into '{branch}' " | |
| f"(worktree: {worktree_path}).", | |
| file=sys.stderr) | |
| print( | |
| "Resolve conflicts in the worktree and commit.", file=sys.stderr) | |
| sys.exit(e.code if isinstance(e.code, int) else 1) | |
| except Exception as e: | |
| print(f"\nUnexpected error updating '{branch}': {e}", file=sys.stderr) | |
| sys.exit(1) | |
| else: | |
| print(f"\nUpdating '{branch}' by merging '{parent}'...") | |
| try: | |
| run_git_command(['checkout', branch]) | |
| run_git_command(['merge', parent]) | |
| print(f"Merge successful.") | |
| except SystemExit as e: | |
| print( | |
| f"MERGE FAILED: Conflicts merging '{parent}' into '{branch}'.", | |
| file=sys.stderr) | |
| print("Resolve conflicts manually and commit.", file=sys.stderr) | |
| if original_branch_to_restore and get_current_branch( | |
| ) != original_branch_to_restore: | |
| print( | |
| f"Restoring original branch '{original_branch_to_restore}'...") | |
| run_git_command(['checkout', original_branch_to_restore], | |
| check=False) | |
| sys.exit(e.code if isinstance(e.code, int) else 1) | |
| except Exception as e: | |
| print(f"\nUnexpected error updating '{branch}': {e}", file=sys.stderr) | |
| if original_branch_to_restore and get_current_branch( | |
| ) != original_branch_to_restore: | |
| run_git_command(['checkout', original_branch_to_restore], | |
| check=False) | |
| sys.exit(1) | |
| if original_branch_to_restore and get_current_branch( | |
| ) != original_branch_to_restore: | |
| print(f"\nRestoring original branch '{original_branch_to_restore}'...") | |
| run_git_command(['checkout', original_branch_to_restore], check=False) | |
| print( | |
| f"\n--- Update process finished for stack including '{target_branch}' ---" | |
| ) | |
| if __name__ == "__main__": | |
| main() |