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