Repository navigation
Expand file tree
/
Copy pathgit.bash
More file actions
238 lines (193 loc) · 6.36 KB
/
Copy pathgit.bash
File metadata and controls
238 lines (193 loc) · 6.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
#!/bin/bash
# Add ssh-key
eval && ssh-add "$HOME/.ssh/id_rsa"
# LazyGit
alias lg="lazygit"
alias gs="lg status"
alias lgl="lg log"
alias lgb="lg branch"
alias lgst="lg stash"
# Git
alias g="git"
alias gP="g pull"
alias gc="g commit --no-verify -m"
unalias gd 2>/dev/null
function gd() {
if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
git diff -w "$@"
return $?
fi
local has_cached=0
for arg in "$@"; do
if [[ "$arg" == "--cached" || "$arg" == "--staged" ]]; then
has_cached=1
break
fi
done
if [[ $has_cached -eq 1 ]]; then
git diff -w "$@"
return $?
fi
local tmp_untracked
tmp_untracked=$(mktemp) || {
git diff -w "$@"
return $?
}
git ls-files -z --others --exclude-standard -- ":/" > "$tmp_untracked" 2>/dev/null
if [[ ! -s "$tmp_untracked" ]]; then
rm -f "$tmp_untracked"
git diff -w "$@"
return $?
fi
local cleaned=0
cleanup() {
if [[ $cleaned -eq 0 ]]; then
cleaned=1
if [[ -f "$tmp_untracked" ]]; then
git reset -q --pathspec-from-file="$tmp_untracked" --pathspec-file-nul 2>/dev/null || true
rm -f "$tmp_untracked"
fi
fi
}
trap cleanup INT TERM EXIT
git add -N --pathspec-from-file="$tmp_untracked" --pathspec-file-nul 2>/dev/null || true
git diff -w "$@"
local ret=$?
cleanup
trap - INT TERM EXIT
return $ret
}
alias gds="gd --stat"
alias gch="g checkout"
alias grh="g reset --hard && gclean"
alias gpa="git-pull-all"
# Checkout a branch, most recently visited first (from the reflog), then the rest alphabetically
unalias gb 2>/dev/null
function gb() {
local branches
branches=$(git branch --all --format='%(refname:short)' | sed -e 's|^origin/||' -e 's|^remotes/origin/||' | grep -Ev '^(HEAD|\(HEAD|origin/HEAD)' | sort -u) || return $?
local recent
recent=$(git reflog --format='%gs' 2>/dev/null | awk '/^checkout: moving from / { print $NF; print $4 }' | sed 's|^origin/||')
# Keep only existing branches (drops detached SHAs), first occurrence wins
printf '%s\n%s\n' "$recent" "$branches" \
| awk 'FNR == NR { ok[$0] = 1; next } ok[$0] && !seen[$0]++' <(printf '%s\n' "$branches") - \
| fzf --header 'Select branch to checkout:' --tiebreak=index --preview 'git show --color=always {-1}' --bind 'enter:become(git checkout {-1})' --height 50% --layout reverse
}
# Switch to another worktree of the current repo (agent-locked ones are flagged)
unalias gw 2>/dev/null
function gw() {
if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
echo "gw: not inside a git repository" >&2
return 1
fi
local current_root
current_root=$(git rev-parse --show-toplevel) || return $?
# One row per live worktree: "<label>\t<dir>". Prunable (deleted) worktrees are skipped
local rows
rows=$(git worktree list --porcelain | awk -v cur="$current_root" '
function flush() {
if (dir != "" && !prunable) {
label = (branch != "" ? branch : "(detached " substr(head, 1, 7) ")")
if (dir == cur) label = "● " label
if (lock != "") label = label " 🔒 " lock
printf "%s\t%s\n", label, dir
}
dir = ""; head = ""; branch = ""; lock = ""; prunable = 0
}
/^worktree / { flush(); dir = substr($0, 10); next }
/^HEAD / { head = substr($0, 6); next }
/^branch / { branch = substr($0, 8); sub(/^refs\/heads\//, "", branch); next }
/^locked/ { lock = substr($0, 8); if (lock == "") lock = "locked"; next }
/^prunable/ { prunable = 1; next }
END { flush() }
') || return $?
if [[ $(printf '%s\n' "$rows" | grep -c .) -le 1 ]]; then
echo "gw: no other worktrees in $current_root"
return 0
fi
# Match the query against the label only; the shared parent path would fuzzy-match everything
local wt_line
wt_line=$(printf '%s\n' "$rows" | fzf --header 'Select worktree to switch to:' --delimiter '\t' --nth 1 --tiebreak=index \
--query "$*" --select-1 --exit-0 \
--preview 'git -C {2} -c color.status=always status -sb; echo; git -C {2} log --oneline --color=always -n 20' \
--height 50% --layout reverse)
[[ -n "$wt_line" ]] || return 0
local wt_dir
wt_dir=$(printf '%s\n' "$wt_line" | cut -f2)
cd -- "$wt_dir" || return $?
if [[ "$wt_line" == *"🔒 claude-skill:"* ]]; then
echo "gw: warning — an agent is working in this worktree; avoid checkout/stash/edits here" >&2
fi
}
alias gclean="g clean -f"
alias gst="g status"
alias gcwip="g add . && g status && gc wip && gp"
function gcw() {
git add . || return $?
git status || return $?
if git diff --cached --quiet; then
echo "Nothing to commit, working tree clean."
return 0
fi
local msg="$*"
if [ -z "$msg" ]; then
printf "\nEnter commit message: "
read -r msg
fi
if [[ -z "${msg// }" ]]; then
echo "Commit message cannot be empty. Aborted."
return 1
fi
git commit --no-verify -m "$msg" || return $?
local current_branch
current_branch=$(git symbolic-ref --short HEAD 2>/dev/null)
if [ -n "$current_branch" ] && [ -z "$(git config branch.${current_branch}.remote)" ]; then
echo "No upstream branch set for ${current_branch}. Setting it now..."
git push --set-upstream origin "$current_branch"
else
git push
fi
}
alias meligo="run_fzf_json meligo --title 'Meligo Azure Logs'"
function gdw() {
SEARCH=$1
if [[ ! $SEARCH ]]; then
echo "Usage: gdw <string>"
return
fi
gd "*$SEARCH*"
}
# Create and push a tag to Bitbcket
function gt() {
g tag "$1" && g push origin "$1"
}
# Commit and push the changes
function gP() {
if [ -n "$1" ]; then
gc "$1"
fi
# Check if the current branch has an upstream branch
CURRENT_BRANCH=$(git symbolic-ref --short HEAD)
if [ -z "$(git config branch.${CURRENT_BRANCH}.remote)" ]; then
echo "No upstream branch set for ${CURRENT_BRANCH}. Setting it now..."
git push --set-upstream origin "$CURRENT_BRANCH"
else
g push origin
fi
}
# Push a specific local branch without switching to it
function gpb() {
local branch="$1"
if [ -z "$branch" ]; then
if command -v fzf >/dev/null 2>&1; then
branch=$(git branch --format='%(refname:short)' | fzf --header 'Select branch to push:' --preview 'git show --color=always {-1}' --height 50% --layout reverse)
fi
else
shift
fi
if [ -z "$branch" ]; then
echo "Usage: gpb <branch-name> [git push options...]"
return 1
fi
git push origin "$branch:$branch" "$@"
}