-
Notifications
You must be signed in to change notification settings - Fork 2
/
git.zsh
302 lines (260 loc) · 7.13 KB
/
git.zsh
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
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
alias gs='echo'
alias gd='git diff'
alias gdc='git diff --cached'
alias gl='git log --decorate'
alias glogS='git log -p -S '
alias gcommitgrep='git log --grep '
alias gpickaxe='git log -p -S '
alias gf='git fetch --prune'
alias gcommit='git commit'
alias gfixup='git commit --fixup=HEAD^1'
alias gca='git commit -a'
alias grebase='git rebase '
alias gnb='git checkout -b'
alias gcheckout='git checkout'
alias gpush='git push '
alias greset='git reset '
alias gpull='git pull --rebase'
alias gclone='git clone '
alias gstash='git stash '
alias gadd='git add '
alias gtags='git tag --list | sort -V'
alias gpushtags='git push origin --tags'
alias gtags-latest='git tag --list | sort -V | tail -n 1'
alias gl-last-tag-to-HEAD='git log $(git tag --list | sort -V | tail -n 1)..master'
alias gremotes='git remote -v'
alias gremote='git remote'
function _default_remote_branch {
output=$(git symbolic-ref refs/remotes/origin/HEAD 2>&1)
# For fresh repositories HEAD is not set
# https://stackoverflow.com/questions/45811971/warning-ignoring-broken-ref-refs-remotes-origin-head
if [[ $output == "fatal: ref refs/remotes/origin/HEAD is not a symbolic ref" ]]
then
git remote set-head origin master > /dev/null 2>&1
echo "master"
return
fi
git symbolic-ref refs/remotes/origin/HEAD | sed 's@^refs/remotes/origin/@@'
}
function gdom {
query=$1
if [ -z "$default_remote_branch" ]; then
local default_remote_branch=$(_default_remote_branch)
fi
if [[ "$query" == "--stat" ]]; then
git diff origin/$default_remote_branch --stat
return
fi
file=$(
git diff origin/"$default_remote_branch" --stat --color=always | \
fzf --query=$query --ansi --prompt "GitFiles?> " \
--preview="git diff origin/$default_remote_branch --color=always -- {1}" | \
awk '{print $1}'
)
[ ! -z $file ] && git diff origin/$default_remote_branch -- $file
}
function grom {
if [ -z "$default_remote_branch" ]; then
local default_remote_branch=$(_default_remote_branch)
fi
git fetch
git rebase origin/"$default_remote_branch"
}
gdob () { git diff origin/$(_local_branch) $@ }
compdef _git-diff gdob
alias ci-status='hub ci-status'
# alias pr='dht git pull-request'
alias squash='dht git autosquash'
# Initiate _git which exposes the _git-* completions
_git
# Retrieve local and remote branches sorted by last commit to the branch
fbranch() {
local branches=$(git branch --sort=committerdate -a |\
cut -c 3- |\
sed 's/^remotes\/origin\///' |\
sed '/HEAD/d' |\
uniq)
local branch=$(echo $branches | fzf --ansi --exact --tac --multi)
echo $branch
}
function gshow {
if [ -n "$1" ]; then
git show "$1"
else
local commit=`fcommit`
if [[ -n $commit ]]; then
cmd="git show $@ $commit"
print -s $cmd
eval $cmd
fi
fi
}
gcheckoutcommit() {
local commit=`fcommit`
if [[ -n $commit ]]; then
cmd="git checkout $@ $commit"
print -s $cmd
eval $cmd
fi
}
gcheckoutbranch() {
local branch_name=$(fbranch)
if [[ $branch_name =~ ^origin ]]; then
# Strip the origin part. If we don't do this it won't checkout a new branch but will be in
# detached state
branch_name=$(echo $branch_name | sed -e 's/^origin\///')
fi
if [[ -n $branch_name ]]; then
cmd="git checkout $@ $branch_name"
print -s $cmd
eval $cmd
fi
}
gresetbranch() {
local branch_name=$(fbranch)
if [[ -n $branch_name ]]; then
cmd="git reset $@ $branch_name"
print -s $cmd
eval $cmd
fi
}
compdef _git-reset gresetbranch
alias gcc=gcheckoutcommit
alias gcb=gcheckoutbranch
compdef _git-checkout gcheckoutcommit gcheckoutbranch
gresetfilefromhead() {
file=$(git diff-tree --no-commit-id --name-only -r HEAD | fzf)
if [[ -n $file ]]; then
git reset --soft HEAD^
git reset HEAD $file
cmd="git reset HEAD $file"
git commit -c ORIG_HEAD --amend
fi
}
grbc() {
local commit=`fcommit`
[[ -n $commit ]] && print -z git rebase -i $@ $commit
}
grbb() {
branch=`fbranch`
[[ -n $branch ]] && print -z git rebase $@ origin/$branch
}
compdef _git-rebase grbc grbb
# TODO: FZF preview window commit message
goneline() {
git log --pretty=oneline --decorate=short | \
fzf | \
awk '{print $1}' | \
tr -d '\n' | \
xclip -selection clipboard
}
gresetcommit() {
commit=`fcommit`
[[ -n $commit ]] && print -z git reset $@ $commit
}
gresetbranch() {
branch=`fbranch`
[[ -n $branch ]] && print -z git reset $@ "$branch"
}
compdef _git-reset gresetcommit gresetbranch
gformatpatch() {
commit=`fcommit`
[[ -n $commit ]] && print -z git format-patch $@ $commit
}
grevert() {
commit=`fcommit`
[[ -n $commit ]] && print -z git revert $@ $commit
}
compdef _git-format-patch gformatpatch
gsha1() {
print -z `fcommit`
}
_local_branch() {
git symbolic-ref --short HEAD
}
_remote_branch() {
remote=$(git remote)
if [ $? != 0 ]; then
return 1 # Returning $? will return the output of the if test.
fi
branch=$(_local_branch)
if [ $(echo $remote | wc -l) = 1 ]; then
echo "$remote $branch"
else
# If we have multiple remotes, default to origin
echo origin $branch
fi
}
function delete_dead_branches {
dead_branches=$(git branch --merged=master | egrep --invert-match '(master|production)')
echo $dead_branches | while read branch; do
# If branch name does not contain just whitespace
if [[ $branch = *[![:space:]]* ]]; then
git branch -d $branch
fi
done
}
gpullbranch() {
branch=$(_local_branch)
if [ $? = 0 ]; then
git fetch --prune
git pull $@ origin $branch
delete_dead_branches
fi
}
compdef _git-pull gpullbranch
gpushbranch() {
branch=$(_remote_branch)
[ $? = 0 ] && eval git push $@ $branch
}
compdef _git-push gpushbranch
alias gplb=gpullbranch
alias gpsb=gpushbranch
gcherry() {
current_branch=$(_local_branch)
unmerged_branch=$(git branch --no-merged $current_branch | cut -c 3- | fzf)
commits=$(git rev-list $unmerged_branch --not $current_branch --no-merges --pretty=oneline --abbrev-commit | fzf -m)
num_commits=$(echo $commits | wc -l)
if [[ $num_commits -gt '2' ]]; then
echo "Select 1 to 2 commits, starting at the oldest commit"
elif [[ $num_commits -eq '1' ]]; then
commit=$(echo $commits | awk '{print $1}')
print -z git cherry-pick "$commit"
elif [[ $num_commits -eq '2' ]]; then
first=$(echo $commits | awk '{if (NR==1) print $1}')
second=$(echo $commits | awk '{if (NR==2) print $1}')
cmd="git cherry-pick \"$first^..$second\""
print -s $cmd
eval "$cmd"
fi
}
function gcherrynewbranch {
python3 -c "import git_helpers; git_helpers.git_cherry_pick_new_branch()"
}
function gcherrypr {
python3 -c "import git_helpers; git_helpers.git_cherry_pick_new_branch()"
gpushbranch
hub pull-request --no-edit
}
function gdelbranch {
branches=$(fbranch)
if [ -z "$branches" ]; then
echo Provide a branch name
return
fi
while read -r branch; do
git branch -d "$branch"
git push origin --delete "$branch"
done <<< $branches
}
compdef _git-branch gdelbranch
function gdeltag {
tag_name=$1
if [ -z "$tag_name" ]; then
echo Provide a tag name
return
fi
git tag -d "$tag_name"
git push origin :"$tag_name"
}
compdef _git-branch gdeltag