{"thread":{"id":"23503","subject":"[RFC/PATCH] blind rebase --onto","startedAt":"2010-04-17T18:44:33Z","lastAt":"2010-04-17T18:44:33Z","messageCount":1,"participants":["Clemens Buchacher"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"139770","messageId":"20100417184433.GA14864@localhost","threadId":"23503","inReplyTo":null,"subject":"[RFC/PATCH] blind rebase --onto","fromName":"Clemens Buchacher","fromEmail":"drizzd@aon.at","sentAt":"2010-04-17T18:44:33Z","receivedAt":"2010-04-17T18:44:33Z","isPatch":true,"sender":{"key":"drizzd@gmx.net","avatar":"https://avatars.githubusercontent.com/u/59082?v=4"},"body":"Hi,\n\nI know that there have been several discussions about rebase tracking in the\npast and I admit that I was not following them too closely. So please feel\nfree to flame me if this idea is nothing new or even known to be bad. I\nappreciate your comments and I will try to get up to speed on this topic as\nsoon as possible.\n\nClemens\n\n--8<--\nWe start out with a history like this.\n\n         G subtopic\n        /\n       E---F topic\n      /\n A---B---C---D upstream\n\nAfter rebasing topic to upstream, subtopic is still based on the old\nhistory of topic.\n\n         G subtopic\n        /\n       E       E'---F' topic\n      /       /\n A---B---C---D upstream\n\nIf the changes introduced by E' differ from the ones introduced by E\nin any way, rebase will try to re-apply E on top of F'. This is not\nuseful at all and will almost certainly result in needless conflicts.\n\nThis situation is described more verbosely in Section \"RECOVERING FROM\nUPSTREAM REBASE, The hard case\" of the git-rebase(1) man page. The\nsuggested solution is to use as upstream the branch subtopic was\noriginally based on, i.e. in this case \"rebase --onto topic\ntopic@{1}\".\n\nSince the \"right\" upstream to use could have been any other reflog\nentry, this approach may require a significant amount of manual\ndigging through the reflog.\n\nThis patch introduces an algorithm to search the reflog automatically.\nIt searches the reflog for possible merge bases and chooses the one\nwith the \"largest amount of common history\".\n\nIn the example above, B is the merge base of subtopic and topic, but E\nis the merge base of subtopic and topic@{1} and is a strict descendant\nof B, which is why E has more common history with subtopic than B\ndoes. Therefore, \"rebase --onto topic\" does the right thing in this\ncase, and it would still do the right thing if topic had been\nrewritten multiple times in between.\n\nNote 1: This patch requires some cleanup. The branch to be rebased\n($branch) is evaluated only later in the code, which is why I am using\nHEAD directly.\n\nNote 2: The syntax should probably be something more noisy than\n\"rebase --onto <branch>\", at least until this should prove to be\nuseful in many cases.\n\nSigned-off-by: Clemens Buchacher <drizzd@aon.at>\n---\n git-rebase.sh |   37 ++++++++++++++++++++++++++++++++-----\n 1 files changed, 32 insertions(+), 5 deletions(-)\n\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex fb4fef7..e1d4cbf 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -404,11 +404,38 @@ esac\n \n if test -z \"$rebase_root\"\n then\n-\t# The upstream head must be given.  Make sure it is valid.\n-\tupstream_name=\"$1\"\n-\tshift\n-\tupstream=`git rev-parse --verify \"${upstream_name}^0\"` ||\n-\tdie \"invalid upstream $upstream_name\"\n+\tif test $# -ge 1\n+\tthen\n+\t\t# The upstream head must be given.  Make sure it is valid.\n+\t\tupstream_name=\"$1\"\n+\t\tshift\n+\t\tupstream=`git rev-parse --verify \"${upstream_name}^0\"` ||\n+\t\tdie \"invalid upstream $upstream_name\"\n+\telse\n+\t\ttest -n \"$newbase\" || usage\n+\t\tgit rev-parse -q --verify \"refs/heads/$newbase\" >/dev/null ||\n+\t\tgit rev-parse -q --verify \"refs/remotes/$newbase\" >/dev/null ||\n+\t\tdie \"not a branch: $newbase\"\n+\t\t# Search newbase reflog for commit with the largest common\n+\t\t# history. In case of nonlinear history only the first branch\n+\t\t# found is followed while any parallel ones are discarded.\n+\t\tmaxbase=\n+\t\tfor tip in `git rev-list -g \"$newbase\"`\n+\t\tdo\n+\t\t\tif base=$(git merge-base \"$tip\" HEAD) &&\n+\t\t\t\t(test -z \"$maxbase\" ||\n+\t\t\t\t(test -n \"`git rev-list $maxbase..$base`\" &&\n+\t\t\t\t test -z \"`git rev-list $base..$maxbase`\"))\n+\t\t\tthen\n+\t\t\t\tmaxbase=\"$base\"\n+\t\t\tfi\n+\t\tdone\n+\t\ttest -n \"$maxbase\" ||\n+\t\tdie \"Could not find a merge base for $newbase.\"\n+\t\tsay \"Using merge base $maxbase.\"\n+\t\tupstream_name=\"$maxbase\"\n+\t\tupstream=\"$maxbase\"\n+\tfi\n \tunset root_flag\n \tupstream_arg=\"$upstream_name\"\n else\n-- \n1.7.0.5.3.ga76e\n"}]}