{"thread":{"id":"24647","subject":"[PATCH 0/2] Fix spurious conflicts with pull --rebase","startedAt":"2010-08-06T14:05:01Z","lastAt":"2010-08-08T19:27:19Z","messageCount":4,"participants":["Elijah Newren"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"147314","messageId":"1281103503-27515-1-git-send-email-newren@gmail.com","threadId":"24647","inReplyTo":null,"subject":"[PATCH 0/2] Fix spurious conflicts with pull --rebase","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2010-08-06T14:05:01Z","receivedAt":"2010-08-06T14:05:01Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"This patch series fixes git pull --rebase failing to detect if \"local\"\npatches are already upstream in cases where the upstream repository is\nnot itself rebased.  Also in the non-rebased upstream case, this\nseries avoids checking/applying more patches than needed (i.e. avoids\nhaving rebase work on commits which are already reachable from\nupstream).\n\nIt would be nice to make 'git pull --rebase' able to detect if patches\nbeing applied are already part of upstream in cases where the upstream\nrepository has been rebased.  As far as I can tell, that would require\nchanges to format-patch to allow it to be told what 'upstream' is, and\nsome changes to git-pull.sh/git-rebase.sh to pass it this information.\n\nElijah Newren (2):\n  t5520-pull: Add testcases showing spurious conflicts from git pull\n    --rebase\n  pull --rebase: Avoid spurious conflicts and reapplying unnecessary\n    patches\n\n git-pull.sh     |   34 ++++++++++++++++++++-----------\n t/t5520-pull.sh |   59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 81 insertions(+), 12 deletions(-)\n"},{"id":"147316","messageId":"1281103503-27515-2-git-send-email-newren@gmail.com","threadId":"24647","inReplyTo":"1281103503-27515-1-git-send-email-newren@gmail.com","subject":"[PATCH 1/2] t5520-pull: Add testcases showing spurious conflicts from git pull --rebase","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2010-08-06T14:05:02Z","receivedAt":"2010-08-06T14:05:02Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n t/t5520-pull.sh |   59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 59 insertions(+), 0 deletions(-)\n\ndiff --git a/t/t5520-pull.sh b/t/t5520-pull.sh\nindex 319e389..8f76829 100755\n--- a/t/t5520-pull.sh\n+++ b/t/t5520-pull.sh\n@@ -160,4 +160,63 @@ test_expect_success 'pull --rebase works on branch yet to be born' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'setup for detecting upstreamed changes' '\n+\tmkdir src &&\n+\t(cd src &&\n+\t git init &&\n+\t for i in $(seq 1 10); do echo $i; done > stuff &&\n+\t git add stuff &&\n+\t git commit -m \"Initial revision\"\n+\t) &&\n+\tgit clone src dst &&\n+\t(cd src &&\n+\t sed -i s/5/43/ stuff &&\n+\t git commit -a -m \"5->43\" &&\n+\t sed -i s/6/42/ stuff &&\n+\t git commit -a -m \"Make it bigger\" &&\n+\t correct=$(git rev-parse HEAD)\n+\t) &&\n+\t(cd dst &&\n+\t sed -i s/5/43/ stuff &&\n+\t git commit -a -m \"Independent discovery of 5->43\"\n+\t)\n+'\n+\n+test_expect_failure 'git pull --rebase detects upstreamed changes' '\n+\t(cd dst &&\n+\t git pull --rebase &&\n+\t test -z \"$(git ls-files -u)\"\n+\t)\n+'\n+\n+test_expect_success 'setup for avoiding reapplying old patches' '\n+\t(cd dst &&\n+\t (git rebase --abort || true) &&\n+\t git reset --hard origin/master\n+\t) &&\n+\tgit clone --bare src src-replace.git &&\n+\trm -rf src &&\n+\tmv src-replace.git src &&\n+\t(cd dst &&\n+\t sed -i s/2/22/ stuff &&\n+\t git commit -a -m \"Change 2\" &&\n+\t sed -i s/3/33/ stuff &&\n+\t git commit -a -m \"Change 3\" &&\n+\t sed -i s/4/44/ stuff &&\n+\t git commit -a -m \"Chagne 4\" &&\n+\t git push &&\n+\n+\t sed -i s/44/55/ stuff &&\n+\t git commit --amend -a -m \"Change 4\" &&\n+\t test_must_fail git push\n+\t)\n+'\n+\n+test_expect_failure 'git pull --rebase does not reapply old patches' '\n+\t(cd dst &&\n+\t (git pull --rebase || true) &&\n+\t test 3 != $(find .git/rebase-apply -name \"000*\" | wc -l)\n+\t)\n+'\n+\n test_done\n-- \n1.7.1.1\n"},{"id":"147315","messageId":"1281103503-27515-3-git-send-email-newren@gmail.com","threadId":"24647","inReplyTo":"1281103503-27515-1-git-send-email-newren@gmail.com","subject":"[PATCH 2/2] pull --rebase: Avoid spurious conflicts and reapplying unnecessary patches","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2010-08-06T14:05:03Z","receivedAt":"2010-08-06T14:05:03Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Prior to c85c79279df2c8a583d95449d1029baba41f8660, pull --rebase would run\n  git rebase $merge_head\nwhich resulted in a call to\n  git format-patch ... --ignore-if-in-upstream $merge_head..$cur_branch\n\nThis had two nice qualities when upstream isn't rebased: (1) \"only\" the\npatches in $merge_head..$cur_branch would be applied, and (2) patches\ncould be dropped/ignored if they had already been applied.  But this did\nnot work well when upstream is rebased, since in that case\n$merge_head..$cur_branch refers to too many commits that would need to be\nreapplied, and could result in intentionally dropped commits being\nreintroduced.\n\nSo the algorithm was changed.  Defining $old_remote_ref to be the most\nrecent entry in the reflog for @upstream that is an ancestor of\n$cur_branch, pull --rebase was changed (over time) to run\n  git rebase --onto $merge_head $old_remote_ref\nwhich results in a call to\n  git format-patch ... --ignore-if-in-upstream $old_remote_ref..$cur_branch\n\nIn the rebased upstream case, this can result in far fewer commits being\nincluded in the rebase, though the fact that $old_remote_ref is an ancestor\nof $cur_branch means that format-patch will not know what upstream is and\nwill not be able to determine if any patches are already upstream.\n\nIn the non-rebased upstream case, this new form is usually the same as the\noriginal code.  However, as noted above, the --ignore-if-in-upstream flag\nbecomes meaningless and all patches will be forced to be reapplied.  Also,\n$old_remote_ref can be an ancestor of\n   $(git merge-base $merge_head $cur_branch)\nmeaning that pull --rebase may try to reapply more patches which are\nclearly already upstream, without the means to detect that they've already\nbeen applied.  This can be extremely confusing for new users (\"git is\ngiving me lots of conflicts in stuff I didn't even change since my last\npush.\")\n\nFix the non-rebased upstream case by ignoring $old_remote_ref whenever it\nis contained by $(git merge-base $merge_head $cur_branch).\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n git-pull.sh     |   34 ++++++++++++++++++++++------------\n t/t5520-pull.sh |    4 ++--\n 2 files changed, 24 insertions(+), 14 deletions(-)\n\ndiff --git a/git-pull.sh b/git-pull.sh\nindex a09a44e..54da07b 100755\n--- a/git-pull.sh\n+++ b/git-pull.sh\n@@ -206,18 +206,6 @@ test true = \"$rebase\" && {\n \t\tgit diff-index --ignore-submodules --cached --quiet HEAD -- ||\n \t\tdie \"refusing to pull with rebase: your working tree is not up-to-date\"\n \tfi\n-\toldremoteref= &&\n-\t. git-parse-remote &&\n-\tremoteref=\"$(get_remote_merge_branch \"$@\" 2>/dev/null)\" &&\n-\toldremoteref=\"$(git rev-parse -q --verify \"$remoteref\")\" &&\n-\tfor reflog in $(git rev-list -g $remoteref 2>/dev/null)\n-\tdo\n-\t\tif test \"$reflog\" = \"$(git merge-base $reflog $curr_branch)\"\n-\t\tthen\n-\t\t\toldremoteref=\"$reflog\"\n-\t\t\tbreak\n-\t\tfi\n-\tdone\n }\n orig_head=$(git rev-parse -q --verify HEAD)\n git fetch $verbosity $progress $dry_run --update-head-ok \"$@\" || exit 1\n@@ -273,6 +261,28 @@ then\n \texit\n fi\n \n+if test true = \"$rebase\"\n+then\n+\toldremoteref= &&\n+\t. git-parse-remote &&\n+\tremoteref=\"$(get_remote_merge_branch \"$@\" 2>/dev/null)\" &&\n+\toldremoteref=\"$(git rev-parse -q --verify \"$remoteref\")\" &&\n+\tfor reflog in $(git rev-list -g $remoteref 2>/dev/null)\n+\tdo\n+\t\tif test \"$reflog\" = \"$(git merge-base $reflog $curr_branch)\"\n+\t\tthen\n+\t\t\toldremoteref=\"$reflog\"\n+\t\t\tbreak\n+\t\tfi\n+\tdone\n+\n+\to=$(git show-branch --merge-base $curr_branch $merge_head $oldremoteref)\n+\tif test \"$oldremoteref\" = \"$o\"\n+\tthen\n+\t\tunset oldremoteref\n+\tfi\n+fi\n+\n merge_name=$(git fmt-merge-msg $log_arg <\"$GIT_DIR/FETCH_HEAD\") || exit\n case \"$rebase\" in\n true)\ndiff --git a/t/t5520-pull.sh b/t/t5520-pull.sh\nindex 8f76829..4bf2253 100755\n--- a/t/t5520-pull.sh\n+++ b/t/t5520-pull.sh\n@@ -182,7 +182,7 @@ test_expect_success 'setup for detecting upstreamed changes' '\n \t)\n '\n \n-test_expect_failure 'git pull --rebase detects upstreamed changes' '\n+test_expect_success 'git pull --rebase detects upstreamed changes' '\n \t(cd dst &&\n \t git pull --rebase &&\n \t test -z \"$(git ls-files -u)\"\n@@ -212,7 +212,7 @@ test_expect_success 'setup for avoiding reapplying old patches' '\n \t)\n '\n \n-test_expect_failure 'git pull --rebase does not reapply old patches' '\n+test_expect_success 'git pull --rebase does not reapply old patches' '\n \t(cd dst &&\n \t (git pull --rebase || true) &&\n \t test 3 != $(find .git/rebase-apply -name \"000*\" | wc -l)\n-- \n1.7.1.1\n"},{"id":"147453","messageId":"AANLkTimmys53DbyvdJFnbb0_iiaAjwczC6GafZO=DRWf@mail.gmail.com","threadId":"24647","inReplyTo":"1281103503-27515-1-git-send-email-newren@gmail.com","subject":"Re: [PATCH 0/2] Fix spurious conflicts with pull --rebase","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2010-08-08T19:27:19Z","receivedAt":"2010-08-08T19:27:19Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Fri, Aug 6, 2010 at 8:05 AM, Elijah Newren <newren@gmail.com> wrote:\n> This patch series fixes git pull --rebase failing to detect if \"local\"\n> patches are already upstream in cases where the upstream repository is\n> not itself rebased.  Also in the non-rebased upstream case, this\n> series avoids checking/applying more patches than needed (i.e. avoids\n> having rebase work on commits which are already reachable from\n> upstream).\n>\n> It would be nice to make 'git pull --rebase' able to detect if patches\n> being applied are already part of upstream in cases where the upstream\n> repository has been rebased.  As far as I can tell, that would require\n> changes to format-patch to allow it to be told what 'upstream' is, and\n> some changes to git-pull.sh/git-rebase.sh to pass it this information.\n\nI obviously hadn't slept enough when I wrote the above paragraphs;\nthey don't parse very well.  Sorry about that.  I just posted a new\nseries, with some wording improvements and minor portability fixes.\n\n(For the benefit of those not following this list, to whom I gave a\ndirect link to this thread, the updated series is here:\nhttp://thread.gmane.org/gmane.comp.version-control.git/152918)\n\n\nElijah\n"}]}