Skip to content

Commit 45acb75

Browse files
committed
Merge branch 'rr/rebase-autostash'
* rr/rebase-autostash: rebase: implement --[no-]autostash and rebase.autostash rebase --merge: return control to caller, for housekeeping rebase -i: return control to caller, for housekeeping am: return control to caller, for housekeeping rebase: prepare to do generic housekeeping rebase -i: don't error out if $state_dir already exists am: tighten a conditional that checks for $dotest
2 parents 52faa0e + 5879477 commit 45acb75

File tree

8 files changed

+235
-16
lines changed

8 files changed

+235
-16
lines changed

Documentation/config.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1867,6 +1867,14 @@ rebase.stat::
18671867
rebase.autosquash::
18681868
If set to true enable '--autosquash' option by default.
18691869

1870+
rebase.autostash::
1871+
When set to true, automatically create a temporary stash
1872+
before the operation begins, and apply it after the operation
1873+
ends. This means that you can run rebase on a dirty worktree.
1874+
However, use with care: the final stash application after a
1875+
successful rebase might result in non-trivial conflicts.
1876+
Defaults to false.
1877+
18701878
receive.autogc::
18711879
By default, git-receive-pack will run "git-gc --auto" after
18721880
receiving data from git-push and updating refs. You can stop

Documentation/git-rebase.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,9 @@ rebase.stat::
208208
rebase.autosquash::
209209
If set to true enable '--autosquash' option by default.
210210

211+
rebase.autostash::
212+
If set to true enable '--autostash' option by default.
213+
211214
OPTIONS
212215
-------
213216
--onto <newbase>::
@@ -394,6 +397,13 @@ If the '--autosquash' option is enabled by default using the
394397
configuration variable `rebase.autosquash`, this option can be
395398
used to override and disable this setting.
396399

400+
--[no-]autostash::
401+
Automatically create a temporary stash before the operation
402+
begins, and apply it after the operation ends. This means
403+
that you can run rebase on a dirty worktree. However, use
404+
with care: the final stash application after a successful
405+
rebase might result in non-trivial conflicts.
406+
397407
--no-ff::
398408
With --interactive, cherry-pick all rebased commits instead of
399409
fast-forwarding over the unchanged ones. This ensures that the

git-am.sh

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,8 @@ done
446446
# If the dotest directory exists, but we have finished applying all the
447447
# patches in them, clear it out.
448448
if test -d "$dotest" &&
449+
test -f "$dotest/last" &&
450+
test -f "$dotest/next" &&
449451
last=$(cat "$dotest/last") &&
450452
next=$(cat "$dotest/next") &&
451453
test $# != 0 &&
@@ -454,7 +456,7 @@ then
454456
rm -fr "$dotest"
455457
fi
456458

457-
if test -d "$dotest"
459+
if test -d "$dotest" && test -f "$dotest/last" && test -f "$dotest/next"
458460
then
459461
case "$#,$skip$resolved$abort" in
460462
0,*t*)
@@ -904,5 +906,10 @@ if test -s "$dotest"/rewritten; then
904906
fi
905907
fi
906908

907-
rm -fr "$dotest"
908-
git gc --auto
909+
# If am was called with --rebasing (from git-rebase--am), it's up to
910+
# the caller to take care of housekeeping.
911+
if ! test -f "$dotest/rebasing"
912+
then
913+
rm -fr "$dotest"
914+
git gc --auto
915+
fi

git-rebase--am.sh

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ case "$action" in
77
continue)
88
git am --resolved --resolvemsg="$resolvemsg" &&
99
move_to_original_branch
10-
exit
10+
return
1111
;;
1212
skip)
1313
git am --skip --resolvemsg="$resolvemsg" &&
1414
move_to_original_branch
15-
exit
15+
return
1616
;;
1717
esac
1818

@@ -56,7 +56,7 @@ else
5656
5757
As a result, git cannot rebase them.
5858
EOF
59-
exit $?
59+
return $?
6060
fi
6161

6262
git am $git_am_opt --rebasing --resolvemsg="$resolvemsg" <"$GIT_DIR/rebased-patches"
@@ -68,7 +68,7 @@ fi
6868
if test 0 != $ret
6969
then
7070
test -d "$state_dir" && write_basic_state
71-
exit $ret
71+
return $ret
7272
fi
7373

7474
move_to_original_branch

git-rebase--interactive.sh

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -628,17 +628,16 @@ do_next () {
628628
"$GIT_DIR"/hooks/post-rewrite rebase < "$rewritten_list"
629629
true # we don't care if this hook failed
630630
fi &&
631-
rm -rf "$state_dir" &&
632-
git gc --auto &&
633631
warn "Successfully rebased and updated $head_name."
634632

635-
exit
633+
return 1 # not failure; just to break the do_rest loop
636634
}
637635

636+
# can only return 0, when the infinite loop breaks
638637
do_rest () {
639638
while :
640639
do
641-
do_next
640+
do_next || break
642641
done
643642
}
644643

