]> git.ipfire.org Git - thirdparty/git.git/blame_incremental - git-rebase.sh
cvsimport - cleanup of the multi-indexes handling
[thirdparty/git.git] / git-rebase.sh
... / ...
CommitLineData
1#!/bin/sh
2#
3# Copyright (c) 2005 Junio C Hamano.
4#
5
6USAGE='[--onto <newbase>] <upstream> [<branch>]'
7LONG_USAGE='git-rebase replaces <branch> with a new branch of the
8same name. When the --onto option is provided the new branch starts
9out with a HEAD equal to <newbase>, otherwise it is equal to <upstream>
10It then attempts to create a new commit for each commit from the original
11<branch> that does not exist in the <upstream> branch.
12
13It is possible that a merge failure will prevent this process from being
14completely automatic. You will have to resolve any such merge failure
15and run git rebase --continue. Another option is to bypass the commit
16that caused the merge failure with git rebase --skip. To restore the
17original <branch> and remove the .dotest working files, use the command
18git rebase --abort instead.
19
20Note that if <branch> is not specified on the command line, the
21currently checked out branch is used. You must be in the top
22directory of your project to start (or continue) a rebase.
23
24Example: git-rebase master~1 topic
25
26 A---B---C topic A'\''--B'\''--C'\'' topic
27 / --> /
28 D---E---F---G master D---E---F---G master
29'
30. git-sh-setup
31
32RESOLVEMSG="
33When you have resolved this problem run \"git rebase --continue\".
34If you would prefer to skip this patch, instead run \"git rebase --skip\".
35To restore the original branch and stop rebasing run \"git rebase --abort\".
36"
37unset newbase
38strategy=recursive
39do_merge=
40dotest=$GIT_DIR/.dotest-merge
41prec=4
42
43continue_merge () {
44 test -n "$prev_head" || die "prev_head must be defined"
45 test -d "$dotest" || die "$dotest directory does not exist"
46
47 unmerged=$(git-ls-files -u)
48 if test -n "$unmerged"
49 then
50 echo "You still have unmerged paths in your index"
51 echo "did you forget update-index?"
52 die "$RESOLVEMSG"
53 fi
54
55 if test -n "`git-diff-index HEAD`"
56 then
57 printf "Committed: %0${prec}d" $msgnum
58 git-commit -C "`cat $dotest/current`"
59 else
60 printf "Already applied: %0${prec}d" $msgnum
61 fi
62 echo ' '`git-rev-list --pretty=oneline -1 HEAD | \
63 sed 's/^[a-f0-9]\+ //'`
64
65 prev_head=`git-rev-parse HEAD^0`
66 # save the resulting commit so we can read-tree on it later
67 echo "$prev_head" > "$dotest/prev_head"
68
69 # onto the next patch:
70 msgnum=$(($msgnum + 1))
71 echo "$msgnum" >"$dotest/msgnum"
72}
73
74call_merge () {
75 cmt="$(cat $dotest/cmt.$1)"
76 echo "$cmt" > "$dotest/current"
77 git-merge-$strategy "$cmt^" -- HEAD "$cmt"
78 rv=$?
79 case "$rv" in
80 0)
81 return
82 ;;
83 1)
84 test -d "$GIT_DIR/rr-cache" && git-rerere
85 die "$RESOLVEMSG"
86 ;;
87 2)
88 echo "Strategy: $rv $strategy failed, try another" 1>&2
89 die "$RESOLVEMSG"
90 ;;
91 *)
92 die "Unknown exit code ($rv) from command:" \
93 "git-merge-$strategy $cmt^ -- HEAD $cmt"
94 ;;
95 esac
96}
97
98finish_rb_merge () {
99 rm -r "$dotest"
100 echo "All done."
101}
102
103while case "$#" in 0) break ;; esac
104do
105 case "$1" in
106 --continue)
107 diff=$(git-diff-files)
108 case "$diff" in
109 ?*) echo "You must edit all merge conflicts and then"
110 echo "mark them as resolved using git update-index"
111 exit 1
112 ;;
113 esac
114 if test -d "$dotest"
115 then
116 prev_head="`cat $dotest/prev_head`"
117 end="`cat $dotest/end`"
118 msgnum="`cat $dotest/msgnum`"
119 onto="`cat $dotest/onto`"
120 continue_merge
121 while test "$msgnum" -le "$end"
122 do
123 call_merge "$msgnum"
124 continue_merge
125 done
126 finish_rb_merge
127 exit
128 fi
129 git am --resolved --3way --resolvemsg="$RESOLVEMSG"
130 exit
131 ;;
132 --skip)
133 if test -d "$dotest"
134 then
135 prev_head="`cat $dotest/prev_head`"
136 end="`cat $dotest/end`"
137 msgnum="`cat $dotest/msgnum`"
138 msgnum=$(($msgnum + 1))
139 onto="`cat $dotest/onto`"
140 while test "$msgnum" -le "$end"
141 do
142 call_merge "$msgnum"
143 continue_merge
144 done
145 finish_rb_merge
146 exit
147 fi
148 git am -3 --skip --resolvemsg="$RESOLVEMSG"
149 exit
150 ;;
151 --abort)
152 if test -d "$dotest"
153 then
154 rm -r "$dotest"
155 elif test -d .dotest
156 then
157 rm -r .dotest
158 else
159 die "No rebase in progress?"
160 fi
161 git reset --hard ORIG_HEAD
162 exit
163 ;;
164 --onto)
165 test 2 -le "$#" || usage
166 newbase="$2"
167 shift
168 ;;
169 -M|-m|--m|--me|--mer|--merg|--merge)
170 do_merge=t
171 ;;
172 -s=*|--s=*|--st=*|--str=*|--stra=*|--strat=*|--strate=*|\
173 --strateg=*|--strategy=*|\
174 -s|--s|--st|--str|--stra|--strat|--strate|--strateg|--strategy)
175 case "$#,$1" in
176 *,*=*)
177 strategy=`expr "z$1" : 'z-[^=]*=\(.*\)'` ;;
178 1,*)
179 usage ;;
180 *)
181 strategy="$2"
182 shift ;;
183 esac
184 do_merge=t
185 ;;
186 -*)
187 usage
188 ;;
189 *)
190 break
191 ;;
192 esac
193 shift
194done
195
196# Make sure we do not have .dotest
197if test -z "$do_merge"
198then
199 if mkdir .dotest
200 then
201 rmdir .dotest
202 else
203 echo >&2 '
204It seems that I cannot create a .dotest directory, and I wonder if you
205are in the middle of patch application or another rebase. If that is not
206the case, please rm -fr .dotest and run me again. I am stopping in case
207you still have something valuable there.'
208 exit 1
209 fi
210else
211 if test -d "$dotest"
212 then
213 die "previous dotest directory $dotest still exists." \
214 'try git-rebase < --continue | --abort >'
215 fi
216fi
217
218# The tree must be really really clean.
219git-update-index --refresh || exit
220diff=$(git-diff-index --cached --name-status -r HEAD)
221case "$diff" in
222?*) echo "$diff"
223 exit 1
224 ;;
225esac
226
227# The upstream head must be given. Make sure it is valid.
228upstream_name="$1"
229upstream=`git rev-parse --verify "${upstream_name}^0"` ||
230 die "invalid upstream $upstream_name"
231
232# If a hook exists, give it a chance to interrupt
233if test -x "$GIT_DIR/hooks/pre-rebase"
234then
235 "$GIT_DIR/hooks/pre-rebase" ${1+"$@"} || {
236 echo >&2 "The pre-rebase hook refused to rebase."
237 exit 1
238 }
239fi
240
241# If the branch to rebase is given, first switch to it.
242case "$#" in
2432)
244 branch_name="$2"
245 git-checkout "$2" || usage
246 ;;
247*)
248 branch_name=`git symbolic-ref HEAD` || die "No current branch"
249 branch_name=`expr "z$branch_name" : 'zrefs/heads/\(.*\)'`
250 ;;
251esac
252branch=$(git-rev-parse --verify "${branch_name}^0") || exit
253
254# Make sure the branch to rebase onto is valid.
255onto_name=${newbase-"$upstream_name"}
256onto=$(git-rev-parse --verify "${onto_name}^0") || exit
257
258# Now we are rebasing commits $upstream..$branch on top of $onto
259
260# Check if we are already based on $onto, but this should be
261# done only when upstream and onto are the same.
262if test "$upstream" = "$onto"
263then
264 mb=$(git-merge-base "$onto" "$branch")
265 if test "$mb" = "$onto"
266 then
267 echo >&2 "Current branch $branch_name is up to date."
268 exit 0
269 fi
270fi
271
272# Rewind the head to "$onto"; this saves our current head in ORIG_HEAD.
273git-reset --hard "$onto"
274
275# If the $onto is a proper descendant of the tip of the branch, then
276# we just fast forwarded.
277if test "$mb" = "$onto"
278then
279 echo >&2 "Fast-forwarded $branch to $newbase."
280 exit 0
281fi
282
283if test -z "$do_merge"
284then
285 git-format-patch -k --stdout --full-index "$upstream"..ORIG_HEAD |
286 git am --binary -3 -k --resolvemsg="$RESOLVEMSG"
287 exit $?
288fi
289
290if test "@@NO_PYTHON@@" && test "$strategy" = "recursive"
291then
292 die 'The recursive merge strategy currently relies on Python,
293which this installation of git was not configured with. Please consider
294a different merge strategy (e.g. octopus, resolve, stupid, ours)
295or install Python and git with Python support.'
296
297fi
298
299# start doing a rebase with git-merge
300# this is rename-aware if the recursive (default) strategy is used
301
302mkdir -p "$dotest"
303echo "$onto" > "$dotest/onto"
304prev_head=`git-rev-parse HEAD^0`
305echo "$prev_head" > "$dotest/prev_head"
306
307msgnum=0
308for cmt in `git-rev-list --no-merges "$upstream"..ORIG_HEAD \
309 | perl -e 'print reverse <>'`
310do
311 msgnum=$(($msgnum + 1))
312 echo "$cmt" > "$dotest/cmt.$msgnum"
313done
314
315echo 1 >"$dotest/msgnum"
316echo $msgnum >"$dotest/end"
317
318end=$msgnum
319msgnum=1
320
321while test "$msgnum" -le "$end"
322do
323 call_merge "$msgnum"
324 continue_merge
325done
326
327finish_rb_merge