-
Notifications
You must be signed in to change notification settings - Fork 6
/
git-edit-commit
executable file
·80 lines (74 loc) · 2.27 KB
/
git-edit-commit
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
#!/usr/bin/env bash
#
# Run a rebase to `edit` or `reword` a specific commit:
#
# ```bash
# # Open the 3th commit back from HEAD, in rebase "edit" mode.
# # A subsequent `rebase --continue` will rebase the remaining 3 commits on top of it.
# git edit-commit HEAD~3
#
# # "Dry run" of the above:
# git edit-commit -n HEAD~3
# # Would run git rebase -i d6aae97^:
# # edit d6aae97 rm orphaned(?) `commit-filename{,s}` aliases
# # pick ed9447b `cmba="commit-body -a"`, `cnb="commit-body --amend"`
# # pick df33af4 `git-diff-json.py` fixes
# # pick 3c166c3 `dtl`/`details`: commit details
#
# # Same as above, but preserve the "committer dates" of `HEAD^` and `HEAD` (`g rcd` = `git reset-committer-date-rebase-head`)
# git edit-commit -r "new message" -x "g rcd" HEAD^
#
# # As a demonstration, this is effectively a no-op (same HEAD SHA before and after).
# # `gby = git body = git log -1 --format=%B`, so this rewrites the parent commit with the same
# # message, and preserves its committer date.
# git edit-commit -r "`gby HEAD^`" -x "g rcd" HEAD^
# ```
dry_run=()
exec=
reword=
reword_file=
cmd=edit
while [ $# -gt 0 ]; do
case "$1" in
-n) shift; dry_run=(-n) ;;
-p) shift; exec="git reset-committer-date-rebase-head" ;;
-r) shift; reword="$1"; reword_file="$(mktemp)"; cmd=pick; shift ;;
-x) shift; exec="$1"; shift ;;
*) break ;;
esac
done
if [ $# -ne 1 ]; then
echo "Usage: $0 [-n] [-p | -x <cmd>] [-r] <commit>" >&2
echo " -n: dry run" >&2
echo " -p: preserve committer date" >&2
echo " -r: reword commit message (default: \"edit\" commit" >&2
echo " -x: execute command after each commit" >&2
exit 1
fi
ref="$1"; shift
ref="$(git log -1 --format=%h "$ref")"
sbj="$(git log -1 --format=%s "$ref")"
exec_line() {
if [ -n "$exec" ]; then
echo "exec $exec"
fi
}
(
echo "$cmd $ref $sbj"
if [ -n "$reword" ]; then
echo "$reword" > "$reword_file"
echo "exec git commit --amend -F$reword_file"
fi
exec_line
git log --reverse "--format=%h %s" "$ref..HEAD" | \
while IFS= read -r line; do
echo "pick $line"
exec_line
done
) | git rebase-stdin "${dry_run[@]}" "$ref^"
cleanup() {
if [ -n "$reword_file" ]; then
rm -f "$reword_file"
fi
}
trap cleanup EXIT