gitbash 0.1.0
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.
- package/LICENSE +21 -0
- package/README.md +194 -0
- package/bin/gitbash +124 -0
- package/commands/branch.sh +184 -0
- package/commands/cleanstash.sh +187 -0
- package/commands/cleanup.sh +452 -0
- package/commands/commit.sh +169 -0
- package/commands/commits.sh +211 -0
- package/commands/create.sh +205 -0
- package/commands/pr.sh +130 -0
- package/commands/stale.sh +403 -0
- package/commands/stale.zsh +403 -0
- package/commands/stash.sh +93 -0
- package/commands/stashes.sh +183 -0
- package/commands/status.sh +323 -0
- package/commands/switch.sh +174 -0
- package/commands/unstash.sh +174 -0
- package/commands/update.sh +191 -0
- package/package.json +42 -0
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# shellcheck disable=SC2155
|
|
3
|
+
|
|
4
|
+
# List recent commits and optionally revert selected ones
|
|
5
|
+
commits() {
|
|
6
|
+
# -----------------------------
|
|
7
|
+
# 0. Check for help flag
|
|
8
|
+
# -----------------------------
|
|
9
|
+
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
|
|
10
|
+
cat << 'EOF'
|
|
11
|
+
Usage: commits [COUNT]
|
|
12
|
+
|
|
13
|
+
List recent commits in the current branch with option to revert selected ones.
|
|
14
|
+
|
|
15
|
+
Arguments:
|
|
16
|
+
COUNT Number of commits to show (default: 20)
|
|
17
|
+
|
|
18
|
+
Navigation:
|
|
19
|
+
↑/↓ or j/k Navigate through commits
|
|
20
|
+
TAB Select/deselect commit for revert
|
|
21
|
+
Enter Revert selected commit(s)
|
|
22
|
+
ESC/Ctrl-C Exit without action
|
|
23
|
+
|
|
24
|
+
Notes:
|
|
25
|
+
- Shows commits from newest to oldest
|
|
26
|
+
- Preview shows full commit diff
|
|
27
|
+
- Multiple commits can be selected for revert
|
|
28
|
+
- Reverts are done in reverse order (oldest first) to avoid conflicts
|
|
29
|
+
- Each revert creates a new commit
|
|
30
|
+
|
|
31
|
+
Examples:
|
|
32
|
+
$ commits
|
|
33
|
+
# Shows last 20 commits
|
|
34
|
+
|
|
35
|
+
$ commits 50
|
|
36
|
+
# Shows last 50 commits
|
|
37
|
+
|
|
38
|
+
Requirements:
|
|
39
|
+
- Must be in a git repository
|
|
40
|
+
- fzf (fuzzy finder)
|
|
41
|
+
|
|
42
|
+
EOF
|
|
43
|
+
return 0
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# -----------------------------
|
|
47
|
+
# 1. Check prerequisites
|
|
48
|
+
# -----------------------------
|
|
49
|
+
if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
50
|
+
echo "Not inside a git repository."
|
|
51
|
+
return 1
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
if ! command -v fzf >/dev/null 2>&1; then
|
|
55
|
+
echo "fzf is not installed."
|
|
56
|
+
read -rp "Install fzf with Homebrew? (y/N): " ans
|
|
57
|
+
case "$ans" in
|
|
58
|
+
[yY][eE][sS]|[yY])
|
|
59
|
+
echo "Installing fzf with brew..."
|
|
60
|
+
if ! command -v brew >/dev/null 2>&1; then
|
|
61
|
+
echo "Homebrew is not installed. Aborting."
|
|
62
|
+
return 1
|
|
63
|
+
fi
|
|
64
|
+
brew install fzf || { echo "fzf install failed. Aborting."; return 1; }
|
|
65
|
+
;;
|
|
66
|
+
*)
|
|
67
|
+
echo "Aborted (skipped fzf installation)."
|
|
68
|
+
return 1
|
|
69
|
+
;;
|
|
70
|
+
esac
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
# -----------------------------
|
|
74
|
+
# 2. Get commit count
|
|
75
|
+
# -----------------------------
|
|
76
|
+
local count="${1:-20}"
|
|
77
|
+
local abort_label="✖ Abort"
|
|
78
|
+
local current_branch
|
|
79
|
+
current_branch=$(git rev-parse --abbrev-ref HEAD)
|
|
80
|
+
|
|
81
|
+
# -----------------------------
|
|
82
|
+
# 3. Build commit list
|
|
83
|
+
# -----------------------------
|
|
84
|
+
local commit_list
|
|
85
|
+
commit_list=$(git log -n "$count" --format="%h|%s|%cr|%an" | while IFS='|' read -r hash subject date author; do
|
|
86
|
+
# Truncate subject if too long
|
|
87
|
+
if [[ ${#subject} -gt 60 ]]; then
|
|
88
|
+
subject="${subject:0:57}..."
|
|
89
|
+
fi
|
|
90
|
+
printf "%-8s %-60s %-15s %s\t%s\n" "$hash" "$subject" "$date" "$author" "$hash"
|
|
91
|
+
done)
|
|
92
|
+
|
|
93
|
+
if [[ -z "$commit_list" ]]; then
|
|
94
|
+
echo "No commits found."
|
|
95
|
+
return 0
|
|
96
|
+
fi
|
|
97
|
+
|
|
98
|
+
# Add abort option
|
|
99
|
+
commit_list+=$'\n'"$abort_label"$'\t'
|
|
100
|
+
|
|
101
|
+
# Create temp file
|
|
102
|
+
local commit_file
|
|
103
|
+
commit_file=$(mktemp)
|
|
104
|
+
echo "$commit_list" > "$commit_file"
|
|
105
|
+
|
|
106
|
+
# -----------------------------
|
|
107
|
+
# 4. Run fzf picker
|
|
108
|
+
# -----------------------------
|
|
109
|
+
local selection
|
|
110
|
+
selection=$(cat "$commit_file" | fzf \
|
|
111
|
+
--prompt="Commits on '$current_branch' > " \
|
|
112
|
+
-i \
|
|
113
|
+
--reverse \
|
|
114
|
+
--border \
|
|
115
|
+
--header="[TAB] select for revert | [Enter] revert selected | [ESC] exit
|
|
116
|
+
Showing last $count commits" \
|
|
117
|
+
--multi \
|
|
118
|
+
--delimiter=$'\t' \
|
|
119
|
+
--with-nth=1 \
|
|
120
|
+
--bind=enter:accept \
|
|
121
|
+
--preview='
|
|
122
|
+
line={}
|
|
123
|
+
if [[ "$line" == "✖ Abort"* ]]; then
|
|
124
|
+
echo "Exit without action";
|
|
125
|
+
else
|
|
126
|
+
hash=$(echo "$line" | cut -f2)
|
|
127
|
+
echo "Commit: $hash";
|
|
128
|
+
echo "";
|
|
129
|
+
git show --stat --color=always "$hash" 2>/dev/null;
|
|
130
|
+
echo "";
|
|
131
|
+
echo "─────────────────────────────────────────────────────";
|
|
132
|
+
echo "";
|
|
133
|
+
git show --color=always "$hash" 2>/dev/null | head -100;
|
|
134
|
+
fi
|
|
135
|
+
' \
|
|
136
|
+
--preview-window=right:50%
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
# Cleanup temp file
|
|
140
|
+
rm -f "$commit_file"
|
|
141
|
+
|
|
142
|
+
# ESC or Ctrl-C
|
|
143
|
+
if [[ -z "$selection" ]]; then
|
|
144
|
+
echo "Exited."
|
|
145
|
+
return 0
|
|
146
|
+
fi
|
|
147
|
+
|
|
148
|
+
# Abort option
|
|
149
|
+
if echo "$selection" | grep -q "^$abort_label"; then
|
|
150
|
+
echo "Aborted."
|
|
151
|
+
return 0
|
|
152
|
+
fi
|
|
153
|
+
|
|
154
|
+
# -----------------------------
|
|
155
|
+
# 5. Extract commit hashes and confirm revert
|
|
156
|
+
# -----------------------------
|
|
157
|
+
local commits_to_revert=()
|
|
158
|
+
|
|
159
|
+
while IFS= read -r line; do
|
|
160
|
+
[[ "$line" == "✖ Abort"* ]] && continue
|
|
161
|
+
local hash
|
|
162
|
+
hash=$(echo "$line" | cut -f2)
|
|
163
|
+
if [[ -n "$hash" ]]; then
|
|
164
|
+
commits_to_revert+=("$hash")
|
|
165
|
+
fi
|
|
166
|
+
done <<< "$selection"
|
|
167
|
+
|
|
168
|
+
if [[ ${#commits_to_revert[@]} -eq 0 ]]; then
|
|
169
|
+
echo "No commits selected."
|
|
170
|
+
return 0
|
|
171
|
+
fi
|
|
172
|
+
|
|
173
|
+
echo ""
|
|
174
|
+
echo "Selected commits to revert:"
|
|
175
|
+
for hash in "${commits_to_revert[@]}"; do
|
|
176
|
+
local subject
|
|
177
|
+
subject=$(git log -1 --format="%s" "$hash")
|
|
178
|
+
echo " - $hash: $subject"
|
|
179
|
+
done
|
|
180
|
+
echo ""
|
|
181
|
+
|
|
182
|
+
local confirm
|
|
183
|
+
read -rp "Revert these ${#commits_to_revert[@]} commit(s)? (y/N): " confirm
|
|
184
|
+
case "$confirm" in
|
|
185
|
+
[yY][eE][sS]|[yY])
|
|
186
|
+
echo "Reverting commits..."
|
|
187
|
+
|
|
188
|
+
# Reverse the array to revert oldest first (avoids conflicts)
|
|
189
|
+
local reversed=()
|
|
190
|
+
for ((i=${#commits_to_revert[@]}-1; i>=0; i--)); do
|
|
191
|
+
reversed+=("${commits_to_revert[$i]}")
|
|
192
|
+
done
|
|
193
|
+
|
|
194
|
+
for hash in "${reversed[@]}"; do
|
|
195
|
+
echo "Reverting $hash ..."
|
|
196
|
+
if git revert --no-edit "$hash"; then
|
|
197
|
+
echo "✓ Reverted $hash"
|
|
198
|
+
else
|
|
199
|
+
echo "✗ Failed to revert $hash (conflict?)"
|
|
200
|
+
echo " Resolve the conflict and run 'git revert --continue'"
|
|
201
|
+
return 1
|
|
202
|
+
fi
|
|
203
|
+
done
|
|
204
|
+
echo ""
|
|
205
|
+
echo "✓ All selected commits reverted."
|
|
206
|
+
;;
|
|
207
|
+
*)
|
|
208
|
+
echo "Revert cancelled."
|
|
209
|
+
;;
|
|
210
|
+
esac
|
|
211
|
+
}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# shellcheck disable=SC2155
|
|
3
|
+
|
|
4
|
+
create() {
|
|
5
|
+
# -----------------------------
|
|
6
|
+
# 0. Check for help flag
|
|
7
|
+
# -----------------------------
|
|
8
|
+
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
|
|
9
|
+
cat << 'EOF'
|
|
10
|
+
Usage: create [JIRA_LINK] [TITLE...]
|
|
11
|
+
|
|
12
|
+
Create a new git branch with the pattern: feature/<ISSUE>-<title>
|
|
13
|
+
|
|
14
|
+
Options:
|
|
15
|
+
-h, --help Show this help message
|
|
16
|
+
|
|
17
|
+
Configuration:
|
|
18
|
+
- Branch prefix can be changed by editing the 'GITBASH_FEATURE_BRANCH_PREFIX' variable
|
|
19
|
+
- Default: "feature/"
|
|
20
|
+
|
|
21
|
+
Interactive mode (no arguments):
|
|
22
|
+
$ create
|
|
23
|
+
Enter Jira link (e.g., https://jira.company.com/browse/PROJ-123):
|
|
24
|
+
> https://jira.company.com/browse/PROJ-123
|
|
25
|
+
Parsed issue number: PROJ-123
|
|
26
|
+
|
|
27
|
+
Enter branch title (will be converted to lowercase with dashes):
|
|
28
|
+
> Fix Login Bug
|
|
29
|
+
|
|
30
|
+
Branch name: feature/PROJ-123-fix-login-bug
|
|
31
|
+
Create this branch? (y/N): y
|
|
32
|
+
|
|
33
|
+
One-liner mode (with arguments):
|
|
34
|
+
$ create https://jira.company.com/browse/PROJ-123 fix login bug
|
|
35
|
+
Parsed issue number: PROJ-123
|
|
36
|
+
|
|
37
|
+
Branch name: feature/PROJ-123-fix-login-bug
|
|
38
|
+
Create this branch? (y/N): y
|
|
39
|
+
|
|
40
|
+
$ create PROJ-456 add user settings
|
|
41
|
+
Parsed issue number: PROJ-456
|
|
42
|
+
|
|
43
|
+
Branch name: feature/PROJ-456-add-user-settings
|
|
44
|
+
Create this branch? (y/N): y
|
|
45
|
+
|
|
46
|
+
Examples:
|
|
47
|
+
create https://jira.company.com/browse/PROJ-123 make some fixes
|
|
48
|
+
create PROJ-456 implement new feature
|
|
49
|
+
create https://company.atlassian.net/browse/ABC-789 refactor code
|
|
50
|
+
|
|
51
|
+
EOF
|
|
52
|
+
return 0
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
# -----------------------------
|
|
56
|
+
# 1. Get Jira link from user (or from arguments)
|
|
57
|
+
# -----------------------------
|
|
58
|
+
local jira_link
|
|
59
|
+
local branch_title
|
|
60
|
+
|
|
61
|
+
if [[ -n "${1:-}" ]]; then
|
|
62
|
+
# Arguments provided - use one-liner mode
|
|
63
|
+
jira_link="$1"
|
|
64
|
+
shift
|
|
65
|
+
# Join remaining arguments as title
|
|
66
|
+
branch_title="$*"
|
|
67
|
+
else
|
|
68
|
+
# Interactive mode
|
|
69
|
+
echo "Enter Jira link (e.g., https://jira.company.com/browse/PROJ-123):"
|
|
70
|
+
read -rp " > " jira_link
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
if [[ -z "$jira_link" ]]; then
|
|
74
|
+
echo "Error: No Jira link provided."
|
|
75
|
+
return 1
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
# -----------------------------
|
|
79
|
+
# 2. Parse issue number from Jira link
|
|
80
|
+
# -----------------------------
|
|
81
|
+
local issue_number
|
|
82
|
+
# First try to match just the issue number pattern (e.g., PROJ-123)
|
|
83
|
+
issue_number=$(echo "$jira_link" | grep -o -E '^[A-Z]+-[0-9]+$' | head -1)
|
|
84
|
+
|
|
85
|
+
# If not a direct match, try to extract from URL
|
|
86
|
+
if [[ -z "$issue_number" ]]; then
|
|
87
|
+
# Match patterns like PROJ-123, ABC-456, etc.
|
|
88
|
+
# Supports both /browse/PROJ-123 and selectedIssue=PROJ-123 formats
|
|
89
|
+
issue_number=$(echo "$jira_link" | grep -o -E '(browse/|selectedIssue=)[A-Z]+-[0-9]+' | grep -o '[A-Z]\+-[0-9]\+' | head -1)
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
if [[ -z "$issue_number" ]]; then
|
|
93
|
+
echo "Warning: Could not parse issue number from Jira link. Using NOISSUE."
|
|
94
|
+
issue_number="NOISSUE"
|
|
95
|
+
# If parsing failed and we had arguments, include the first arg in the title
|
|
96
|
+
if [[ -n "$branch_title" ]]; then
|
|
97
|
+
branch_title="$jira_link $branch_title"
|
|
98
|
+
else
|
|
99
|
+
branch_title="$jira_link"
|
|
100
|
+
fi
|
|
101
|
+
else
|
|
102
|
+
echo "Parsed issue number: $issue_number"
|
|
103
|
+
fi
|
|
104
|
+
echo
|
|
105
|
+
|
|
106
|
+
# -----------------------------
|
|
107
|
+
# 3. Get branch title from user (if not already provided)
|
|
108
|
+
# -----------------------------
|
|
109
|
+
if [[ -z "$branch_title" ]]; then
|
|
110
|
+
echo "Enter branch title (will be converted to lowercase with dashes):"
|
|
111
|
+
read -rp " > " branch_title
|
|
112
|
+
fi
|
|
113
|
+
|
|
114
|
+
if [[ -z "$branch_title" ]]; then
|
|
115
|
+
echo "Error: No branch title provided."
|
|
116
|
+
return 1
|
|
117
|
+
fi
|
|
118
|
+
|
|
119
|
+
# Convert title to lowercase and replace spaces/special chars with dashes
|
|
120
|
+
branch_title=$(echo "$branch_title" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g' | sed 's/^-//;s/-$//')
|
|
121
|
+
|
|
122
|
+
# -----------------------------
|
|
123
|
+
# 4. Construct branch name
|
|
124
|
+
# -----------------------------
|
|
125
|
+
local branch_prefix="${GITBASH_FEATURE_BRANCH_PREFIX:-feature/}"
|
|
126
|
+
local branch_name="${branch_prefix}${issue_number}-${branch_title}"
|
|
127
|
+
|
|
128
|
+
echo
|
|
129
|
+
echo "Branch name: $branch_name"
|
|
130
|
+
echo
|
|
131
|
+
|
|
132
|
+
# -----------------------------
|
|
133
|
+
# 5. Check if branch already exists
|
|
134
|
+
# -----------------------------
|
|
135
|
+
if git show-ref --verify --quiet "refs/heads/$branch_name"; then
|
|
136
|
+
echo "⚠ Branch '$branch_name' already exists locally."
|
|
137
|
+
read -rp "Switch to this branch instead? (Y/n): " ans
|
|
138
|
+
case "$ans" in
|
|
139
|
+
[nN][oO]|[nN])
|
|
140
|
+
echo "Aborted."
|
|
141
|
+
return 1
|
|
142
|
+
;;
|
|
143
|
+
*)
|
|
144
|
+
git checkout "$branch_name"
|
|
145
|
+
echo "✓ Switched to existing branch: $branch_name"
|
|
146
|
+
return 0
|
|
147
|
+
;;
|
|
148
|
+
esac
|
|
149
|
+
fi
|
|
150
|
+
|
|
151
|
+
# -----------------------------
|
|
152
|
+
# 6. Update main/master branch before creating new branch
|
|
153
|
+
# -----------------------------
|
|
154
|
+
# Detect base branch: main or master
|
|
155
|
+
local base_branch
|
|
156
|
+
if git show-ref --verify --quiet refs/heads/main; then
|
|
157
|
+
base_branch="main"
|
|
158
|
+
elif git show-ref --verify --quiet refs/heads/master; then
|
|
159
|
+
base_branch="master"
|
|
160
|
+
else
|
|
161
|
+
echo "⚠ Could not detect 'main' or 'master' branch. Creating branch from current HEAD."
|
|
162
|
+
base_branch=""
|
|
163
|
+
fi
|
|
164
|
+
|
|
165
|
+
if [[ -n "$base_branch" ]]; then
|
|
166
|
+
echo "Updating '$base_branch' from origin..."
|
|
167
|
+
if git fetch origin "$base_branch:$base_branch" 2>/dev/null; then
|
|
168
|
+
echo "✓ '$base_branch' is up to date."
|
|
169
|
+
else
|
|
170
|
+
echo "⚠ Could not update '$base_branch' from origin. Creating branch from local '$base_branch'."
|
|
171
|
+
fi
|
|
172
|
+
fi
|
|
173
|
+
|
|
174
|
+
# -----------------------------
|
|
175
|
+
# 7. Create branch
|
|
176
|
+
# -----------------------------
|
|
177
|
+
echo "Creating branch..."
|
|
178
|
+
if [[ -n "$base_branch" ]]; then
|
|
179
|
+
# Create branch from updated base branch
|
|
180
|
+
if git checkout -b "$branch_name" "$base_branch"; then
|
|
181
|
+
echo "✓ Successfully created and switched to branch: $branch_name (from $base_branch)"
|
|
182
|
+
else
|
|
183
|
+
echo "✗ Failed to create branch."
|
|
184
|
+
return 1
|
|
185
|
+
fi
|
|
186
|
+
else
|
|
187
|
+
# Fallback: create from current HEAD
|
|
188
|
+
if git checkout -b "$branch_name"; then
|
|
189
|
+
echo "✓ Successfully created and switched to branch: $branch_name"
|
|
190
|
+
else
|
|
191
|
+
echo "✗ Failed to create branch."
|
|
192
|
+
return 1
|
|
193
|
+
fi
|
|
194
|
+
fi
|
|
195
|
+
|
|
196
|
+
# -----------------------------
|
|
197
|
+
# 8. Push branch to origin and set up tracking
|
|
198
|
+
# -----------------------------
|
|
199
|
+
echo "Pushing branch to origin and setting up tracking..."
|
|
200
|
+
if git push -u origin "$branch_name"; then
|
|
201
|
+
echo "✓ Successfully pushed '$branch_name' to origin with tracking."
|
|
202
|
+
else
|
|
203
|
+
echo "⚠ Failed to push branch to origin. You can push it later with: git push -u origin $branch_name"
|
|
204
|
+
fi
|
|
205
|
+
}
|
package/commands/pr.sh
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
## pr opens the current pr, if in repo
|
|
2
|
+
pr() {
|
|
3
|
+
local should_push=false
|
|
4
|
+
|
|
5
|
+
# Parse arguments
|
|
6
|
+
while [[ $# -gt 0 ]]; do
|
|
7
|
+
case $1 in
|
|
8
|
+
-h|--help)
|
|
9
|
+
cat << 'EOF'
|
|
10
|
+
Usage: pr [OPTIONS]
|
|
11
|
+
|
|
12
|
+
Open the current branch's pull request in your browser.
|
|
13
|
+
If no PR exists, opens GitHub's compare page to create one.
|
|
14
|
+
|
|
15
|
+
Options:
|
|
16
|
+
-p, --push Push current branch to origin before opening PR
|
|
17
|
+
-h, --help Show this help message
|
|
18
|
+
|
|
19
|
+
Behavior:
|
|
20
|
+
- Must be run inside a git repository
|
|
21
|
+
- Uses the 'origin' remote URL
|
|
22
|
+
- Opens a compare URL for the current branch
|
|
23
|
+
- Automatically converts SSH URLs to HTTPS
|
|
24
|
+
|
|
25
|
+
Examples:
|
|
26
|
+
$ pr
|
|
27
|
+
# Opens: https://github.com/user/repo/compare/feature-branch?expand=1
|
|
28
|
+
|
|
29
|
+
$ git checkout feature/helix/LOVE-123-fix-bug
|
|
30
|
+
$ pr
|
|
31
|
+
# Opens: https://github.com/user/repo/compare/feature/helix/LOVE-123-fix-bug?expand=1
|
|
32
|
+
|
|
33
|
+
# Push before opening PR
|
|
34
|
+
$ pr -p
|
|
35
|
+
Pushing 'feature-branch' to origin...
|
|
36
|
+
✓ Successfully pushed 'feature-branch' to origin.
|
|
37
|
+
# Opens: https://github.com/user/repo/compare/feature-branch?expand=1
|
|
38
|
+
|
|
39
|
+
Notes:
|
|
40
|
+
- Works with both SSH and HTTPS remote URLs
|
|
41
|
+
- Opens in your default browser using the 'open' command
|
|
42
|
+
- Branch name is automatically URL-encoded by the browser
|
|
43
|
+
|
|
44
|
+
EOF
|
|
45
|
+
return 0
|
|
46
|
+
;;
|
|
47
|
+
-p|--push)
|
|
48
|
+
should_push=true
|
|
49
|
+
shift
|
|
50
|
+
;;
|
|
51
|
+
-*)
|
|
52
|
+
echo "Unknown option: $1"
|
|
53
|
+
echo "Usage: pr [-p|--push]"
|
|
54
|
+
return 1
|
|
55
|
+
;;
|
|
56
|
+
*)
|
|
57
|
+
echo "Unknown argument: $1"
|
|
58
|
+
echo "Usage: pr [-p|--push]"
|
|
59
|
+
return 1
|
|
60
|
+
;;
|
|
61
|
+
esac
|
|
62
|
+
done
|
|
63
|
+
|
|
64
|
+
# Ensure we're inside a Git repo
|
|
65
|
+
if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
66
|
+
echo "Not inside a git repository."
|
|
67
|
+
return 1
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
# Remote URL (e.g. git@github.com:user/repo.git or https://github.com/user/repo.git)
|
|
71
|
+
remote=$(git config --get remote.origin.url)
|
|
72
|
+
|
|
73
|
+
if [[ -z "$remote" ]]; then
|
|
74
|
+
echo "No remote 'origin' found."
|
|
75
|
+
return 1
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
# Convert SSH URLs to HTTPS URLs
|
|
79
|
+
remote_https=$remote
|
|
80
|
+
remote_https=${remote_https/git@github.com:/https://github.com/}
|
|
81
|
+
remote_https=${remote_https%.git}
|
|
82
|
+
|
|
83
|
+
# Current branch
|
|
84
|
+
branch=$(git rev-parse --abbrev-ref HEAD)
|
|
85
|
+
|
|
86
|
+
# Push if requested
|
|
87
|
+
if [[ "$should_push" == true ]]; then
|
|
88
|
+
# Check if remote has updates and pull first
|
|
89
|
+
git fetch origin "$branch" 2>/dev/null
|
|
90
|
+
local local_commit=$(git rev-parse HEAD)
|
|
91
|
+
local remote_commit=$(git rev-parse "origin/$branch" 2>/dev/null)
|
|
92
|
+
|
|
93
|
+
if [[ -n "$remote_commit" && "$local_commit" != "$remote_commit" ]]; then
|
|
94
|
+
# Check if we're behind the remote
|
|
95
|
+
if git merge-base --is-ancestor "$local_commit" "$remote_commit" 2>/dev/null; then
|
|
96
|
+
echo "Remote has updates. Pulling first..."
|
|
97
|
+
git pull --rebase origin "$branch"
|
|
98
|
+
if [[ $? -ne 0 ]]; then
|
|
99
|
+
echo "⚠ Failed to pull remote changes. Please resolve conflicts and try again."
|
|
100
|
+
return 1
|
|
101
|
+
fi
|
|
102
|
+
echo "✓ Pulled latest changes."
|
|
103
|
+
elif ! git merge-base --is-ancestor "$remote_commit" "$local_commit" 2>/dev/null; then
|
|
104
|
+
# Branches have diverged
|
|
105
|
+
echo "Remote has diverged. Pulling with rebase..."
|
|
106
|
+
git pull --rebase origin "$branch"
|
|
107
|
+
if [[ $? -ne 0 ]]; then
|
|
108
|
+
echo "⚠ Failed to pull remote changes. Please resolve conflicts and try again."
|
|
109
|
+
return 1
|
|
110
|
+
fi
|
|
111
|
+
echo "✓ Rebased on latest changes."
|
|
112
|
+
fi
|
|
113
|
+
fi
|
|
114
|
+
|
|
115
|
+
echo "Pushing '$branch' to origin..."
|
|
116
|
+
git push origin "$branch"
|
|
117
|
+
if [[ $? -eq 0 ]]; then
|
|
118
|
+
echo "✓ Successfully pushed '$branch' to origin."
|
|
119
|
+
else
|
|
120
|
+
echo "⚠ Failed to push '$branch' to origin."
|
|
121
|
+
return 1
|
|
122
|
+
fi
|
|
123
|
+
fi
|
|
124
|
+
|
|
125
|
+
# Construct compare URL
|
|
126
|
+
url="$remote_https/compare/$branch?expand=1"
|
|
127
|
+
|
|
128
|
+
# Open in browser
|
|
129
|
+
open "$url"
|
|
130
|
+
}
|