panqake 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- panqake-0.1.0/.gitignore +1 -0
- panqake-0.1.0/PKG-INFO +125 -0
- panqake-0.1.0/README.md +116 -0
- panqake-0.1.0/pyproject.toml +33 -0
- panqake-0.1.0/src/panqake/__init__.py +3 -0
- panqake-0.1.0/src/panqake/__main__.py +6 -0
- panqake-0.1.0/src/panqake/cli.py +112 -0
- panqake-0.1.0/src/panqake/commands/__init__.py +1 -0
- panqake-0.1.0/src/panqake/commands/delete.py +153 -0
- panqake-0.1.0/src/panqake/commands/list.py +74 -0
- panqake-0.1.0/src/panqake/commands/new.py +56 -0
- panqake-0.1.0/src/panqake/commands/pr.py +173 -0
- panqake-0.1.0/src/panqake/commands/switch.py +83 -0
- panqake-0.1.0/src/panqake/commands/update.py +122 -0
- panqake-0.1.0/src/panqake/utils/__init__.py +1 -0
- panqake-0.1.0/src/panqake/utils/config.py +102 -0
- panqake-0.1.0/src/panqake/utils/git.py +71 -0
- panqake-0.1.0/src/panqake/utils/prompt.py +86 -0
- panqake-0.1.0/src/panqake/utils/questionary_prompt.py +173 -0
panqake-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
**/*.pyc
|
panqake-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: panqake
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Git Branch Stacking Utility
|
|
5
|
+
Requires-Python: >=3.12
|
|
6
|
+
Requires-Dist: prompt-toolkit>=3.0.51
|
|
7
|
+
Requires-Dist: questionary>=2.1.0
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
|
|
10
|
+
# Panqake - Git Branch Stacking Utility
|
|
11
|
+
|
|
12
|
+
Panqake is a set of shell utilities for implementing the git-stacking workflow. It helps manage stacked branches, making it easier to work with multiple dependent pull requests.
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
1. Clone this repository:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
git clone https://github.com/yourusername/panqake.git
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
2. Add the panqake directory to your PATH or create symlinks to the panqake script in a directory that's already in your PATH.
|
|
23
|
+
|
|
24
|
+
3. Dependencies:
|
|
25
|
+
- jq: For JSON processing
|
|
26
|
+
- gh: GitHub CLI (optional, only needed for PR creation)
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
### Create a new branch in the stack
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
panqake new feature-login
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
This creates a new branch based on your current branch and tracks the relationship.
|
|
37
|
+
|
|
38
|
+
### View the branch stack
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
panqake list
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Displays a tree view of your current branch stack.
|
|
45
|
+
|
|
46
|
+
### Update branches after changes
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
panqake update
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
After making changes to a branch, this command rebases all child branches to incorporate your changes.
|
|
53
|
+
|
|
54
|
+
### Delete a branch and relink the stack
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
panqake delete feature-old
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Deletes a branch and relinks its children to its parent, maintaining the stack structure.
|
|
61
|
+
|
|
62
|
+
### Create PRs for the branch stack
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
panqake pr
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Creates pull requests for each branch in the stack, starting from the bottom.
|
|
69
|
+
|
|
70
|
+
## Workflow Example
|
|
71
|
+
|
|
72
|
+
1. Start a new feature stack from main:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
git checkout main
|
|
76
|
+
panqake new feature-base
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
2. Make your initial changes and commit.
|
|
80
|
+
|
|
81
|
+
3. Create a dependent branch for additional work:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
panqake new feature-ui
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
4. Make changes and commit in the feature-ui branch.
|
|
88
|
+
|
|
89
|
+
5. If you need to update the feature-base branch:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
git checkout feature-base
|
|
93
|
+
# Make changes and commit
|
|
94
|
+
panqake update
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
6. Create PRs for your stack:
|
|
98
|
+
```bash
|
|
99
|
+
panqake pr
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## License
|
|
103
|
+
|
|
104
|
+
MIT
|
|
105
|
+
|
|
106
|
+
## Contributing
|
|
107
|
+
|
|
108
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
109
|
+
|
|
110
|
+
## Changelog
|
|
111
|
+
|
|
112
|
+
### v0.1.1 (Unreleased)
|
|
113
|
+
|
|
114
|
+
- Switched CLI interface from prompt_toolkit to questionary for improved user experience
|
|
115
|
+
- Enhanced command-line prompts with better styling and autocomplete
|
|
116
|
+
- Fixed styling issues in branch listing display
|
|
117
|
+
- Improved output formatting for colored text
|
|
118
|
+
- Added custom color scheme that works well on both light and dark terminals
|
|
119
|
+
- Added documentation for the style system
|
|
120
|
+
|
|
121
|
+
### v0.1.0
|
|
122
|
+
|
|
123
|
+
- Initial release with core functionality
|
|
124
|
+
- Branch stacking management
|
|
125
|
+
- PR creation support
|
panqake-0.1.0/README.md
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# Panqake - Git Branch Stacking Utility
|
|
2
|
+
|
|
3
|
+
Panqake is a set of shell utilities for implementing the git-stacking workflow. It helps manage stacked branches, making it easier to work with multiple dependent pull requests.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
1. Clone this repository:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
git clone https://github.com/yourusername/panqake.git
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
2. Add the panqake directory to your PATH or create symlinks to the panqake script in a directory that's already in your PATH.
|
|
14
|
+
|
|
15
|
+
3. Dependencies:
|
|
16
|
+
- jq: For JSON processing
|
|
17
|
+
- gh: GitHub CLI (optional, only needed for PR creation)
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
### Create a new branch in the stack
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
panqake new feature-login
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
This creates a new branch based on your current branch and tracks the relationship.
|
|
28
|
+
|
|
29
|
+
### View the branch stack
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
panqake list
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Displays a tree view of your current branch stack.
|
|
36
|
+
|
|
37
|
+
### Update branches after changes
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
panqake update
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
After making changes to a branch, this command rebases all child branches to incorporate your changes.
|
|
44
|
+
|
|
45
|
+
### Delete a branch and relink the stack
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
panqake delete feature-old
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Deletes a branch and relinks its children to its parent, maintaining the stack structure.
|
|
52
|
+
|
|
53
|
+
### Create PRs for the branch stack
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
panqake pr
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Creates pull requests for each branch in the stack, starting from the bottom.
|
|
60
|
+
|
|
61
|
+
## Workflow Example
|
|
62
|
+
|
|
63
|
+
1. Start a new feature stack from main:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
git checkout main
|
|
67
|
+
panqake new feature-base
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
2. Make your initial changes and commit.
|
|
71
|
+
|
|
72
|
+
3. Create a dependent branch for additional work:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
panqake new feature-ui
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
4. Make changes and commit in the feature-ui branch.
|
|
79
|
+
|
|
80
|
+
5. If you need to update the feature-base branch:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
git checkout feature-base
|
|
84
|
+
# Make changes and commit
|
|
85
|
+
panqake update
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
6. Create PRs for your stack:
|
|
89
|
+
```bash
|
|
90
|
+
panqake pr
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## License
|
|
94
|
+
|
|
95
|
+
MIT
|
|
96
|
+
|
|
97
|
+
## Contributing
|
|
98
|
+
|
|
99
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
100
|
+
|
|
101
|
+
## Changelog
|
|
102
|
+
|
|
103
|
+
### v0.1.1 (Unreleased)
|
|
104
|
+
|
|
105
|
+
- Switched CLI interface from prompt_toolkit to questionary for improved user experience
|
|
106
|
+
- Enhanced command-line prompts with better styling and autocomplete
|
|
107
|
+
- Fixed styling issues in branch listing display
|
|
108
|
+
- Improved output formatting for colored text
|
|
109
|
+
- Added custom color scheme that works well on both light and dark terminals
|
|
110
|
+
- Added documentation for the style system
|
|
111
|
+
|
|
112
|
+
### v0.1.0
|
|
113
|
+
|
|
114
|
+
- Initial release with core functionality
|
|
115
|
+
- Branch stacking management
|
|
116
|
+
- PR creation support
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "panqake"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Git Branch Stacking Utility"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.12"
|
|
7
|
+
dependencies = [
|
|
8
|
+
"prompt-toolkit>=3.0.51",
|
|
9
|
+
"questionary>=2.1.0",
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
[project.scripts]
|
|
13
|
+
panqake = "panqake.cli:main"
|
|
14
|
+
pq = "panqake.cli:main"
|
|
15
|
+
|
|
16
|
+
[build-system]
|
|
17
|
+
requires = ["hatchling"]
|
|
18
|
+
build-backend = "hatchling.build"
|
|
19
|
+
|
|
20
|
+
[tool.hatch.build.targets.wheel]
|
|
21
|
+
packages = ["src/panqake"]
|
|
22
|
+
|
|
23
|
+
[tool.hatch.build.targets.sdist]
|
|
24
|
+
include = [
|
|
25
|
+
"src/panqake",
|
|
26
|
+
"README.md",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
[dependency-groups]
|
|
30
|
+
dev = [
|
|
31
|
+
"pytest>=8.3.5",
|
|
32
|
+
"hatch",
|
|
33
|
+
]
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Panqake - Git Branch Stacking Utility
|
|
4
|
+
A Python implementation of git-stacking workflow management
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import argparse
|
|
8
|
+
import sys
|
|
9
|
+
|
|
10
|
+
from panqake.commands.delete import delete_branch
|
|
11
|
+
from panqake.commands.list import list_branches
|
|
12
|
+
from panqake.commands.new import create_new_branch
|
|
13
|
+
from panqake.commands.pr import create_pull_requests
|
|
14
|
+
from panqake.commands.switch import switch_branch
|
|
15
|
+
from panqake.commands.update import update_branches
|
|
16
|
+
from panqake.utils.config import init_panqake
|
|
17
|
+
from panqake.utils.git import is_git_repo
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def main():
|
|
21
|
+
"""Main entry point for the panqake CLI."""
|
|
22
|
+
parser = argparse.ArgumentParser(
|
|
23
|
+
description="Panqake - Git Branch Stacking Utility"
|
|
24
|
+
)
|
|
25
|
+
subparsers = parser.add_subparsers(dest="command", help="Command to run")
|
|
26
|
+
|
|
27
|
+
# new command
|
|
28
|
+
new_parser = subparsers.add_parser("new", help="Create a new branch in the stack")
|
|
29
|
+
new_parser.add_argument(
|
|
30
|
+
"branch_name",
|
|
31
|
+
nargs="?",
|
|
32
|
+
help="Name of the new branch to create",
|
|
33
|
+
)
|
|
34
|
+
new_parser.add_argument(
|
|
35
|
+
"base_branch",
|
|
36
|
+
nargs="?",
|
|
37
|
+
help="Optional base branch (defaults to current branch)",
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
# list command
|
|
41
|
+
list_parser = subparsers.add_parser("list", help="List the branch stack")
|
|
42
|
+
list_parser.add_argument(
|
|
43
|
+
"branch_name",
|
|
44
|
+
nargs="?",
|
|
45
|
+
help="Optional branch to start from (defaults to current branch)",
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
# update command
|
|
49
|
+
update_parser = subparsers.add_parser(
|
|
50
|
+
"update", help="Update branches after changes"
|
|
51
|
+
)
|
|
52
|
+
update_parser.add_argument(
|
|
53
|
+
"branch_name",
|
|
54
|
+
nargs="?",
|
|
55
|
+
help="Optional branch to start from (defaults to current branch)",
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
# delete command
|
|
59
|
+
delete_parser = subparsers.add_parser(
|
|
60
|
+
"delete", help="Delete a branch and relink the stack"
|
|
61
|
+
)
|
|
62
|
+
delete_parser.add_argument("branch_name", help="Name of the branch to delete")
|
|
63
|
+
|
|
64
|
+
# pr command
|
|
65
|
+
pr_parser = subparsers.add_parser("pr", help="Create PRs for the branch stack")
|
|
66
|
+
pr_parser.add_argument(
|
|
67
|
+
"branch_name",
|
|
68
|
+
nargs="?",
|
|
69
|
+
help="Optional branch to start from (defaults to current branch)",
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
# switch command
|
|
73
|
+
switch_parser = subparsers.add_parser(
|
|
74
|
+
"switch", help="Interactively switch between branches"
|
|
75
|
+
)
|
|
76
|
+
switch_parser.add_argument(
|
|
77
|
+
"branch_name",
|
|
78
|
+
nargs="?",
|
|
79
|
+
help="Optional branch to switch to (defaults to interactive selection)",
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
args = parser.parse_args()
|
|
83
|
+
|
|
84
|
+
if not args.command:
|
|
85
|
+
parser.print_help()
|
|
86
|
+
return
|
|
87
|
+
|
|
88
|
+
# Initialize panqake directory and files
|
|
89
|
+
init_panqake()
|
|
90
|
+
|
|
91
|
+
# Check if we're in a git repository
|
|
92
|
+
if not is_git_repo():
|
|
93
|
+
print("Error: Not in a git repository")
|
|
94
|
+
sys.exit(1)
|
|
95
|
+
|
|
96
|
+
# Execute the appropriate command
|
|
97
|
+
if args.command == "new":
|
|
98
|
+
create_new_branch(args.branch_name, args.base_branch)
|
|
99
|
+
elif args.command == "list":
|
|
100
|
+
list_branches(args.branch_name)
|
|
101
|
+
elif args.command == "update":
|
|
102
|
+
update_branches(args.branch_name)
|
|
103
|
+
elif args.command == "delete":
|
|
104
|
+
delete_branch(args.branch_name)
|
|
105
|
+
elif args.command == "pr":
|
|
106
|
+
create_pull_requests(args.branch_name)
|
|
107
|
+
elif args.command == "switch":
|
|
108
|
+
switch_branch(args.branch_name)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
if __name__ == "__main__":
|
|
112
|
+
main()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Command modules for panqake git-stacking utility."""
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"""Command for deleting a branch and relinking the stack."""
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
from panqake.utils.config import (
|
|
6
|
+
add_to_stack,
|
|
7
|
+
get_child_branches,
|
|
8
|
+
get_parent_branch,
|
|
9
|
+
remove_from_stack,
|
|
10
|
+
)
|
|
11
|
+
from panqake.utils.git import branch_exists, get_current_branch, run_git_command
|
|
12
|
+
from panqake.utils.questionary_prompt import (
|
|
13
|
+
format_branch,
|
|
14
|
+
print_formatted_text,
|
|
15
|
+
prompt_confirm,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def validate_branch_for_deletion(branch_name):
|
|
20
|
+
"""Validate that a branch can be deleted."""
|
|
21
|
+
current_branch = get_current_branch()
|
|
22
|
+
|
|
23
|
+
# Check if target branch exists
|
|
24
|
+
if not branch_exists(branch_name):
|
|
25
|
+
print_formatted_text(
|
|
26
|
+
f"<warning>Error: Branch '{branch_name}' does not exist</warning>"
|
|
27
|
+
)
|
|
28
|
+
sys.exit(1)
|
|
29
|
+
|
|
30
|
+
# Check if target branch is the current branch
|
|
31
|
+
if branch_name == current_branch:
|
|
32
|
+
print_formatted_text(
|
|
33
|
+
"<warning>Error: Cannot delete the current branch. Please checkout another branch first.</warning>"
|
|
34
|
+
)
|
|
35
|
+
sys.exit(1)
|
|
36
|
+
|
|
37
|
+
return current_branch
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def get_branch_relationships(branch_name):
|
|
41
|
+
"""Get parent and child branches and validate parent exists."""
|
|
42
|
+
parent_branch = get_parent_branch(branch_name)
|
|
43
|
+
child_branches = get_child_branches(branch_name)
|
|
44
|
+
|
|
45
|
+
# Ensure parent branch exists
|
|
46
|
+
if parent_branch and not branch_exists(parent_branch):
|
|
47
|
+
print_formatted_text(
|
|
48
|
+
f"<warning>Error: Parent branch '{parent_branch}' does not exist</warning>"
|
|
49
|
+
)
|
|
50
|
+
sys.exit(1)
|
|
51
|
+
|
|
52
|
+
return parent_branch, child_branches
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def display_deletion_info(branch_name, parent_branch, child_branches):
|
|
56
|
+
"""Display deletion information and ask for confirmation."""
|
|
57
|
+
print_formatted_text(
|
|
58
|
+
f"<info>Branch to delete:</info> {format_branch(branch_name, danger=True)}"
|
|
59
|
+
)
|
|
60
|
+
if parent_branch:
|
|
61
|
+
print_formatted_text(
|
|
62
|
+
f"<info>Parent branch:</info> {format_branch(parent_branch)}"
|
|
63
|
+
)
|
|
64
|
+
if child_branches:
|
|
65
|
+
print_formatted_text("<info>Child branches that will be relinked:</info>")
|
|
66
|
+
for child in child_branches:
|
|
67
|
+
print_formatted_text(f" {format_branch(child)}")
|
|
68
|
+
|
|
69
|
+
# Confirm deletion
|
|
70
|
+
if not prompt_confirm("Are you sure you want to delete this branch?"):
|
|
71
|
+
print_formatted_text("<info>Branch deletion cancelled.</info>")
|
|
72
|
+
return False
|
|
73
|
+
|
|
74
|
+
return True
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def relink_child_branches(child_branches, parent_branch, current_branch, branch_name):
|
|
78
|
+
"""Relink child branches to the parent branch."""
|
|
79
|
+
if not child_branches:
|
|
80
|
+
return True
|
|
81
|
+
|
|
82
|
+
print_formatted_text(
|
|
83
|
+
f"<info>Relinking child branches to parent '{parent_branch}'...</info>"
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
for child in child_branches:
|
|
87
|
+
print_formatted_text(
|
|
88
|
+
f"<info>Processing child branch:</info> {format_branch(child)}"
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
# Checkout the child branch
|
|
92
|
+
checkout_result = run_git_command(["checkout", child])
|
|
93
|
+
if checkout_result is None:
|
|
94
|
+
print_formatted_text(
|
|
95
|
+
f"<warning>Error: Failed to checkout branch '{child}'</warning>"
|
|
96
|
+
)
|
|
97
|
+
run_git_command(["checkout", current_branch])
|
|
98
|
+
sys.exit(1)
|
|
99
|
+
|
|
100
|
+
# Rebase onto the grandparent branch
|
|
101
|
+
if parent_branch:
|
|
102
|
+
rebase_result = run_git_command(["rebase", parent_branch])
|
|
103
|
+
if rebase_result is None:
|
|
104
|
+
print_formatted_text(
|
|
105
|
+
f"<warning>Error: Rebase conflict detected in branch '{child}'</warning>"
|
|
106
|
+
)
|
|
107
|
+
print_formatted_text(
|
|
108
|
+
"<warning>Please resolve conflicts and run 'git rebase --continue'</warning>"
|
|
109
|
+
)
|
|
110
|
+
print_formatted_text(
|
|
111
|
+
f"<warning>Then run 'panqake delete {branch_name}' again to retry</warning>"
|
|
112
|
+
)
|
|
113
|
+
sys.exit(1)
|
|
114
|
+
|
|
115
|
+
# Update stack metadata
|
|
116
|
+
add_to_stack(child, parent_branch)
|
|
117
|
+
|
|
118
|
+
return True
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def delete_branch(branch_name):
|
|
122
|
+
"""Delete a branch and relink the stack."""
|
|
123
|
+
current_branch = validate_branch_for_deletion(branch_name)
|
|
124
|
+
parent_branch, child_branches = get_branch_relationships(branch_name)
|
|
125
|
+
|
|
126
|
+
if not display_deletion_info(branch_name, parent_branch, child_branches):
|
|
127
|
+
return
|
|
128
|
+
|
|
129
|
+
print_formatted_text(
|
|
130
|
+
f"<info>Deleting branch '{branch_name}' from the stack...</info>"
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
# Process child branches
|
|
134
|
+
relink_child_branches(child_branches, parent_branch, current_branch, branch_name)
|
|
135
|
+
|
|
136
|
+
# Return to original branch if it's not the one being deleted
|
|
137
|
+
if branch_name != current_branch:
|
|
138
|
+
run_git_command(["checkout", current_branch])
|
|
139
|
+
|
|
140
|
+
# Delete the branch
|
|
141
|
+
delete_result = run_git_command(["branch", "-D", branch_name])
|
|
142
|
+
if delete_result is None:
|
|
143
|
+
print_formatted_text(
|
|
144
|
+
f"<warning>Error: Failed to delete branch '{branch_name}'</warning>"
|
|
145
|
+
)
|
|
146
|
+
sys.exit(1)
|
|
147
|
+
|
|
148
|
+
# Remove from stack metadata
|
|
149
|
+
remove_from_stack(branch_name)
|
|
150
|
+
|
|
151
|
+
print_formatted_text(
|
|
152
|
+
f"<success>Success! Deleted branch '{branch_name}' and relinked the stack</success>"
|
|
153
|
+
)
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""Command for listing branches in the stack."""
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
from panqake.utils.config import get_child_branches, get_parent_branch
|
|
6
|
+
from panqake.utils.git import branch_exists, get_current_branch
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def find_stack_root(branch):
|
|
10
|
+
"""Find the root of the stack for a given branch."""
|
|
11
|
+
parent = get_parent_branch(branch)
|
|
12
|
+
|
|
13
|
+
if not parent:
|
|
14
|
+
return branch
|
|
15
|
+
else:
|
|
16
|
+
return find_stack_root(parent)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def print_branch_tree(branch, indent="", is_last_sibling=True):
|
|
20
|
+
"""Recursively print the branch tree."""
|
|
21
|
+
current_branch = get_current_branch()
|
|
22
|
+
is_current = branch == current_branch
|
|
23
|
+
|
|
24
|
+
# Determine the connector for the current branch
|
|
25
|
+
if indent: # Not the root
|
|
26
|
+
connector = "└── " if is_last_sibling else "├── "
|
|
27
|
+
else: # Root branch
|
|
28
|
+
connector = ""
|
|
29
|
+
|
|
30
|
+
# Format and print the current branch line
|
|
31
|
+
prefix = f"{indent}{connector}"
|
|
32
|
+
if is_current:
|
|
33
|
+
# Apply branch styling using ANSI codes
|
|
34
|
+
branch_display = f"* {branch}"
|
|
35
|
+
# Print prefix first, then styled branch with ANSI codes
|
|
36
|
+
print(f"{prefix}\033[92m{branch_display}\033[0m")
|
|
37
|
+
else:
|
|
38
|
+
# Non-current branches use default terminal text color
|
|
39
|
+
print(f"{prefix}{branch}")
|
|
40
|
+
|
|
41
|
+
# Prepare the indentation for children
|
|
42
|
+
# Add a vertical bar if this branch is not the last sibling, otherwise add spaces
|
|
43
|
+
child_indent = indent + (" " if is_last_sibling else "│ ")
|
|
44
|
+
|
|
45
|
+
# Get children of this branch
|
|
46
|
+
children = get_child_branches(branch)
|
|
47
|
+
num_children = len(children)
|
|
48
|
+
|
|
49
|
+
if children:
|
|
50
|
+
for i, child in enumerate(children):
|
|
51
|
+
is_last_child = i == num_children - 1
|
|
52
|
+
print_branch_tree(child, child_indent, is_last_child)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def list_branches(branch_name=None):
|
|
56
|
+
"""List the branch stack."""
|
|
57
|
+
# If no branch specified, use current branch
|
|
58
|
+
if not branch_name:
|
|
59
|
+
branch_name = get_current_branch()
|
|
60
|
+
|
|
61
|
+
# Check if target branch exists
|
|
62
|
+
if not branch_exists(branch_name):
|
|
63
|
+
# Use standard print with ANSI codes for warning style (yellow)
|
|
64
|
+
print(f"\033[93mError: Branch '{branch_name}' does not exist\033[0m")
|
|
65
|
+
sys.exit(1)
|
|
66
|
+
|
|
67
|
+
# Find the root of the stack for the target branch
|
|
68
|
+
root_branch = find_stack_root(branch_name)
|
|
69
|
+
|
|
70
|
+
# Use standard print with ANSI codes for info style (cyan)
|
|
71
|
+
print(f"\033[96mBranch stack (current: {get_current_branch()})\033[0m")
|
|
72
|
+
|
|
73
|
+
# Initial call starts with no indent and assumes the root is the 'last sibling' conceptually
|
|
74
|
+
print_branch_tree(root_branch, indent="", is_last_sibling=True)
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""Command for creating a new branch in the stack."""
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
from panqake.utils.config import add_to_stack
|
|
6
|
+
from panqake.utils.git import (
|
|
7
|
+
branch_exists,
|
|
8
|
+
get_current_branch,
|
|
9
|
+
list_all_branches,
|
|
10
|
+
run_git_command,
|
|
11
|
+
)
|
|
12
|
+
from panqake.utils.questionary_prompt import BranchNameValidator, prompt_input
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def create_new_branch(branch_name=None, base_branch=None):
|
|
16
|
+
"""Create a new branch in the stack."""
|
|
17
|
+
# If no branch name specified, prompt for it
|
|
18
|
+
if not branch_name:
|
|
19
|
+
validator = BranchNameValidator()
|
|
20
|
+
branch_name = prompt_input("Enter new branch name: ", validator=validator)
|
|
21
|
+
|
|
22
|
+
# If no base branch specified, use current branch but offer selection
|
|
23
|
+
current = get_current_branch()
|
|
24
|
+
if not base_branch:
|
|
25
|
+
base_branch = current
|
|
26
|
+
branches = list_all_branches()
|
|
27
|
+
if branches:
|
|
28
|
+
base_branch = prompt_input(
|
|
29
|
+
f"Enter base branch [default: {current}]: ",
|
|
30
|
+
completer=branches,
|
|
31
|
+
default=current,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
# Check if the new branch already exists
|
|
35
|
+
if branch_exists(branch_name):
|
|
36
|
+
print(f"Error: Branch '{branch_name}' already exists")
|
|
37
|
+
sys.exit(1)
|
|
38
|
+
|
|
39
|
+
# Check if the base branch exists
|
|
40
|
+
if base_branch and not branch_exists(base_branch):
|
|
41
|
+
print(f"Error: Base branch '{base_branch}' does not exist")
|
|
42
|
+
sys.exit(1)
|
|
43
|
+
|
|
44
|
+
print(f"Creating new branch '{branch_name}' based on '{base_branch}'...")
|
|
45
|
+
|
|
46
|
+
# Create the new branch
|
|
47
|
+
result = run_git_command(["checkout", "-b", branch_name, base_branch])
|
|
48
|
+
if result is None:
|
|
49
|
+
print("Error: Failed to create new branch")
|
|
50
|
+
sys.exit(1)
|
|
51
|
+
|
|
52
|
+
# Record the dependency information
|
|
53
|
+
add_to_stack(branch_name, base_branch)
|
|
54
|
+
|
|
55
|
+
print(f"Success! Created new branch '{branch_name}' in the stack")
|
|
56
|
+
print(f"Parent branch: {base_branch}")
|