From: Stephen Haberman <hidden> Date: 2016-06-15 22:45:29
This is v3, rebased on top of sp/maint with sp/master and sh/maint-rebase3.
So, it should apply cleanly to that. Junio's feedback aside, the only change
from v2 is that maint-rebase3's dropped commit check needs to be done before
Johannes's recent addition of:
test -s "$TODO" || echo noop >> "$TODO"
Because now the todo may temporarily have picks in it while probing for parents
that could later be removed by the dropped/cherry-picked commit check.
Previously todo never had temporary entries, so it didn't matter when the
dropped commit check was done.
(Apologies for not seeing Junio's what's cooking first and using his
maint/master instead of Shawn's. Let me know if I need to redo this and I will
get even more practice at rebasing.)
(Gah, resending with the list cc'd this time. Dammit, sorry about that.)
Thanks,
Stephen
Stephen Haberman (7):
rebase-i-p: test to exclude commits from todo based on its parents
rebase-i-p: use HEAD for updating the ref instead of mapping OLDHEAD
rebase-i-p: delay saving current-commit to REWRITTEN if squashing
rebase-i-p: fix 'no squashing merges' tripping up non-merges
rebase-i-p: only list commits that require rewriting in todo
rebase-i-p: do not include non-first-parent commits touching UPSTREAM
rebase-i-p: if todo was reordered use HEAD as the rewritten parent
git-rebase--interactive.sh | 131 ++++++++++++++++++-----------
t/t3411-rebase-preserve-around-merges.sh | 136 ++++++++++++++++++++++++++++++
2 files changed, 218 insertions(+), 49 deletions(-)
create mode 100644 t/t3411-rebase-preserve-around-merges.sh
From: Stephen Haberman <hidden> Date: 2016-06-15 22:45:29
If the current-commit was dumped to REWRITTEN, but then we squash the next
commit in to it, we have invalidated the HEAD was just written to REWRITTEN.
Instead, append the squash hash to current-commit and save both of them the next
time around.
Signed-off-by: Stephen Haberman <redacted>
---
git-rebase--interactive.sh | 15 ++++++++++-----
1 files changed, 10 insertions(+), 5 deletions(-)
@@ -170,13 +170,18 @@ pick_one_preserving_merges () {iftest-f"$DOTEST"/current-committhen-current_commit=$(cat"$DOTEST"/current-commit)&&-gitrev-parseHEAD>"$REWRITTEN"/$current_commit&&-rm"$DOTEST"/current-commit||-die"Cannot write current commit's replacement sha1"+if["$fast_forward"=="t"]+then+cat"$DOTEST"/current-commit|whilereadcurrent_commit+do+gitrev-parseHEAD>"$REWRITTEN"/$current_commit+done+rm"$DOTEST"/current-commit||+die"Cannot write current commit's replacement sha1"+fifi-echo$sha1>"$DOTEST"/current-commit+echo$sha1>>"$DOTEST"/current-commit# rewrite parents; if none were rewritten, we can fast-forward.new_parents=
From: Stephen Haberman <hidden> Date: 2016-06-15 22:45:29
The first case was based off a script from Avi Kivity [off-list ref].
The second case includes a merge-of-a-merge to ensure both are included in todo.
Signed-off-by: Stephen Haberman <redacted>
---
t/t3411-rebase-preserve-around-merges.sh | 136 ++++++++++++++++++++++++++++++
1 files changed, 136 insertions(+), 0 deletions(-)
create mode 100644 t/t3411-rebase-preserve-around-merges.sh
From: Stephen Haberman <hidden> Date: 2016-06-15 22:45:29
If OLDHEAD was reordered in the todo, and its mapped NEWHEAD was used to set the
ref, commits reordered after OLDHEAD in the todo would should up as un-committed
changes.
Signed-off-by: Stephen Haberman <redacted>
---
git-rebase--interactive.sh | 15 +--------------
1 files changed, 1 insertions(+), 14 deletions(-)
From: Stephen Haberman <hidden> Date: 2016-06-15 22:45:29
This is heavily based on Stephan Beyer's git sequencer rewrite of rebase-i-p.
Each commit is still found by rev-list UPSTREAM..HEAD, but a commit is only
included in todo if at least one its parents has been marked for rewriting.
Signed-off-by: Stephen Haberman <redacted>
---
git-rebase--interactive.sh | 77 +++++++++++++++++++++++++++++--------------
1 files changed, 52 insertions(+), 25 deletions(-)
@@ -579,18 +579,67 @@ first and then run 'git rebase --continue' again."echo$ONTO>"$REWRITTEN"/$c||die"Could not init rewritten commits"done+# No cherry-pick because our first pass is to determine+# parents to rewrite and skipping dropped commits would+# prematurely end our probeMERGES_OPTION=else-MERGES_OPTION=--no-merges+MERGES_OPTION="--no-merges --cherry-pick"fiSHORTUPSTREAM=$(gitrev-parse--short$UPSTREAM)SHORTHEAD=$(gitrev-parse--short$HEAD)SHORTONTO=$(gitrev-parse--short$ONTO)gitrev-list$MERGES_OPTION--pretty=oneline--abbrev-commit\---abbrev=7--reverse--left-right--cherry-pick\+--abbrev=7--reverse--left-right--topo-order\$UPSTREAM...$HEAD|\-sed-n"s/^>/pick /p">"$TODO"+sed-n"s/^>//p"|whilereadshortsha1rest+do+iftestt!="$PRESERVE_MERGES"+then+echo"pick $shortsha1$rest">>"$TODO"+else+sha1=$(gitrev-parse$shortsha1)+preserve=t+forpin$(gitrev-list--parents-1$sha1|cut-d' '-f2-)+do+iftest-f"$REWRITTEN"/$p+then+preserve=f+fi+done+iftestf="$preserve"+then+touch"$REWRITTEN"/$sha1+echo"pick $shortsha1$rest">>"$TODO"+fi+fi+done++# Watch for commits that been dropped by --cherry-pick+iftestt="$PRESERVE_MERGES"+then+mkdir"$DROPPED"+# Save all non-cherry-picked changes+gitrev-list$UPSTREAM...$HEAD--left-right--cherry-pick|\+sed-n"s/^>//p">"$DOTEST"/not-cherry-picks+# Now all commits and note which ones are missing in+# not-cherry-picks and hence being dropped+gitrev-list$UPSTREAM...$HEAD--left-right|\+sed-n"s/^>//p"|whilereadrev+do+iftest-f"$REWRITTEN"/$rev-a"$(grep"$rev""$DOTEST"/not-cherry-picks)"=""+then+# Use -f2 because if rev-list is telling us this commit is+# not worthwhile, we don't want to track its multiple heads,+# just the history of its first-parent for others that will+# be rebasing on top of it+gitrev-list--parents-1$rev|cut-d' '-f2>"$DROPPED"/$rev+cat"$TODO"|grep-v"${rev:0:7}">"${TODO}2";mv"${TODO}2""$TODO"+rm"$REWRITTEN"/$rev+fi+done+fitest-s"$TODO"||echonoop>>"$TODO"cat>>"$TODO"<<EOF
@@ -606,28 +655,6 @@ first and then run 'git rebase --continue' again."# EOF-# Watch for commits that been dropped by --cherry-pick-iftestt="$PRESERVE_MERGES"-then-mkdir"$DROPPED"-# drop the --cherry-pick parameter this time-gitrev-list$MERGES_OPTION--abbrev-commit\---abbrev=7$UPSTREAM...$HEAD--left-right|\-sed-n"s/^>//p"|whilereadrev-do-grep--quiet"$rev""$TODO"-if[$?-ne0]-then-# Use -f2 because if rev-list is telling this commit is not-# worthwhile, we don't want to track its multiple heads,-# just the history of its first-parent for others that will-# be rebasing on top of us-full=$(gitrev-parse$rev)-gitrev-list--parents-1$rev|cut-d' '-f2>"$DROPPED"/$full-fi-done-fi-has_action"$TODO"||die_abort"Nothing to do"
From: Stephen Haberman <hidden> Date: 2016-06-15 22:45:29
Also only check out the first parent if this commit if not a squash--if it is a
squash, we want to explicitly ignore the parent and leave the wc as is, as
cherry-pick will apply the squash on top of it.
Signed-off-by: Stephen Haberman <redacted>
---
git-rebase--interactive.sh | 14 +++++++++-----
1 files changed, 9 insertions(+), 5 deletions(-)
@@ -219,15 +219,19 @@ pick_one_preserving_merges () {die"Cannot fast forward to $sha1";;f)-test"a$1"=a-n&&die"Refusing to squash a merge: $sha1"-first_parent=$(expr"$new_parents":' \([^ ]*\)')-# detach HEAD to current parent-outputgitcheckout$first_parent2>/dev/null||-die"Cannot move HEAD to $first_parent"++if["$1"!="-n"]+then+# detach HEAD to current parent+outputgitcheckout$first_parent2>/dev/null||+die"Cannot move HEAD to $first_parent"+ficase"$new_parents"in' '*' '*)+test"a$1"=a-n&&die"Refusing to squash a merge: $sha1"+# redo mergeauthor_script=$(get_author_ident_from_commit$sha1)eval"$author_script"
From: Stephen Haberman <hidden> Date: 2016-06-15 22:45:29
This covers an odd boundary case found by Avi Kivity's script where a branch
coming off of UPSTREAM is merged into HEAD. Initially it show up in
UPSTREAM..HEAD, but technically UPSTREAM is not moving, the rest of head is, so
we should not need to rewrite the merge.
This adds a check saying we can keep `preserve=t` if `p=UPSTREAM`...unless this
is the first first-parent commit in our UPSTREAM..HEAD rev-list, which could
very well point to UPSTREAM, but we still need to consider it as rewritten so we
start pulling in the rest of the UPSTREAM..HEAD commits that point to it.
Signed-off-by: Stephen Haberman <redacted>
---
git-rebase--interactive.sh | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
@@ -583,6 +583,7 @@ first and then run 'git rebase --continue' again."# parents to rewrite and skipping dropped commits would# prematurely end our probeMERGES_OPTION=+first_after_upstream="$(gitrev-list--reverse--first-parent$UPSTREAM..$HEAD|head-n1)"elseMERGES_OPTION="--no-merges --cherry-pick"fi
@@ -603,7 +604,7 @@ first and then run 'git rebase --continue' again."preserve=tforpin$(gitrev-list--parents-1$sha1|cut-d' '-f2-)do-iftest-f"$REWRITTEN"/$p+iftest-f"$REWRITTEN"/$p-a\($p!=$UPSTREAM-o$sha1=$first_after_upstream\)thenpreserve=ffi
From: Stephen Haberman <hidden> Date: 2016-06-15 22:45:29
This seems like the best guess we can make until git sequencer marks are
available. That being said, within the context of re-ordering a commit before
its parent in todo, I think applying it on top of the current commit seems like
a reasonable assumption of what the user intended.
Signed-off-by: Stephen Haberman <redacted>
---
git-rebase--interactive.sh | 9 +++++++++
t/t3411-rebase-preserve-around-merges.sh | 4 ++--
2 files changed, 11 insertions(+), 2 deletions(-)
@@ -194,6 +194,15 @@ pick_one_preserving_merges () {iftest-f"$REWRITTEN"/$pthennew_p=$(cat"$REWRITTEN"/$p)++# If the todo reordered commits, and our parent is marked for+# rewriting, but hasn't been gotten to yet, assume the user meant to+# drop it on top of the current HEAD+iftest-z"$new_p"+then+new_p=$(gitrev-parseHEAD)+fi+test$p!=$new_p&&fast_forward=fcase"$new_parents"in*$new_p*)
@@ -80,7 +80,7 @@ test_expect_success 'setup' '# \ /# -- C1 --#-test_expect_failure'squash F1 into D1''+test_expect_success'squash F1 into D1''FAKE_LINES="1 squash 3 2"gitrebase-i-pB1&&test"$(gitrev-parseHEAD^2)"="$(gitrev-parsebranch)"&&test"$(gitrev-parseHEAD~2)"="$(gitrev-parseB1)"&&
@@ -99,7 +99,7 @@ test_expect_failure 'squash F1 into D1' '## And rebase G1..M1 onto E2-test_expect_failure'rebase two levels of merge''+test_expect_success'rebase two levels of merge''gitcheckout-bbranch2A1&&touchg&&gitaddg&&