-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgit-fixup
85 lines (74 loc) · 2.22 KB
/
git-fixup
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
#!/bin/bash
# git-fixup (https://github.com/keis/git-fixup)
SUBDIRECTORY_OK=yes
. "$(git --exec-path)/git-sh-setup"
# Define a sed program that turns `git diff` output into a stream of filenames
# and sections within those files.
grok_diff='/^--- .*/p ;
s/^@@ -\([0-9]*\),\([0-9]*\).*/\1 \2/p'
# Produce suggestion of commits by finding the sections of files with changes
# staged (U1 to diff is used to give some context for when adding items to
# lists etc) and looking up the previous commits touching those sections.
function fixup_candidates_lines () {
git diff --cached -U1 --no-prefix | sed -n "$grok_diff" | (
file=''
while read offs len; do
if test "$offs" == '---'; then
file="$len"
else
if test "$len" != '0'; then
if test "$file" != '/dev/null'; then
git blame -sl -L "$offs,+$len" $rev_range -- "$file"
fi
fi
fi
done
) | grep -v "^^" | cut -d' ' -f 1 | sed 's/^/L /g'
}
# Produce suggestion of commits by taking the latest commit to each file with
# staged changes
function fixup_candidates_files () {
git diff --cached --name-only | (
while read file; do
git rev-list $rev_range -- $file \
| grep -v -f <(git rev-list -E --grep='^(fixup|squash)' $rev_range -- $file )
done
) | sed 's/^/F /g'
}
# Pretty print details of a commit
function print_sha () {
local sha=$1
local type=$2
git --no-pager log --format="%H [$type] %s <%ae>" -n 1 "$sha"
}
op="fixup"
case "$1" in
-s|--squash)
op="squash"
shift
;;
esac
if test $# -eq 1; then
git commit --$op=$1
exit
fi
if git diff --cached --quiet; then
echo 'No staged changes. Use git add -p to add them.' >&2
exit 1
fi
cd_to_toplevel
upstream=`git rev-parse @{upstream} 2>/dev/null`
head=`git rev-parse HEAD 2>/dev/null`
if test -z "$upstream" -o "$upstream" = "$head"; then
rev_range="HEAD"
else
rev_range="@{upstream}..HEAD"
fi
(
fixup_candidates_lines
fixup_candidates_files
) | sort -uk2 | while read type sha; do
if test "$sha" != ""; then
print_sha "$sha" "$type"
fi
done