]> git.ipfire.org Git - thirdparty/git.git/blame - git-rebase.sh
cvsimport - cleanup of the multi-indexes handling
[thirdparty/git.git] / git-rebase.sh
CommitLineData
59e6b23a
JH
1#!/bin/sh
2#
3# Copyright (c) 2005 Junio C Hamano.
4#
5
e646c9c8 6USAGE='[--onto <newbase>] <upstream> [<branch>]'
031321c6
SE
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.
69a60af5 12
031321c6
SE
13It is possible that a merge failure will prevent this process from being
14completely automatic. You will have to resolve any such merge failure
cc120056
SE
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.
69a60af5 19
031321c6
SE
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.
e646c9c8 23
031321c6 24Example: git-rebase master~1 topic
e646c9c8 25
031321c6
SE
26 A---B---C topic A'\''--B'\''--C'\'' topic
27 / --> /
28 D---E---F---G master D---E---F---G master
e646c9c8 29'
ae2b0f15 30. git-sh-setup
4282c4fb 31
cc120056
SE
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"
e646c9c8 37unset newbase
58634dbf
EW
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?"
66eb64cb 52 die "$RESOLVEMSG"
58634dbf
EW
53 fi
54
55 if test -n "`git-diff-index HEAD`"
56 then
9e4bc7dd 57 printf "Committed: %0${prec}d" $msgnum
58634dbf
EW
58 git-commit -C "`cat $dotest/current`"
59 else
9e4bc7dd 60 printf "Already applied: %0${prec}d" $msgnum
58634dbf 61 fi
9e4bc7dd
EW
62 echo ' '`git-rev-list --pretty=oneline -1 HEAD | \
63 sed 's/^[a-f0-9]\+ //'`
58634dbf
EW
64
65 prev_head=`git-rev-parse HEAD^0`
58634dbf 66 # save the resulting commit so we can read-tree on it later
58634dbf
EW
67 echo "$prev_head" > "$dotest/prev_head"
68
69 # onto the next patch:
70 msgnum=$(($msgnum + 1))
5887ac82 71 echo "$msgnum" >"$dotest/msgnum"
58634dbf
EW
72}
73
74call_merge () {
5887ac82 75 cmt="$(cat $dotest/cmt.$1)"
58634dbf
EW
76 echo "$cmt" > "$dotest/current"
77 git-merge-$strategy "$cmt^" -- HEAD "$cmt"
78 rv=$?
79 case "$rv" in
80 0)
9e4bc7dd 81 return
58634dbf
EW
82 ;;
83 1)
84 test -d "$GIT_DIR/rr-cache" && git-rerere
66eb64cb 85 die "$RESOLVEMSG"
58634dbf
EW
86 ;;
87 2)
88 echo "Strategy: $rv $strategy failed, try another" 1>&2
66eb64cb 89 die "$RESOLVEMSG"
58634dbf
EW
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 () {
58634dbf
EW
99 rm -r "$dotest"
100 echo "All done."
101}
102
e646c9c8
JH
103while case "$#" in 0) break ;; esac
104do
105 case "$1" in
031321c6
SE
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
58634dbf
EW
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
cc120056
SE
129 git am --resolved --3way --resolvemsg="$RESOLVEMSG"
130 exit
131 ;;
132 --skip)
58634dbf
EW
133 if test -d "$dotest"
134 then
d5e673b6
EW
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
58634dbf 147 fi
cc120056 148 git am -3 --skip --resolvemsg="$RESOLVEMSG"
031321c6
SE
149 exit
150 ;;
151 --abort)
58634dbf
EW
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
031321c6 161 git reset --hard ORIG_HEAD
031321c6
SE
162 exit
163 ;;
e646c9c8
JH
164 --onto)
165 test 2 -le "$#" || usage
166 newbase="$2"
167 shift
168 ;;
58634dbf
EW
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 *,*=*)
8096fae7 177 strategy=`expr "z$1" : 'z-[^=]*=\(.*\)'` ;;
58634dbf
EW
178 1,*)
179 usage ;;
180 *)
181 strategy="$2"
182 shift ;;
183 esac
184 do_merge=t
185 ;;
e646c9c8
JH
186 -*)
187 usage
188 ;;
189 *)
190 break
191 ;;
192 esac
193 shift
194done
2db8aaec 195
7f4bd5d8 196# Make sure we do not have .dotest
58634dbf 197if test -z "$do_merge"
7f4bd5d8 198then
58634dbf
EW
199 if mkdir .dotest
200 then
201 rmdir .dotest
202 else
203 echo >&2 '
7f4bd5d8
JH
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.'
58634dbf
EW
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
7f4bd5d8
JH
216fi
217
7f59dbbb 218# The tree must be really really clean.
215a7ad1 219git-update-index --refresh || exit
7f59dbbb 220diff=$(git-diff-index --cached --name-status -r HEAD)
32d99544 221case "$diff" in
7f59dbbb
JH
222?*) echo "$diff"
223 exit 1
224 ;;
225esac
99a92f92 226
e646c9c8
JH
227# The upstream head must be given. Make sure it is valid.
228upstream_name="$1"
229upstream=`git rev-parse --verify "${upstream_name}^0"` ||
d0080b3c 230 die "invalid upstream $upstream_name"
32d99544 231
9a111c91
JH
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
7f59dbbb 241# If the branch to rebase is given, first switch to it.
59e6b23a 242case "$#" in
7f59dbbb 2432)
e646c9c8 244 branch_name="$2"
3ae39ab2 245 git-checkout "$2" || usage
e646c9c8
JH
246 ;;
247*)
248 branch_name=`git symbolic-ref HEAD` || die "No current branch"
f327dbce 249 branch_name=`expr "z$branch_name" : 'zrefs/heads/\(.*\)'`
e646c9c8 250 ;;
59e6b23a 251esac
e646c9c8 252branch=$(git-rev-parse --verify "${branch_name}^0") || exit
59e6b23a 253
e646c9c8
JH
254# Make sure the branch to rebase onto is valid.
255onto_name=${newbase-"$upstream_name"}
256onto=$(git-rev-parse --verify "${onto_name}^0") || exit
32d99544 257
e646c9c8
JH
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.
b176e6ba 262if test "$upstream" = "$onto"
7f4bd5d8 263then
e646c9c8
JH
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
7f4bd5d8
JH
270fi
271
e646c9c8
JH
272# Rewind the head to "$onto"; this saves our current head in ORIG_HEAD.
273git-reset --hard "$onto"
32d99544 274
e646c9c8 275# If the $onto is a proper descendant of the tip of the branch, then
32d99544 276# we just fast forwarded.
e646c9c8 277if test "$mb" = "$onto"
32d99544 278then
e646c9c8 279 echo >&2 "Fast-forwarded $branch to $newbase."
32d99544
LS
280 exit 0
281fi
282
58634dbf
EW
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
693c15dc
EW
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
58634dbf
EW
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))
5887ac82 312 echo "$cmt" > "$dotest/cmt.$msgnum"
58634dbf
EW
313done
314
5887ac82
JH
315echo 1 >"$dotest/msgnum"
316echo $msgnum >"$dotest/end"
58634dbf
EW
317
318end=$msgnum
319msgnum=1
320
321while test "$msgnum" -le "$end"
322do
323 call_merge "$msgnum"
324 continue_merge
325done
cc120056 326
58634dbf 327finish_rb_merge