1
-#!/bin/sh
2
-
3
-USAGE="[-a] [-r] [-m] [-t] [-n] [-b <newname>] <name>"
4
-LONG_USAGE="git-resurrect attempts to find traces of a branch tip
5
-called <name>, and tries to resurrect it. Currently, the reflog is
6
-searched for checkout messages, and with -r also merge messages. With
7
--m and -t, the history of all refs is scanned for Merge <name> into
8
-other/Merge <other> into <name> (respectively) commit subjects, which
9
-is rather slow but allows you to resurrect other people's topic
10
-branches."
11
-
12
-OPTIONS_KEEPDASHDASH=
13
-OPTIONS_STUCKLONG=
14
-OPTIONS_SPEC="\
15
-git resurrect $USAGE
16
---
17
-b,branch= save branch as <newname> instead of <name>
18
-a,all same as -l -r -m -t
19
-k,keep-going full rev-list scan (instead of first match)
20
-l,reflog scan reflog for checkouts (enabled by default)
21
-r,reflog-merges scan for merges recorded in reflog
22
-m,merges scan for merges into other branches (slow)
23
-t,merge-targets scan for merges of other branches into <name>
24
-n,dry-run don't recreate the branch"
25
-
26
-. git-sh-setup
27
-
28
-search_reflog () {
29
- sed -ne 's~^\([^ ]*\) .* checkout: moving from '"$1"' .*~\1~p' \
30
- < "$GIT_DIR"/logs/HEAD
31
-}
32
-
33
-search_reflog_merges () {
34
- git rev-parse $(
35
- sed -ne 's~^[^ ]* \([^ ]*\) .* merge '"$1"':.*~\1^2~p' \
36
- < "$GIT_DIR"/logs/HEAD
37
- )
38
-}
39
-
40
-oid_pattern=$(git hash-object --stdin </dev/null | sed -e 's/./[0-9a-f]/g')
41
-
42
-search_merges () {
43
- git rev-list --all --grep="Merge branch '$1'" \
44
- --pretty=tformat:"%P %s" |
45
- sed -ne "/^$oid_pattern \($oid_pattern\) Merge .*/ {s//\1/p;$early_exit}"
46
-}
47
-
48
-search_merge_targets () {
49
- git rev-list --all --grep="Merge branch '[^']*' into $branch\$" \
50
- --pretty=tformat:"%H %s" --all |
51
- sed -ne "/^\($oid_pattern\) Merge .*/ {s//\1/p;$early_exit} "
52
-}
53
-
54
-dry_run=
55
-early_exit=q
56
-scan_reflog=t
57
-scan_reflog_merges=
58
-scan_merges=
59
-scan_merge_targets=
60
-new_name=
61
-
62
-while test "$#" != 0; do
63
- case "$1" in
64
- -b|--branch)
65
- shift
66
- new_name="$1"
67
- ;;
68
- -n|--dry-run)
69
- dry_run=t
70
- ;;
71
- --no-dry-run)
72
- dry_run=
73
- ;;
74
- -k|--keep-going)
75
- early_exit=
76
- ;;
77
- --no-keep-going)
78
- early_exit=q
79
- ;;
80
- -m|--merges)
81
- scan_merges=t
82
- ;;
83
- --no-merges)
84
- scan_merges=
85
- ;;
86
- -l|--reflog)
87
- scan_reflog=t
88
- ;;
89
- --no-reflog)
90
- scan_reflog=
91
- ;;
92
- -r|--reflog_merges)
93
- scan_reflog_merges=t
94
- ;;
95
- --no-reflog_merges)
96
- scan_reflog_merges=
97
- ;;
98
- -t|--merge-targets)
99
- scan_merge_targets=t
100
- ;;
101
- --no-merge-targets)
102
- scan_merge_targets=
103
- ;;
104
- -a|--all)
105
- scan_reflog=t
106
- scan_reflog_merges=t
107
- scan_merges=t
108
- scan_merge_targets=t
109
- ;;
110
- --)
111
- shift
112
- break
113
- ;;
114
- *)
115
- usage
116
- ;;
117
- esac
118
- shift
119
-done
120
-
121
-test "$#" = 1 || usage
122
-
123
-all_strategies="$scan_reflog$scan_reflog_merges$scan_merges$scan_merge_targets"
124
-if test -z "$all_strategies"; then
125
- die "must enable at least one of -lrmt"
126
-fi
127
-
128
-branch="$1"
129
-test -z "$new_name" && new_name="$branch"
130
-
131
-if test ! -z "$scan_reflog"; then
132
- if test -r "$GIT_DIR"/logs/HEAD; then
133
- candidates="$(search_reflog $branch)"
134
- else
135
- die 'reflog scanning requested, but' \
136
- '$GIT_DIR/logs/HEAD not readable'
137
- fi
138
-fi
139
-if test ! -z "$scan_reflog_merges"; then
140
- if test -r "$GIT_DIR"/logs/HEAD; then
141
- candidates="$candidates $(search_reflog_merges $branch)"
142
- else
143
- die 'reflog scanning requested, but' \
144
- '$GIT_DIR/logs/HEAD not readable'
145
- fi
146
-fi
147
-if test ! -z "$scan_merges"; then
148
- candidates="$candidates $(search_merges $branch)"
149
-fi
150
-if test ! -z "$scan_merge_targets"; then
151
- candidates="$candidates $(search_merge_targets $branch)"
152
-fi
153
-
154
-candidates="$(git rev-parse $candidates | sort -u)"
155
-
156
-if test -z "$candidates"; then
157
- hint=
158
- test "z$all_strategies" != "ztttt" \
159
- && hint=" (maybe try again with -a)"
160
- die "no candidates for $branch found$hint"
161
-fi
162
-
163
-echo "** Candidates for $branch **"
164
-for cmt in $candidates; do
165
- git --no-pager log --pretty=tformat:"%ct:%h [%cr] %s" --abbrev-commit -1 $cmt
166
-done \
167
-| sort -n | cut -d: -f2-
168
-
169
-newest="$(git rev-list -1 $candidates)"
170
-if test ! -z "$dry_run"; then
171
- printf "** Most recent: "
172
- git --no-pager log -1 --pretty=tformat:"%h %s" $newest
173
-elif ! git rev-parse --verify --quiet $new_name >/dev/null; then
174
- printf "** Restoring $new_name to "
175
- git --no-pager log -1 --pretty=tformat:"%h %s" $newest
176
- git branch $new_name $newest
177
-else
178
- printf "Most recent: "
179
- git --no-pager log -1 --pretty=tformat:"%h %s" $newest
180
- echo "** $new_name already exists, doing nothing"
181
-fi