-
-
Notifications
You must be signed in to change notification settings - Fork 59
/
Copy path.git_aliases
383 lines (341 loc) · 16.2 KB
/
.git_aliases
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
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
# This file is part of eRCaGuy_dotfiles: https://github.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles
# ==================================================================================================
# These are bash "git aliases", meaning that they are bash aliases that are intended to be related
# to or used by `git`. This file is sourced by the ".bash_aliases" file.
#
# NB: Most of my custom git commands and scripts are NOT in this alias file. Rather, they are in
# the "eRCaGuy_dotfiles/useful_scripts" folder, and are generally named "git-*".
# ==================================================================================================
# See which files have changed since some prior commit named `MY_FIRST_COMMIT`.
# Usage:
# gs_git_files_changed MY_FIRST_COMMIT~
# OR (same thing):
# gs_git_files_changed BASE_COMMIT
# Known limitations: works only on filenames which have no spaces or special bash chars. To make
# it handle these chars, it will require using `git diff --name-only -z`, with some more
# fancy bash trickery. See my ans:
# https://stackoverflow.com/questions/28109520/how-to-cope-with-spaces-in-file-names-when-iterating-results-from-git-diff-nam/62853776#62853776
gs_git_list_files_changed() {
files="$(command git diff --name-only "$1")"
echo "These are the changed files:"
echo "$files"
# Now optionally create a new function from this and do something with these files here if you
# want!
}
############ TODO: fix this up!
# 1. make it stand-alone
# 2. make it work as `git branch_hash_bak [optional message]`
# - let the optional message just be the remainder of the arguments, so it doesn't require a quote
# - however, force it to not contain spaces, so replace spaces with underscores
# - add the optional message into the filename itself at the end
############
# GS: git branch backups: useful to back up git branch hashes before deleting branches, so you can
# always have their hashes to go back to to checkout rather than having to dig through your `git
# reflog` forever.
# - Note that this currently requires that the GIT_BRANCH_HASH_BAK_DIR directory already exists.
# - TODO: fail more gracefully: make it check to see if this dir exists & prompt the user for
# permission to auto-create it with `mkdir -p ${GIT_BRANCH_HASH_BAK_DIR}` if it does not.
#
# Syntax: `gs_git_branch_hash_bak [dir]` = back up to a backup file in directory "dir" if a dir is
# passed in.
##############
#
# Example usage:
#
# # back up to `$GIT_BRANCH_HASH_BAK_DEFAULT_DIR`
# gs_git_branch_hash_bak
#
# # back up to "../some/dir"
# gs_git_branch_hash_bak "../some/dir"
#
# # back up to "../some/dir", with the user phrase "about_to_delete_branches!" at the end
# # of the filename
# gs_git_branch_hash_bak "../some/dir" about to delete branches!
#
GIT_BRANCH_HASH_BAK_DEFAULT_DIR="git_branch_hash_backups"
gs_git_branch_hash_bak() {
CMD="gs_git_branch_hash_bak"
GIT_BRANCH_HASH_BAK_DIR="$GIT_BRANCH_HASH_BAK_DEFAULT_DIR"
EXIT_SUCCESS=0
EXIT_ERROR=1
# Help menu
if [ "$1" == "-h" ] || [ "$1" == "-?" ]; then
echo "This is a bash function in \".git_aliases\" which backs up git branch"
echo "names & short hashes to your local \"${GIT_BRANCH_HASH_BAK_DEFAULT_DIR}\" (or other"
echo "specified) dir."
echo ""
echo "Usage: $CMD [dir]"
echo " Back up branch names and hashes to a backup file in directory \"dir\"."
return $EXIT_SUCCESS
fi
if [ -n "$1" ]; then
# If an arg is passed in, then use it instead of the default directory!
GIT_BRANCH_HASH_BAK_DIR="$1"
shift # past argument (`$1`)
fi
# accept all additional arguments as words in a phrase to append to the end of the file name!
user_added_phrase=""
i=0
num_words="${#@}"
for word in "$@"; do
user_added_phrase+="$word"
# add underscores between words
if [ "$i" -lt "$((num_words-1))" ]; then
user_added_phrase+="_"
fi
((i++))
done
echo "user_added_phrase = $user_added_phrase" # debugging
mkdir -p "$GIT_BRANCH_HASH_BAK_DIR"
DATE=`date +%Y%m%d-%H%Mhrs-%Ssec`
BRANCH="$(gs_git_show_branch_and_hash_no_formatting)"
REPO_ROOT="$(command git rev-parse --show-toplevel)"
REPO=$(basename "$REPO_ROOT") # repository name
# Replace any spaces in the repository name with underscores
# See: https://stackoverflow.com/questions/19661267/replace-spaces-with-underscores-via-bash/19661428#19661428
REPO="${REPO// /_}"
if [ "$user_added_phrase" = "" ]; then
FILE="${GIT_BRANCH_HASH_BAK_DIR}/${REPO}__git_branch_bak--${DATE}.txt"
else
FILE="${GIT_BRANCH_HASH_BAK_DIR}/${REPO}__git_branch_bak--${DATE}__${user_added_phrase}.txt"
fi
echo "Backing up 'git branch -vv' info to \"$FILE\"."
echo -e "date = \"$DATE\"" > $FILE
echo -e "repo (folder) name = \"$REPO\"" >> $FILE
echo -e "repo root = \"$REPO_ROOT\"" >> $FILE
echo -e "pwd = \"$(pwd)\"" >> $FILE
echo -e "current branch name & short hash = \"$BRANCH\"" >> $FILE
echo -e "user-added phrase / notes = \"$user_added_phrase\"" >> $FILE
echo -e "\n=== \`git branch -vv\` ===\n" >> $FILE
command git branch -vv >> $FILE
echo "Done!"
}
#
# Alias function to do the git hash backups in a directory **1 level higher than the root of the
# base repo** so that it won't back up the branch information *within the repo*, which would
# necessitate that you add this backup dir to this git project's .gitignore file.
# - In the event of nested repos (ie: you are in a subrepo), this function will find the root of
# the **parent** (outer) repo, and then go 1 level up from that, meaning it has found **1 level
# up** from the base, or most-outer, repo.
# - This function accepts a user-added phrase as well, to append to the end of the filename!
#
# Example usage:
#
# # back up to "REPO_ROOT/../$GIT_BRANCH_HASH_BAK_DEFAULT_DIR"
# gs_git_branch_hash_bak_up1 <======
#
# # back up to "REPO_ROOT/../$GIT_BRANCH_HASH_BAK_DEFAULT_DIR", with the user
# # phrase "about_to_delete_branches!" at the end of the filename <========
# gs_git_branch_hash_bak_up1 about to delete branches!
#
gs_git_branch_hash_bak_up1() {
local RETURN_CODE_SUCCESS=0
local RETURN_CODE_ERROR=1
# 1st, try to grab the outer repo root path, if this project is a subrepo. This obtains an empty
# string if this is NOT a subrepo.
BASE_REPO_ROOT="$(command git rev-parse --show-superproject-working-tree)" || return $RETURN_CODE_ERROR
if [ -z "$BASE_REPO_ROOT" ]; then
# If not in a subrepo, then try to grab the root of the regular repo.
BASE_REPO_ROOT="$(command git rev-parse --show-toplevel)" || return $RETURN_CODE_ERROR
echo "You are NOT in a subrepo. BASE_REPO_ROOT=$BASE_REPO_ROOT" # debugging
else
echo "You ARE in a subrepo. BASE_REPO_ROOT=$BASE_REPO_ROOT" # debugging
fi
BACKUP_DIR="$BASE_REPO_ROOT/../$GIT_BRANCH_HASH_BAK_DEFAULT_DIR"
gs_git_branch_hash_bak "$BACKUP_DIR" "$@"
}
# Get just the date stamp of the last commit. You can optionally pass in a branch name or commit
# hash.
# Usage:
# gs_git_log_get_last_commit_date [commit_hash]
gs_git_log_get_last_commit_date() {
# get the committer date; see this A to my Q: https://stackoverflow.com/a/71385517/4561887
# Use `"%ad"` for Author Date, or `"%cd"` for Commit Date (aka: Committer Date).
# author_date="$(git log -1 --format="%ad" "$@")"
committer_date="$(command git log -1 --format="%cd" "$@")"
if [ "$?" -ne "0" ]; then
# Error: there are no commits yet in this repo.
# > fatal: your current branch 'main' does not have any commits yet
echo "" # pass out an empty string to indicate no commits yet
return 1
fi
# Now strip off the last space-separated word in order to throw away the time zone portion
# of the date
# str_array=($committer_date)
# str_array_len="${#str_array[@]}"
# str_array_len_minus_one=$((str_array_len - 1))
# committer_date="${str_array[@]:0:$str_array_len_minus_one}"
# Better way to strip the time zone off the end of the date
committer_date="${committer_date% *}"
echo "$committer_date"
}
# Git commit range:
# Run `git commit` with a random time and date stamp for both the **author** (via the `--date`
# option) AND the **committer** (via the `GIT_COMMITTER_DATE` variable). This is a demo script
# to show how to rewrite git history, correct dates, do `date` math with `date -d`, use random
# numbers, etc. Use it as a learning starting point if you ever need to do something weird like
# this to correct errors in timestamps in your repo.
#
# NB: To see `git log` with **author** AND **committer** dates, run:
# git log --pretty=fuller
# NB: install `random` from: "eRCaGuy_dotfiles/useful_scripts/random.sh"
#
# Usage:
# gs_git_commit [<min_minutes> <max_minutes>]
#
# References:
# 1. My Q here: How to make `git log` show only the commit date, nothing else:
# https://stackoverflow.com/q/71384830/4561887
# 1. How can one change the timestamp of an old commit in Git?:
# https://stackoverflow.com/a/9701130/4561887
gs_git_commit_r() {
local RETURN_CODE_SUCCESS=0
local RETURN_CODE_ERROR=1
DEFAULT_MIN_MINUTES="3"
DEFAULT_MAX_MINUTES="20"
# set defaults
min_minutes="$DEFAULT_MIN_MINUTES"
max_minutes="$DEFAULT_MAX_MINUTES"
if [ "$#" -eq "1" ] && [ "$1" != "-h" ] && [ "$1" != "--help" ]; then
echo "ERROR: incorrect number of arguments (you must pass 0 or 2 args; see '--help' menu)."
return 1
# 'gs_git_commit min_minutes max_minutes'
elif [ "$#" -eq "2" ]; then
min_minutes="$1"
max_minutes="$2"
else
if [ "$1" != "-h" ] && [ "$1" != "--help" ]; then
echo "ERROR: too many arguments."
return 1
fi
fi
SECONDS_PER_MINUTE=60
range_minutes=$((max_minutes - min_minutes))
min_seconds=$((min_minutes*SECONDS_PER_MINUTE))
max_seconds=$((max_minutes*SECONDS_PER_MINUTE))
range_seconds=$((max_seconds - min_seconds))
# NB: install `random` from: "eRCaGuy_dotfiles/useful_scripts/random.sh"
random_seconds="$(random "$min_seconds" "$max_seconds")"
ret_code="$?"
if [ "$ret_code" -ne "$RETURN_CODE_SUCCESS" ]; then
echo -e "\n>> ERROR: 'random' failed with ret_code $ret_code. It may not" \
"be installed. Install it from" \
"\"eRCaGuy_dotfiles/useful_scripts/random.sh\". <<"
return $RETURN_CODE_ERROR
fi
random_minutes="$(bc <<< "scale=2; $random_seconds/$SECONDS_PER_MINUTE")"
last_commit_date_in_repo="$(gs_git_log_get_last_commit_date)"
last_commit_date_in_tmp_dir="$last_commit_date_in_repo"
if [ -f "/tmp/llccdd" ]; then
last_commit_date_in_tmp_dir="$(cat "/tmp/llccdd")"
fi
# debugging
# echo "last_commit_date_in_repo = $last_commit_date_in_repo"
# echo "last_commit_date_in_tmp_dir = $last_commit_date_in_tmp_dir"
# Convert dates to Unix timestamps
last_commit_date_in_repo_sec="$(date -d "$last_commit_date_in_repo" +%s)"
last_commit_date_in_tmp_dir_sec="$(date -d "$last_commit_date_in_tmp_dir" +%s)"
# debugging
# echo "last_commit_date_in_repo_sec = \"$last_commit_date_in_repo_sec\""
# echo "last_commit_date_in_tmp_dir_sec = \"$last_commit_date_in_tmp_dir_sec\""
# Handle the edge case where you're in an initialized but empty git repo
# with no commits yet. In this case, the `last_commit_date_in_repo` will be
# an empty string. So, force the math to come out right in the next check
# where we compare the two dates.
if [ -z "$last_commit_date_in_repo" ]; then
last_commit_date_in_repo_sec="0"
fi
# debugging
# echo "last_commit_date_in_repo_sec = \"$last_commit_date_in_repo_sec\""
# echo "last_commit_date_in_tmp_dir_sec = \"$last_commit_date_in_tmp_dir_sec\""
# Get the most recent date
if [ "$last_commit_date_in_repo_sec" -ge "$last_commit_date_in_tmp_dir_sec" ]; then
last_commit_date="$last_commit_date_in_repo"
else
last_commit_date="$last_commit_date_in_tmp_dir"
fi
new_date="$(date +"%a %b %-d %H:%M:%S %Y %z" -d "$last_commit_date + $random_seconds seconds")"
# debug prints
echo "DEBUG PRINTS:"
echo " min_minutes = $min_minutes"
echo " max_minutes = $max_minutes"
echo " range_minutes = $range_minutes"
echo " ---"
echo " min_seconds = $min_seconds"
echo " max_seconds = $max_seconds"
echo " range_seconds = $range_seconds"
echo " ==="
echo " last_commit_date_in_repo = \"$last_commit_date_in_repo\""
echo " last_commit_date_in_tmp_dir = \"$last_commit_date_in_tmp_dir\""
echo " last_commit_date (more recent) = \"$last_commit_date\""
echo " random_seconds = $random_seconds"
echo " random_minutes = $random_minutes"
echo " new_date = \"$new_date\""
echo ""
# help menu / dry-run
if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
echo "$last_commit_date" > "/tmp/llccdd"
# Update the temporary file
echo "=========="
echo "HELP MENU:"
echo "=========="
echo "Git commit range: run 'git commit' with a random time and date stamp."
echo "Usage: gs_git_commit_r [<min_minutes> <max_minutes>]"
echo "Run 'git log --pretty=fuller' to see 'git log' with both **author** AND" \
"**commit** dates!"
echo "---------"
echo "DEFAULT_MIN_MINUTES = $DEFAULT_MIN_MINUTES"
echo "DEFAULT_MAX_MINUTES = $DEFAULT_MAX_MINUTES"
echo "---------"
echo "last_commit_date_in_repo = \"$last_commit_date_in_repo\""
echo "last_commit_date_in_tmp_dir = \"$last_commit_date_in_tmp_dir\""
echo "last_commit_date (more recent) = \"$last_commit_date\""
echo "random_seconds = $random_seconds"
echo "random_minutes = $random_minutes"
echo "new_date = \"$new_date\""
echo "---"
echo "Date now:"
echo 'date_now="$(date +"%a %b %-d %H:%M:%S %Y %z")"'
date_now="$(date +"%a %b %-d %H:%M:%S %Y %z")"
echo "date_now=\"$date_now\""
echo 'GIT_COMMITTER_DATE="$date_now" git commit --date "$date_now"'
echo 'GIT_COMMITTER_DATE="$date_now" git commit --amend'
echo "gcr -h"
echo "---"
echo "Last commit date in repo:"
echo "last_commit_date_in_repo=\"$last_commit_date_in_repo\""
echo 'GIT_COMMITTER_DATE="$last_commit_date_in_repo" git commit --date "$last_commit_date_in_repo"'
echo 'GIT_COMMITTER_DATE="$last_commit_date_in_repo" git commit --amend'
echo "gcr -h"
echo "---"
echo "New date:"
echo "new_date=\"$new_date\""
echo 'GIT_COMMITTER_DATE="$new_date" git commit --date "$new_date"'
echo 'GIT_COMMITTER_DATE="$new_date" git commit --amend'
echo "gcr -h"
echo "---"
return 0
fi
# NB: The `--date` option sets the **author** date stamp, and the variable `GIT_COMMITTER_DATE`
# sets the **committer** date stamp.
# See:
# 1. My Q here: How to make `git log` show only the commit date, nothing else:
# https://stackoverflow.com/q/71384830/4561887
# 1. How can one change the timestamp of an old commit in Git?:
# https://stackoverflow.com/a/9701130/4561887
GIT_COMMITTER_DATE="$new_date" command git commit --date "$new_date"
ret_code="$?"
# echo "ret_code = $ret_code" # debugging
if [ "$ret_code" -ne "$RETURN_CODE_SUCCESS" ]; then
echo "$last_commit_date" > "/tmp/llccdd"
echo -e "\n>> ERROR: 'git commit' failed with ret_code $ret_code. <<"
return $RETURN_CODE_ERROR
fi
last_commit_date="$new_date"
# Strip the time zone off the end of the date
last_commit_date="${last_commit_date% *}"
# Save the most recent date to a file for next time
echo "$last_commit_date" > "/tmp/llccdd"
}
alias git_commit_r="gs_git_commit_r"
alias gcr="gs_git_commit_r"