@@ -805,11 +804,13 @@ first and then run 'git rebase --continue' again."
805804

806805
require_clean_work_tree "rebase"
807806
do_rest
807+
return 0
808808
;;
809809
skip)
810810
git rerere clear
811811

812812
do_rest
813+
return 0
813814
;;
814815
edit-todo)
815816
git stripspace --strip-comments <"$todo" >"$todo".new
@@ -842,7 +843,7 @@ then
842843
fi
843844

844845
orig_head=$(git rev-parse --verify HEAD) || die "No HEAD?"
845-
mkdir "$state_dir" || die "Could not create temporary $state_dir"
846+
mkdir -p "$state_dir" || die "Could not create temporary $state_dir"
846847

847848
: > "$state_dir"/interactive || die "Could not mark as interactive"
848849
write_basic_state

git-rebase--merge.sh

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@ finish_rb_merge () {
9696
"$GIT_DIR"/hooks/post-rewrite rebase <"$state_dir"/rewritten
9797
fi
9898
fi
99-
rm -r "$state_dir"
10099
say All done.
101100
}
102101

@@ -110,7 +109,7 @@ continue)
110109
continue_merge
111110
done
112111
finish_rb_merge
113-
exit
112+
return
114113
;;
115114
skip)
116115
read_state
@@ -122,7 +121,7 @@ skip)
122121
continue_merge
123122
done
124123
finish_rb_merge
125-
exit
124+
return
126125
;;
127126
esac
128127

git-rebase.sh

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ git-rebase --continue | --abort | --skip | --edit-todo
1313
Available options are
1414
v,verbose! display a diffstat of what changed upstream
1515
q,quiet! be quiet. implies --no-stat
16+
autostash! automatically stash/stash pop before and after
1617
onto=! rebase onto given branch instead of upstream
1718
p,preserve-merges! try to recreate merges instead of ignoring them
1819
s,strategy=! use the given merge strategy
@@ -64,6 +65,7 @@ apply_dir="$GIT_DIR"/rebase-apply
6465
verbose=
6566
diffstat=
6667
test "$(git config --bool rebase.stat)" = true && diffstat=t
68+
autostash="$(git config --bool rebase.autostash || echo false)"
6769
git_am_opt=
6870
rebase_root=
6971
force_rebase=
@@ -143,13 +145,42 @@ move_to_original_branch () {
143145
esac
144146
}
145147

148+
finish_rebase () {
149+
if test -f "$state_dir/autostash"
150+
then
151+
stash_sha1=$(cat "$state_dir/autostash")
152+
if git stash apply $stash_sha1 2>&1 >/dev/null
153+
then
154+
echo "$(gettext 'Applied autostash.')"
155+
else
156+
ref_stash=refs/stash &&
157+
>>"$GIT_DIR/logs/$ref_stash" &&
158+
git update-ref -m "autostash" $ref_stash $stash_sha1 ||
159+
die "$(eval_gettext 'Cannot store $stash_sha1')"
160+
161+
gettext 'Applying autostash resulted in conflicts.
162+
Your changes are safe in the stash.
163+
You can run "git stash pop" or "git stash drop" it at any time.
164+
'
165+
fi
166+
fi
167+
git gc --auto &&
168+
rm -rf "$state_dir"
169+
}
170+
146171
run_specific_rebase () {
147172
if [ "$interactive_rebase" = implied ]; then
148173
GIT_EDITOR=:
149174
export GIT_EDITOR
150175
autosquash=
151176
fi
152177
. git-rebase--$type
178+
ret=$?
179+
if test $ret -eq 0
180+
then
181+
finish_rebase
182+
fi
183+
exit $ret
153184
}
154185

155186
run_pre_rebase_hook () {
@@ -241,6 +272,9 @@ do
241272
--stat)
242273
diffstat=t
243274
;;
275+
--autostash)
276+
autostash=true
277+
;;
244278
-v)
245279
verbose=t
246280
diffstat=t
@@ -341,7 +375,7 @@ abort)
341375
;;
342376
esac
343377
output git reset --hard $orig_head
344-
rm -r "$state_dir"
378+
finish_rebase
345379
exit
346380
;;
347381
edit-todo)
@@ -480,6 +514,18 @@ case "$#" in
480514
;;
481515
esac
482516

517+
if test "$autostash" = true && ! (require_clean_work_tree) 2>/dev/null
518+
then
519+
stash_sha1=$(git stash create "autostash") ||
520+
die "$(gettext 'Cannot autostash')"
521+
522+
mkdir -p "$state_dir" &&
523+
echo $stash_sha1 >"$state_dir/autostash" &&
524+
stash_abbrev=$(git rev-parse --short $stash_sha1) &&
525+
echo "$(eval_gettext 'Created autostash: $stash_abbrev')" &&
526+
git reset --hard
527+
fi
528+
483529
require_clean_work_tree "rebase" "$(gettext "Please commit or stash them.")"
484530

485531
# Now we are rebasing commits $upstream..$orig_head (or with --root,

0 commit comments

Comments
 (0)