-
Notifications
You must be signed in to change notification settings - Fork 0
/
git-rr
executable file
·108 lines (101 loc) · 4.73 KB
/
git-rr
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
#!/bin/bash
# Get current branch, without initial "heads/"
BRANCH=$(git rev-parse --abbrev-ref HEAD)
# Kill the "git log" paging features
PAGER=
# Which branch to start with, might be given as the lone parameter.
STARTBRANCH=${1:-master}
# The "start branch" might be a SHA, in which case the user _might_ prefer it
# to see/use the symbolic name for it instead.
if [[ "$STARTBRANCH" =~ ^[a-fA-F0-9]{8,40}$ ]]; then
possible=$(git name-rev --name-only "$STARTBRANCH")
# f00f00 -> "master" great!
# f00f00 -> "master~2" screw it.
if [[ ! "$possible" =~ ~[1-9][0-9]*$ ]]; then
STARTBRANCH=$possible
fi
fi
# Lines look like:
# * c0ffee00 commit message1
# FILE00001 path/to/file1
# <-= newline
# * 00c0ffee commit message2
# FILE00001 path/to/file1
# FILE00002 path/to/file2
# <-= newline
echo "### navigate commits with /pick and 'n' or 'N'"
echo "### use 'd/pick' on a line below 'pick' to clear the files changed by a specific commit"
echo "### START Rebasing branch $BRANCH onto $STARTBRANCH (${1:-master})"
echo "#"
git log --reverse --pretty=format:'* %h %s' --abbrev-commit --stat --name-only "$STARTBRANCH.." | perl -lne'
BEGIN {
%seen = ();
%used = ();
$file = 1;
@lines = ();
}
s!\s*$!!; # kill any trailing spaces
if ( m!^\*! ) {
s!^\*!pick !; # by default, show "pick"
push @lines, $_;
} elsif (/^\s*$/) { # skip whitespace-only lines
next;
} else { # a "file name" line
$seen{$_} = $file++ # track which "unique file number" is it
if !$seen{$_};
$used{$_}++; # track how many times it has been "seen"
push @lines, $_;
}
END {
# Sort file names by how many times they appear in the list of commits
# or just by file name if they appear the same amount of times.
my @sorted = reverse sort { $used{$a} <=> $used{$b} || $a cmp $b } keys %used;
# Rename those file names as FILE00001..FILEfffff with FILE00001 being
# the most seen one, and FILEfffff being the least seen one.
my %renamed = map { ( $sorted[$_] => sprintf "FILE%05x", $_ + 1 ) } 0..$#sorted;
# Show the list of commits, and a commented-out "file id, file name" for
# the files used lines.
for my $line (@lines) {
print exists $used{$line}
? sprintf "# %s %s", $renamed{$line}, $line
: $line;
}
}
'
# Empty line allows Vim users to use "}" to go to the end of the commit list,
# to more easily find the last one.
echo ""
echo "### END Rebasing branch $BRANCH onto $STARTBRANCH (${1:-master})"
### Example ~/.vimrc to use this:
### " Run "git rr" when first entering a rebase buffer; don't do it if it has
### " already "been tampered with" (which is easy to check as all added lines
### " start with a '###', thus the first line's first "word" is ###
### " The buffer should also contain what thing we're rebasing towards, i.e.:
### " # Rebase 8fc2f00f00..83d8f00f00 onto 8fc2f00f00 (9 commands)
### " ^^^^^ target "start"
### " ... which can be used to infer what, if anything, we should pass "git-rr"
### " to ensure it performs the "right" rebase.
### autocmd BufEnter *
### \ if &filetype == 'gitrebase' && split(getline(1))[0] != '###' |
### \ execute "normal! gg/^# Rebase.*onto\<Enter>" |
### \ execute "normal! wwyt." |
### \ execute "normal! ggV}k:!git rr " . getreg('"') . "\<Enter>" |
### \ execute "normal! gg/^pick\<Enter>" |
### \ execute "nohl" |
### \ endif
### " in gitrebase, you can use gj and gk to move commit by commit
### autocmd FileType gitrebase nnoremap <buffer> gj /\v^(pick\|reword\|edit\|squash\|fixup\|exec\|drop)<CR>:nohl<CR>
### autocmd FileType gitrebase nnoremap <buffer> gk ?\v^(pick\|reword\|edit\|squash\|fixup\|exec\|drop)<CR>:nohl<CR>
### " ... or gf and gF to move FILE by FILE
### autocmd FileType gitrebase nnoremap <buffer> gf /FILE\d\+\s<CR>:nohl<CR>
### autocmd FileType gitrebase nnoremap <buffer> gF ?FILE\d\+\s<CR>:nohl<CR>
### " You could also highlight each FILENNNNN using a different/neater colour
### " depending on how often it's used:
### autocmd FileType gitrebase highlight GITREBASEFILE00001 guibg=#00ff00 guifg=#000000 ctermbg=46 ctermfg=16
### autocmd FileType gitrebase highlight GITREBASEFILE00002 guibg=#FF0000 guifg=#000000 ctermbg=196 ctermfg=16
### autocmd FileType gitrebase highlight GITREBASEFILE00003 guibg=#ff00ff guifg=#000000 ctermbg=201 ctermfg=16
### " ...
### autocmd FileType gitrebase call matchadd("GITREBASEFILE00001", "FILE00001")
### autocmd FileType gitrebase call matchadd("GITREBASEFILE00002", "FILE00002")
### autocmd FileType gitrebase call matchadd("GITREBASEFILE00003", "FILE00003")
### " ...