Message ID | 20190630051816.8814-1-eantoranz@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [RFC/PATCH,1/2] rebuash - squash/rebase in a single step | expand |
On Sat, Jun 29, 2019 at 11:18:15PM -0600, Edmundo Carmona Antoranz wrote: > Rebuash allows us to do squash/rebase without having to resort > to use rebase. > > Consider the case where we have feature branches with merges in history: > > Rx: revisions in main branch > Fx: Revisions in feature branch > Mx: Merge revisions (some of them with conflicts) > > ------------ > R1---R2---R3---R4---R5---R6---R7 > \ \ \ > F1---F2---M1---F3---F4---M2---F5 > ------------ > > If on M1 there were conflicts, it's more than likely that if we tried to > cherry-pick R1..F2 on top of R7, we will have to deal with a conflict. But that > conflict has already been taken care of on M1. So, in order to leverage that > work that has already been done, instead of looking back, we look forward. > > First, we create a (temporary) merge commit of both branches (M3) > > ------------ > R1---R2---R3---R4---R5---R6---R7---M3 > \ \ \ / > F1---F2---M1---F3---F4---M2---F5 > ------------ > > At this point, all differences between M3 and R7 are the changes related to the > feature branch, so we can run git reset --soft from M3 to R7 to put all those > differeces in index, and then we create single revision that is both > squashed/rebased for our feature branch. So if I understand correctly, our goal is: R1--R2--...--R7--R8 where R8 has the same tree as M3? Wouldn't doing "git merge --squash" do the same thing? If I set up that scenario like so: git init repo cd repo commit() { for i in "$@"; do echo $i >file && git add file && git commit -m $i; done } commit R1 R2 R3 git checkout -b feature HEAD~2 commit F1 F2 git merge master commit M1 git checkout master commit R4 R5 R6 git checkout feature commit F3 F4 git merge master commit M2 F5 git checkout master commit R7 and then do: git merge --squash feature I get the same merge that rebuash is doing (with R6 as the merge base, so we see F5 and R7 conflicting with each other). And then when I finish it with "git commit", the result is a linear strand with M3 at the tip (and its commit message is even auto-populated with information from the squashed commits). -Peff
On Sun, Jun 30, 2019 at 12:54 AM Jeff King <peff@peff.net> wrote: > > > and then do: > > git merge --squash feature > > I get the same merge that rebuash is doing (with R6 as the merge base, > so we see F5 and R7 conflicting with each other). And then when I finish > it with "git commit", the result is a linear strand with M3 at the tip > (and its commit message is even auto-populated with information from the > squashed commits). > > -Peff From the point of view of the revisions that you produce in the end, it's the same thing, but you are not rebasing/squashing your feature branch, you are moving your upstream branch to where you want the squashed/rebased branch to be. So, in fact you would need more steps, something like (starting from your feature branch being checked out): git checkout --detach $( git rev-parse --abbrev-ref --symbolic-full-name @{u} ) git merge --squash my-feature-branch git branch -f my-feature-branch git checkout my-feature-branch Yes, it works. Only that with rebuash you would do (starting from the feature branch being checked out branch): git rebuash as long as the upstream branch is set, of course. I think it makes more sense in terms of development flow of feature branches, if you know in the end you will give up a squashed branch: modify commit modify commit git pull # no need to use pull --rebase, merges will be fine modify commit modify commit git pull git modify # now I'm ready to rebase/squash git fetch git rebuash adding history could be done with an additional option (--hist (default) and --no-hist?) But, as you said, it's not like it's not possible to do it (with a little more effort) with available tools like merge --squash
On Sun, Jun 30, 2019 at 09:09:31AM -0600, Edmundo Carmona Antoranz wrote: > > git merge --squash feature > > > > I get the same merge that rebuash is doing (with R6 as the merge base, > > so we see F5 and R7 conflicting with each other). And then when I finish > > it with "git commit", the result is a linear strand with M3 at the tip > > (and its commit message is even auto-populated with information from the > > squashed commits). > > From the point of view of the revisions that you produce in the end, > it's the same thing, but you are not rebasing/squashing your feature > branch, you are moving your upstream branch to where you want the > squashed/rebased branch to be. So, in fact you would need more steps, > something like (starting from your feature branch being checked out): Ah, OK, that's what I was missing. I agree that "merge --squash" isn't quite what you want, then. It's sort of a "reverse squash": do the merge, but use the _other_ side as the parent of the new squash commit. I wonder if it might be easier to implement as an option to git-merge. I noticed when I hit a conflict with rebuash that it emphatically told me not to use "git commit" once I had resolved everything. If this were just a special case of a merge, that might be a bit more seamless (though I imagine it might still require teaching git-commit about the feature, since it generally wants to mark HEAD as the parent). > I think it makes more sense in terms of development flow of feature > branches, if you know in the end you will give up a squashed branch: Yeah, I agree it is a separate operation that by itself makes sense. I do wonder a little why you'd care about squashing on the branch. If you're eventually going to squash the whole thing anyway, you don't care about a messy history. So you can just continue to back-merge from master into the feature branch and build on top. But perhaps the squashed version is easier to work with for further modifications? I'm not sure how, though. Certainly in your example rewriting changes in F1 with "rebase --interactive" would be a pain. But I think the end-state of the tree after your rebuash is identical to what you'd get by just merging from master. So in either case, just building new work on top should be the same. > But, as you said, it's not like it's not possible to do it (with a > little more effort) with available tools like merge --squash Yeah, but I agree with you that just because it is possible to do something does not mean that it is not a good idea to make the workflow easier or safer. I'm still not quite sure of the greater workflow where having the rebuash-ed commit on the feature branch is more useful than just having a merge from master. -Peff
On Sun, Jun 30, 2019 at 4:39 PM Jeff King <peff@peff.net> wrote: > > > But perhaps the squashed version is easier to work with for further > modifications? I'm not sure how, though. Certainly in your example > rewriting changes in F1 with "rebase --interactive" would be a pain. But > I think the end-state of the tree after your rebuash is identical to > what you'd get by just merging from master. So in either case, just > building new work on top should be the same. > I'm still not quite sure of the greater workflow where having the > rebuash-ed commit on the feature branch is more useful than just having > a merge from master. Hmm... I as a gatekeeper would rather get either a straight line of revisions for a feature with no merges (even if a final merge takes care of solving conflicts with the upstream branch) or a single revision (if I thought that the change is not worth having more than a single revision). I'd ask the developer to rebase the whole thing and give a straight line (with rebase -i or cherry-picks) or to give me a single revision (where rebuash would come into the picture). Also, I wonder how it would make life easier for people that are learning to use git and the command that they see thrown around very often is to use `git pull` in order to get updates from the other developers. But that might be me being opinionated. PS About rebuash ordering not to use commit: Sure, at the moment, rebuash is not commit-safe.... or merge-continue-safe.... but I can add checks for that in case the user runs them before using rebuash --continue
Jeff King <peff@peff.net> writes: >> First, we create a (temporary) merge commit of both branches (M3) >> >> ------------ >> R1---R2---R3---R4---R5---R6---R7---M3 >> \ \ \ / >> F1---F2---M1---F3---F4---M2---F5 >> ------------ >> >> At this point, all differences between M3 and R7 are the changes related to the >> feature branch, so we can run git reset --soft from M3 to R7 to put all those >> differeces in index, and then we create single revision that is both >> squashed/rebased for our feature branch. > > So if I understand correctly, our goal is: > > R1--R2--...--R7--R8 > > where R8 has the same tree as M3? > > Wouldn't doing "git merge --squash" do the same thing? Yup, from Edmundo's description, I agree that they are equivalent, modulo the merge direction. That affects two things, though. Who becomes the first parent is obviously swapped, but equally importantly, the merge conflicts are presented as if you are merging from the upstream, taking assortment of random changes into a stale codebase with slight modification. Swapping the direction would present the merge much better in that it let you pretend as if you started from the up-to-date upstream and replayed your own changes in the topic, and because you are by definition more familiar with your own changes, during conflict resolution, you would understand the output from "git diff HEAD" much better than the case where you merge upstream into your topic. But "rebase the feature branch on updated upstream and then merge the result, optionally squashing all of them into one big ball of wax" *could* be a lot more useful feature, serving as poor-man's imitation of "git imerge", *but* only if the final squashing is made optional (that at the same time means that sometimes the M3 merge can be unmanageably messy and stepwise rebase may make it manageable). If M3 merge is always easier to manage than incremental stepwise rebase of the topic, then doing the "git merge --reverse-squash" would be a saner interface and also conceptually simpler.
Edmundo Carmona Antoranz <eantoranz@gmail.com> writes: > Hmm... I as a gatekeeper would rather get either a straight line of > revisions for a feature with no merges (even if a final merge takes > care of solving conflicts with the upstream branch) or a single > revision (if I thought that the change is not worth having more than a > single revision). I'd ask the developer to rebase the whole thing and > give a straight line (with rebase -i or cherry-picks) or to give me a > single revision (where rebuash would come into the picture). That part is understandable, but is "rebase-and-squash" a tool intended to be used by the contributor to respond to that request? Wouldn't the developer just do git checkout topic git fetch git rebase [-i] [@{upstream}] git push [publish +topic] to update the topic and ask to be pulled again? The two steps in the middle may be "pull --rebase", but my point is I do not quite see where the new squash/rebase-in-a-single-step thing comes into this picture. There may be a different picture that it fits, but I do not think it is this one.
On Mon, Jul 1, 2019 at 12:51 PM Junio C Hamano <gitster@pobox.com> wrote: > > > That part is understandable, but is "rebase-and-squash" a tool > intended to be used by the contributor to respond to that request? > > Wouldn't the developer just do > > git checkout topic > git fetch > git rebase [-i] [@{upstream}] > git push [publish +topic] > > to update the topic and ask to be pulled again? The two steps in > the middle may be "pull --rebase", but my point is I do not quite > see where the new squash/rebase-in-a-single-step thing comes into > this picture. There may be a different picture that it fits, but > I do not think it is this one. > > I think rebasing -i makes sense* _if_ there are no conflicts on the way to reach the current state of the branch if the developer was pulling while developing the feature branch. If there are conflicts that I took care of when i was pulling, i don't want to run rebase -i to have to deal with them yet again. So rebuash would help developers with or without merges with upstream on their feature branch, with or without conflicts on those merges (if there are merges), get their development into a single revision without having to write 4 or 5 git commands, as Jeff was saying, if it makes workflows simpler.... * rebase -i is the way I see people solve their "squash and rebase" needs (pick the first revision, then squash all the others... but what happens if the very first revision is conflicting with the current state of upstream?), but I (for one) do it the way rebuash is doing: merge with upstream, reset --soft to upstream, commit, voila! That's why i wrote rebuash in the first place, just so you can see where I'm coming from.
On 7/1/2019 2:35 PM, Junio C Hamano wrote: > Jeff King <peff@peff.net> writes: > >>> First, we create a (temporary) merge commit of both branches (M3) >>> >>> ------------ >>> R1---R2---R3---R4---R5---R6---R7---M3 >>> \ \ \ / >>> F1---F2---M1---F3---F4---M2---F5 >>> ------------ >>> >>> At this point, all differences between M3 and R7 are the changes related to the >>> feature branch, so we can run git reset --soft from M3 to R7 to put all those >>> differeces in index, and then we create single revision that is both >>> squashed/rebased for our feature branch. >> >> So if I understand correctly, our goal is: >> >> R1--R2--...--R7--R8 >> >> where R8 has the same tree as M3? >> >> Wouldn't doing "git merge --squash" do the same thing? > > Yup, from Edmundo's description, I agree that they are equivalent, > modulo the merge direction. [snip] > If M3 merge is always easier to manage than incremental stepwise > rebase of the topic, then doing the "git merge --reverse-squash" > would be a saner interface and also conceptually simpler. I agree that this would be a better way to expose this behavior, and likely the implementation could be very clean. Thanks, -Stolee
Derrick Stolee <stolee@gmail.com> writes: > On 7/1/2019 2:35 PM, Junio C Hamano wrote: >> Jeff King <peff@peff.net> writes: >> >>>> First, we create a (temporary) merge commit of both branches (M3) >>>> >>>> ------------ >>>> R1---R2---R3---R4---R5---R6---R7---M3 >>>> \ \ \ / >>>> F1---F2---M1---F3---F4---M2---F5 >>>> ------------ >>>> > ... >> If M3 merge is always easier to manage than incremental stepwise >> rebase of the topic, then doing the "git merge --reverse-squash" >> would be a saner interface and also conceptually simpler. > > I agree that this would be a better way to expose this behavior, > and likely the implementation could be very clean. What I was sort-of hoping to get comments on was actually something else. Would there be cases where the merge M3 gets unmanageably complex even if rebasing the feature commits one by one is relatively simple (and how often would that happen)? "merge --squash" would not work well (and extending the command to merge in a different direction would not help) in such a situation, but "rebase -i" would work much better (and "imerge" would, too).
Am 02.07.19 um 19:20 schrieb Junio C Hamano: > Derrick Stolee <stolee@gmail.com> writes: > >> On 7/1/2019 2:35 PM, Junio C Hamano wrote: >>> Jeff King <peff@peff.net> writes: >>> >>>>> First, we create a (temporary) merge commit of both branches (M3) >>>>> >>>>> ------------ >>>>> R1---R2---R3---R4---R5---R6---R7---M3 >>>>> \ \ \ / >>>>> F1---F2---M1---F3---F4---M2---F5 >>>>> ------------ >>>>> >> ... >>> If M3 merge is always easier to manage than incremental stepwise >>> rebase of the topic, then doing the "git merge --reverse-squash" >>> would be a saner interface and also conceptually simpler. >> >> I agree that this would be a better way to expose this behavior, >> and likely the implementation could be very clean. > > What I was sort-of hoping to get comments on was actually something > else. > > Would there be cases where the merge M3 gets unmanageably complex > even if rebasing the feature commits one by one is relatively simple > (and how often would that happen)? "merge --squash" would not work > well (and extending the command to merge in a different direction > would not help) in such a situation, but "rebase -i" would work > much better (and "imerge" would, too). I've come across the situation occasionally. Once I have resolved a bunch of conflicts in M1 and M2, I think twice whether I should rebase individual commits; it is typically much more tedious. A common situation is that a line is "A" in F1, "B" in F2, and "C" in R3; then I have to resolve ONE conflict in M1 ("<B=C>"), but with individual commits rebased on top of R3, I have two conflicts, "<C=A>" and "<AC=B>", neither of which is helped by rerere. After merges M1 and M2, it is all a done deal, and M3 is typically a much simpler merge than the sum of conflicts incurred by the individual commits. I would generally not recommend a rebase in this situation. But I wouldn't turn M3 into a squashed merged commit, either, as long as F1...F5 aren't messy. -- Hannes
diff --git a/.gitignore b/.gitignore index 4470d7cfc0..46b5c94c8f 100644 --- a/.gitignore +++ b/.gitignore @@ -123,6 +123,7 @@ /git-read-tree /git-rebase /git-rebase--preserve-merges +/git-rebuash /git-receive-pack /git-reflog /git-remote diff --git a/Documentation/git-rebuash.txt b/Documentation/git-rebuash.txt new file mode 100644 index 0000000000..721da64010 --- /dev/null +++ b/Documentation/git-rebuash.txt @@ -0,0 +1,76 @@ +git-rebuash(1) +============= + +NAME +---- +git-rebuash - Squash/Rebase in a single shot + + +SYNOPSIS +-------- +[verse] +'git rebuash' [-m <msg>] [ -u <upstream> ] +'git rebuash' --continue +'git rebuash' --abort + +DESCRIPTION +----------- +Rebuash allows us to do squash/rebase without having to resort +to use rebase. + +Consider the case where we have feature branches with merges in history: + +Rx: revisions in main branch +Fx: Revisions in feature branch +Mx: Merge revisions (some of them with conflicts) + +------------ + R1---R2---R3---R4---R5---R6---R7 + \ \ \ + F1---F2---M1---F3---F4---M2---F5 +------------ + +If on M1 there were conflicts, it's more than likely that if we tried to +cherry-pick R1..F2 on top of R7, we will have to deal with a conflict. But that +conflict has already been taken care of on M1. So, in order to leverage that +work that has already been done, instead of looking back, we look forward. + +First, we create a (temporary) merge commit of both branches (M3) + +------------ + R1---R2---R3---R4---R5---R6---R7---M3 + \ \ \ / + F1---F2---M1---F3---F4---M2---F5 +------------ + +At this point, all differences between M3 and R7 are the changes related to the +feature branch, so we can run git reset --soft from M3 to R7 to put all those +differeces in index, and then we create single revision that is both +squashed/rebased for our feature branch. + +git rebuash will take care of all the details, even figuring out +what the upstream branch is if it is not provided. + +git checkout feature1 +git rebuash -u upstream-branch -m "Feature 1 in a single revision" + + +OPTIONS +------- + +-m <msg>:: + Set the commit message to be used for the merge commit + +-u <upstream>:: + Set the upstream branch. If it is not provided, the upstream branch + from the currently checked out branch will be used. + +--abort:: + Abort the current rebuash process and go back + to the original state before starting rebuash + +--continue:: + If rebuash stopped (due to a conflict of an empty commit message), + allow the process to go on after solving the current issue that made it + stop. + diff --git a/Makefile b/Makefile index f58bf14c7b..c2869d7c11 100644 --- a/Makefile +++ b/Makefile @@ -614,6 +614,7 @@ SCRIPT_SH += git-merge-resolve.sh SCRIPT_SH += git-mergetool.sh SCRIPT_SH += git-quiltimport.sh SCRIPT_SH += git-legacy-stash.sh +SCRIPT_SH += git-rebuash.sh SCRIPT_SH += git-request-pull.sh SCRIPT_SH += git-submodule.sh SCRIPT_SH += git-web--browse.sh diff --git a/command-list.txt b/command-list.txt index 3a9af104b5..cf1cb48fde 100644 --- a/command-list.txt +++ b/command-list.txt @@ -143,6 +143,7 @@ git-quiltimport foreignscminterface git-range-diff mainporcelain git-read-tree plumbingmanipulators git-rebase mainporcelain history +git-rebuash mainporcelain history git-receive-pack synchelpers git-reflog ancillarymanipulators complete git-remote ancillarymanipulators complete diff --git a/git-rebuash.sh b/git-rebuash.sh new file mode 100644 index 0000000000..93c14cb9cc --- /dev/null +++ b/git-rebuash.sh @@ -0,0 +1,324 @@ +#!/bin/bash +# Copyright 2019 Edmundo Carmona Antoranz + +# Released under the terms of GPLv2 + +# Rebuash will be used mainly when you want to squash and rebase +# so that you don't have to go through the ordeal of rebasing +# which would potencially bring conflicts that you would +# rather avoid it at all possible. + +# rebuash takes a different strategy by merging with the target (upstream) branch +# then resetting --soft onto the target branch to finish off with a new +# revision + +# Valid options: +# -u upstream branch (if it's not specified, it will be retrieved from current branch) +# -m comment for the final revision (can be multiline) +# --abort if the user wants to abort the rebuash operation +# --continue if there was a previous conflict and the user wants to continue with the current rebuash operation + +UPSTREAM="" # upstream branch (will be retrieved from current branch if it is not provided) +HEAD="" # the point where we started rebuash from (revision or branch, for messaging) +HEAD_REV="" # point where we started the operation from (the revision) +STEP="" # will be used when we need to continue to know in which step we are at the moment +COMMENT="" # comment to be used on the final revision (might be empty) + +# actions +START=true +CONTINUE=false +ABORT=false + +. git-sh-setup + +STATE_FILE="$GIT_DIR"/REBUASH_STATE + +function report_bug { + echo "You just hit a bug in git-rebuash" + echo "BUG: $1" + echo "Please, report this problem to the git mailing list and cc eantoranz at gmail.com" + exit 1 +} + +function save_state { + echo "UPSTREAM: $UPSTREAM" > "$STATE_FILE" + echo "HEAD: $HEAD" >> "$STATE_FILE" + echo "HEAD_REV: $HEAD_REV" >> "$STATE_FILE" + echo "STEP: $STEP" >> "$STATE_FILE" + echo "" >> "$STATE_FILE" # an empty line + echo "$COMMENT" >> "$STATE_FILE" +} + +function read_state { + # read the content of state file and put it into the variables + if [ ! -f "$STATE_FILE" ] + then + echo Unexpected Error: Rebuash state file was expected to exist. + echo Aborting operation. + echo Please, notify the git mail list and explain them what the situation was + echo so that this bug can be taken care of. + exit 1 + fi + UPSTREAM=$( head -n 1 "$STATE_FILE" | sed 's/UPSTREAM: //' ) + HEAD=$( head -n 2 "$STATE_FILE" | tail -n 1 | sed 's/HEAD: //' ) + HEAD_REV=$( head -n 3 "$STATE_FILE" | tail -n 1 | sed 's/HEAD_REV: //' ) + STEP=$( head -n 4 "$STATE_FILE" | tail -n 1 | sed 's/STEP: //' ) + # there is an empty line + COMMENT=$( tail -n +6 "$STATE_FILE" ) +} + +function remove_state { + if [ -f "$STATE_FILE" ] + then + rm -f "$STATE_FILE" + fi +} + +function check_status { + if [ $CONTINUE == true ] + then + if [ $ABORT == true ] + then + echo Can\'t use --abort and --continue at the same time + exit 1 + fi + + # there has to be an state file + if [ ! -f "$STATE_FILE" ] + then + echo There\'s no rebuash session currently going on. Can\'t continue. + exit 1 + fi + elif [ $ABORT == true ] + then + if [ ! -f "$STATE_FILE" ] + then + echo There\'s no rebuash session currently going on. Can\'t abort. + exit 1 + fi + else + if [ $START != true ] + then + report_bug "START is set to false even though we were not aborting or continuing" + fi + + if [ "$UPSTREAM" == "" ] + then + # as a fallback, try to get upstream from current branch + UPSTREAM=$( git rev-parse --abbrev-ref --symbolic-full-name @{u} 2> /dev/null ) + if [ "$UPSTREAM" == "" ] + then + echo "Could not find out upstream branch. Please provide it with -u" + exit 1 + else + echo Using $UPSTREAM as the upstream branch + fi + fi + + # starting execution + # there must _not_ be anything going on + status=$( git status --short --untracked-files=no ) + if [ "$status" != "" ] + then + echo Status is not clean before rebuashing. + echo Make sure to clean up your working tree before starting rebuash + exit 1 + fi + fi +} + +# Parse arguments +function parse_options { + + while true + do + value=$1 + shift + if [ $? -ne 0 ] + then + # no more parameters + break + fi + + if [ "$value" == "-u" ] + then + # user wants to specify the upstream branch + UPSTREAM="$1" + shift + elif [ "$value" == "-m" ] + then + # user wants to set up the comment for the commit + COMMENT="$1" + shift + elif [ "$value" == "--continue" ] + then + # user wants to resume execution + CONTINUE=true + START=false + elif [ "$value" == "--abort" ] + then + ABORT=true + START=false + fi + done +} + +# Start execution of rebuash +function start_rebuash { + + # there must not exist a previous state file + if [ -f "$STATE_FILE" ] + then + echo You are in the middle of a previous rebuash execution + echo If that is not the case, remove the file "$STATE_FILE" + echo and also feel free to file a report with int git mail list + exit 1 + fi + + git show "$UPSTREAM" &> /dev/null + if [ $? -ne 0 ] + then + echo "Provided upstream ($UPSTREAM) does not exist" + exit 1 + fi + + # persist execution information + HEAD=$( git rev-parse --abbrev-ref --symbolic-full-name @ 2> /dev/null ) + HEAD_REV=$( git show --quiet --pretty="%H" ) + save_state + + # start doing our magic + echo "Merging with upstream branch ($UPSTREAM)" + git merge --no-ff --no-commit "$UPSTREAM" 2> /dev/null + + # we let the process move forward as if we are continuing + STEP=MERGE + save_state # continue_rebuash will read the state from file + CONTINUE=true + return + +} + +function continue_rebuash { + read_state + if [ "$STEP" == "" ] + then + report_bug "Bug: Can't determine in what step we are in order to do --continue." + fi + + if [ "$STEP" == "MERGE" ] + then + git -c core.editor=/bin/true merge --continue &> /dev/null # do not open editor, use previous comment + + if [ $? -ne 0 ] + then + save_state # just in case we add more _previous_ STEPS later on + echo "There are unmerged paths to take care of (or tracked and pending to be added to index)" + echo Check with git status + echo "Finish them (_DO NOT_ commit nor run git merge --continue). Then run:" + echo + echo git rebuash --continue + echo + echo You can also run git rebuash --abort if you would like to stop the whole process + echo and go back to where you were before rebuashing + exit 1 + fi + STEP=RESET + fi + + if [ "$STEP" == "RESET" ] + then + # move branch pointer to UPSTREAM + git reset --soft "$UPSTREAM" + + # merge/reset went fine so we set the STEP to COMMIT + STEP=COMMIT + fi + + if [ "$STEP" == "COMMIT" ] + then + # create new revision + if [ "$COMMENT" == "" ] + then + # no comment was provided + # what was checked out when we started? + if [ "$HEAD" == "HEAD" ] + then + # was working on detached head + TEMP_COMMENT="Rebuashing $HEAD_REV on top of $UPSTREAM" + else + TEMP_COMMENT="Rebuashing $HEAD on top of $UPSTREAM" + fi + git commit -m "$TEMP_COMMENT" --edit + else + git commit -m "$COMMENT" + fi + + if [ $? -ne 0 ] + then + # there was some error while committing + save_state + + echo There was an error while committing. + echo Aborting rebuash operation. + echo When you are ready to finish, run: + echo git rebuash --continue + exit 1 + fi + STEP=END # just in case + fi + + # everything went fine + remove_state + echo Rebuash operation was successful. + exit 0 +} + +function abort_rebuash { + # take it back to the original state + # make sure there was an state to start from + read_state + + # most cases, we are in the middle of the merge operation + if [ "$STEP" == "" ] + then + echo Bug: Could not figure out the step we are in. + echo Please, report this problem to the git mail list + exit 1 + fi + if [ "$STEP" == "MERGE" ] + then + # can ask to abort merge and we go back to where we were when we started + git merge --abort &> /dev/null + elif [ "$STEP" == "COMMIT" ] + then + # need to got back to where we were before + git reset --hard "$HEAD_REV" &> /dev/null + else + report_bug "Unknown step ($STEP)" + fi + + remove_state + + echo Rebuash was successfully aborted + exit 0 +} + +parse_options "$@" + +check_status + +if [ $START == true ] +then + start_rebuash +fi + +if [ $CONTINUE == true ] +then + continue_rebuash +fi + +if [ $ABORT == true ] +then + abort_rebuash +fi