{"thread":{"id":"26510","subject":"checkout/branch needs some extra safety around the --track option","startedAt":"2011-02-15T17:52:03Z","lastAt":"2011-02-18T04:32:28Z","messageCount":7,"participants":["Johan Herland","Junio C Hamano","Martin von Zweigbergk"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"161196","messageId":"201102151852.03881.johan@herland.net","threadId":"26510","inReplyTo":null,"subject":"checkout/branch needs some extra safety around the --track option","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2011-02-15T17:52:03Z","receivedAt":"2011-02-15T17:52:03Z","isPatch":false,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"Hi,\n\nI just got a problem report from a Git user a $dayjob, who was confused \nabout the following output from 'git push' (without arguments, in a \nrepo with push.default == 'tracking'):\n\n> ----------------------------------------------------------------\n> $ git push\n> Total 0 (delta 0), reused 0 (delta 0)\n> To .\n>     c9e7b5a..1bf9fed  mybranch -> v0.99\n> ----------------------------------------------------------------\n\nAfter some investigations, I could reproduce his problem with the \nfollowing commands:\n\n$ git checkout -b mybranch --track v0.99\n# Do work on mybranch\n$ git push\n\nIn other words. The branch was erroneously created with the --track \noption, setting up a bogus branch.mybranch config section. When \npushing, this caused the v0.99 tag to be (unexpectedly, to him) updated \nin the local repo.\n\nObviously, this is rooted in user error, but it occurs to me that Git \nshould be more helpful in this situation. I propose:\n\n1. When given \"--track\", branch/checkout should verify that the tracked \nbranch is indeed a branch (preferably a remote branch, although I guess \ntracking a local branch can make sense in some situations). At least, \nit should deny tracking a _tag_. Tracking a tag simply does not make \nsense at all (unless you expect the tag to move, in which case it \nshould be a branch and not a tag).\n\n2. 'git push' should not move tags by default (not even in your local \nrepo). Moving tags might be ok if given the -f option (still a remote \nrepo should be able to object). With the current version of Git, the \nfollowing commands will transform an annotated tag into a lightweight \ntag with no warning:\n\n$ git config push.default tracking\n$ git checkout -b foo --track $annotated_tag\n$ git push\n\n\n...Johan\n\n-- \nJohan Herland, <johan@herland.net>\nwww.herland.net\n"},{"id":"161208","messageId":"7vfwrpnjxr.fsf@alter.siamese.dyndns.org","threadId":"26510","inReplyTo":"201102151852.03881.johan@herland.net","subject":"Re: checkout/branch needs some extra safety around the --track option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-02-15T20:04:32Z","receivedAt":"2011-02-15T20:04:32Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johan Herland <johan@herland.net> writes:\n\n> 1. When given \"--track\", branch/checkout should verify that the tracked \n> branch is indeed a branch (preferably a remote branch, although I guess \n> tracking a local branch can make sense in some situations). At least, \n> it should deny tracking a _tag_. Tracking a tag simply does not make \n> sense at all (unless you expect the tag to move, in which case it \n> should be a branch and not a tag).\n\nSensible, I think.\n"},{"id":"161289","messageId":"201102161146.23749.johan@herland.net","threadId":"26510","inReplyTo":"7vfwrpnjxr.fsf@alter.siamese.dyndns.org","subject":"[PATCH] branch/checkout --track: Ensure that upstream branch is indeed a branch","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2011-02-16T10:46:23Z","receivedAt":"2011-02-16T10:46:23Z","isPatch":true,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"When creating a new branch using the --track option, we must make sure that\nwe don't try to set an upstream that does not make sense to follow (using\n'git pull') or update (using 'git push'). The current code checks against\nusing HEAD as upstream (since tracking a symref doesn't make sense). However,\ntracking a tag doesn't make sense either. Indeed, tracking _any_ ref that is\nnot a (local or remote) branch doesn't make sense, and should be disallowed.\n\nThis patch achieves this by checking that the ref we're trying to --track\nresides within refs/heads/* or refs/remotes/*. This new check replaces the\nprevious check against HEAD.\n\nA couple of testcases are also added, verifying that we cannot create\nbranches with tags as upstreams.\n\nFinally, some selftests relying on using a non-branch as an upstream have\nbeen reworked or removed:\n\n- t6040: Reverse the meaning of two tests that depend on the ability to\nuse (lightweight and annotated) tags as upstreams. These two tests were\noriginally added in commits 1be570f and 57ffc5f, and this patch reverts the\nintention of those two commits.\n\n- t7201: Remove part of a test (introduced in 9188ed8) relying on a\nnon-branch as upstream.\n\nSigned-off-by: Johan Herland <johan@herland.net>\n---\n\nOn Tuesday 15 February 2011, Junio C Hamano wrote:\n> Johan Herland <johan@herland.net> writes:\n> > 1. When given \"--track\", branch/checkout should verify that the tracked\n> > branch is indeed a branch (preferably a remote branch, although I guess\n> > tracking a local branch can make sense in some situations). At least,\n> > it should deny tracking a _tag_. Tracking a tag simply does not make\n> > sense at all (unless you expect the tag to move, in which case it\n> > should be a branch and not a tag).\n> \n> Sensible, I think.\n\nMake it so.\n\n...Johan\n\n branch.c                 |    6 ++++--\n t/t3200-branch.sh        |    5 +++++\n t/t6040-tracking-info.sh |   16 ++++++++--------\n t/t7201-co.sh            |   16 +++++++++-------\n 4 files changed, 26 insertions(+), 17 deletions(-)\n\ndiff --git a/branch.c b/branch.c\nindex 93dc866..f46a43a 100644\n--- a/branch.c\n+++ b/branch.c\n@@ -175,8 +175,10 @@ void create_branch(const char *head,\n \t\t\tdie(\"Cannot setup tracking information; starting point is not a branch.\");\n \t\tbreak;\n \tcase 1:\n-\t\t/* Unique completion -- good, only if it is a real ref */\n-\t\tif (explicit_tracking && !strcmp(real_ref, \"HEAD\"))\n+\t\t/* Unique completion -- good, only if it is a real branch */\n+\t\tif (explicit_tracking &&\n+\t\t    prefixcmp(real_ref, \"refs/heads/\") &&\n+\t\t    prefixcmp(real_ref, \"refs/remotes/\"))\n \t\t\tdie(\"Cannot setup tracking information; starting point is not a branch.\");\n \t\tbreak;\n \tdefault:\ndiff --git a/t/t3200-branch.sh b/t/t3200-branch.sh\nindex f308235..78da358 100755\n--- a/t/t3200-branch.sh\n+++ b/t/t3200-branch.sh\n@@ -223,6 +223,11 @@ test_expect_success \\\n     'branch from non-branch HEAD w/--track causes failure' \\\n     'test_must_fail git branch --track my10 HEAD^'\n \n+test_expect_success \\\n+    'branch from tag w/--track causes failure' \\\n+    'git tag foobar &&\n+     test_must_fail git branch --track my11 foobar'\n+\n # Keep this test last, as it changes the current branch\n cat >expect <<EOF\n 0000000000000000000000000000000000000000 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> \n1117150200 +0000\tbranch: Created from master\ndiff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh\nindex 1e0447f..cb85132 100755\n--- a/t/t6040-tracking-info.sh\n+++ b/t/t6040-tracking-info.sh\n@@ -74,20 +74,20 @@ test_expect_success 'status' '\n \tgrep \"have 1 and 1 different\" actual\n '\n \n-test_expect_success 'status when tracking lightweight tags' '\n+test_expect_success 'fail to track lightweight tags' '\n \tgit checkout master &&\n \tgit tag light &&\n-\tgit branch --track lighttrack light >actual &&\n-\tgrep \"set up to track\" actual &&\n-\tgit checkout lighttrack\n+\ttest_must_fail git branch --track lighttrack light >actual &&\n+\ttest_must_fail grep \"set up to track\" actual &&\n+\ttest_must_fail git checkout lighttrack\n '\n \n-test_expect_success 'status when tracking annotated tags' '\n+test_expect_success 'fail to track annotated tags' '\n \tgit checkout master &&\n \tgit tag -m heavy heavy &&\n-\tgit branch --track heavytrack heavy >actual &&\n-\tgrep \"set up to track\" actual &&\n-\tgit checkout heavytrack\n+\ttest_must_fail git branch --track heavytrack heavy >actual &&\n+\ttest_must_fail grep \"set up to track\" actual &&\n+\ttest_must_fail git checkout heavytrack\n '\n \n test_expect_success 'setup tracking with branch --set-upstream on existing branch' '\ndiff --git a/t/t7201-co.sh b/t/t7201-co.sh\nindex 1337fa5..0c002ab 100755\n--- a/t/t7201-co.sh\n+++ b/t/t7201-co.sh\n@@ -408,6 +408,15 @@ test_expect_success 'checkout w/--track from non-branch HEAD fails' '\n     test \"z$(git rev-parse master^0)\" = \"z$(git rev-parse HEAD)\"\n '\n \n+test_expect_success 'checkout w/--track from tag fails' '\n+    git checkout master^0 &&\n+    test_must_fail git symbolic-ref HEAD &&\n+    test_must_fail git checkout --track -b track frotz &&\n+    test_must_fail git rev-parse --verify track &&\n+    test_must_fail git symbolic-ref HEAD &&\n+    test \"z$(git rev-parse master^0)\" = \"z$(git rev-parse HEAD)\"\n+'\n+\n test_expect_success 'detach a symbolic link HEAD' '\n     git checkout master &&\n     git config --bool core.prefersymlinkrefs yes &&\n@@ -423,7 +432,6 @@ test_expect_success 'detach a symbolic link HEAD' '\n test_expect_success \\\n     'checkout with --track fakes a sensible -b <name>' '\n     git update-ref refs/remotes/origin/koala/bear renamer &&\n-    git update-ref refs/new/koala/bear renamer &&\n \n     git checkout --track origin/koala/bear &&\n     test \"refs/heads/koala/bear\" = \"$(git symbolic-ref HEAD)\" &&\n@@ -439,12 +447,6 @@ test_expect_success \\\n \n     git checkout --track remotes/origin/koala/bear &&\n     test \"refs/heads/koala/bear\" = \"$(git symbolic-ref HEAD)\" &&\n-    test \"$(git rev-parse HEAD)\" = \"$(git rev-parse renamer)\" &&\n-\n-    git checkout master && git branch -D koala/bear &&\n-\n-    git checkout --track refs/new/koala/bear &&\n-    test \"refs/heads/koala/bear\" = \"$(git symbolic-ref HEAD)\" &&\n     test \"$(git rev-parse HEAD)\" = \"$(git rev-parse renamer)\"\n '\n \n-- \n1.7.4\n"},{"id":"161346","messageId":"7vwrkzhc7x.fsf@alter.siamese.dyndns.org","threadId":"26510","inReplyTo":"201102161146.23749.johan@herland.net","subject":"Re: [PATCH] branch/checkout --track: Ensure that upstream branch is indeed a branch","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-02-16T22:00:02Z","receivedAt":"2011-02-16T22:00:02Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johan Herland <johan@herland.net> writes:\n\n> When creating a new branch using the --track option, we must make sure that\n> we don't try to set an upstream that does not make sense to follow (using\n> 'git pull') or update (using 'git push'). The current code checks against\n> using HEAD as upstream (since tracking a symref doesn't make sense). However,\n> tracking a tag doesn't make sense either. Indeed, tracking _any_ ref that is\n> not a (local or remote) branch doesn't make sense, and should be disallowed.\n>\n> This patch achieves this by checking that the ref we're trying to --track\n> resides within refs/heads/* or refs/remotes/*. This new check replaces the\n> previous check against HEAD.\n> ...\n> Make it so.\n>\n> diff --git a/branch.c b/branch.c\n> index 93dc866..f46a43a 100644\n> --- a/branch.c\n> +++ b/branch.c\n> @@ -175,8 +175,10 @@ void create_branch(const char *head,\n>  \t\t\tdie(\"Cannot setup tracking information; starting point is not a branch.\");\n>  \t\tbreak;\n>  \tcase 1:\n> -\t\t/* Unique completion -- good, only if it is a real ref */\n> -\t\tif (explicit_tracking && !strcmp(real_ref, \"HEAD\"))\n> +\t\t/* Unique completion -- good, only if it is a real branch */\n> +\t\tif (explicit_tracking &&\n> +\t\t    prefixcmp(real_ref, \"refs/heads/\") &&\n> +\t\t    prefixcmp(real_ref, \"refs/remotes/\"))\n>  \t\t\tdie(\"Cannot setup tracking information; starting point is not a branch.\");\n>  \t\tbreak;\n>  \tdefault:\n\nThomas's \"HEAD\" patch 84c1a89 (branch: do not attempt to track HEAD\nimplicitly, 2010-12-14) has an extra action to reset real_ref to NULL when\nnot asking for \"explicit_tracking\" in the same codepath.\n\n<<<<<<< HEAD\n\t\t/* Unique completion -- good, only if it is a real ref */\n\t\tif (!strcmp(real_ref, \"HEAD\")) {\n\t\t\tif (explicit_tracking)\n\t\t\t\tdie(\"Cannot setup tracking information; starting point is not a branch.\");\n\t\t\telse\n\t\t\t\treal_ref = NULL;\n\t\t}\n=======\n\t\t/* Unique completion -- good, only if it is a real branch */\n\t\tif (explicit_tracking &&\n\t\t    prefixcmp(real_ref, \"refs/heads/\") &&\n\t\t    prefixcmp(real_ref, \"refs/remotes/\"))\n\t\t\tdie(\"Cannot setup tracking information; starting point is not a branch.\");\n>>>>>>> @{-1}\n\nDon't we need something similar here?\n"},{"id":"161355","messageId":"201102170012.20964.johan@herland.net","threadId":"26510","inReplyTo":"7vwrkzhc7x.fsf@alter.siamese.dyndns.org","subject":"[PATCH v2] branch/checkout --track: Ensure that upstream branch is indeed a branch","fromName":"Johan Herland","fromEmail":"johan@herland.net","sentAt":"2011-02-16T23:12:20Z","receivedAt":"2011-02-16T23:12:20Z","isPatch":true,"sender":{"key":"johan@herland.net","avatar":"https://avatars.githubusercontent.com/u/547031?v=4"},"body":"When creating a new branch using the --track option, we must make sure that\nwe don't try to set an upstream that does not make sense to follow (using\n'git pull') or update (using 'git push'). The current code checks against\nusing HEAD as upstream (since tracking a symref doesn't make sense). However,\ntracking a tag doesn't make sense either. Indeed, tracking _any_ ref that is\nnot a (local or remote) branch doesn't make sense, and should be disallowed.\n\nThis patch achieves this by checking that the ref we're trying to --track\nresides within refs/heads/* or refs/remotes/*. This new check replaces the\nprevious check against HEAD.\n\nA couple of testcases are also added, verifying that we cannot create\nbranches with tags as upstreams.\n\nFinally, some selftests relying on using a non-branch as an upstream have\nbeen reworked or removed:\n\n- t6040: Reverse the meaning of two tests that depend on the ability to\nuse (lightweight and annotated) tags as upstreams. These two tests were\noriginally added in commits 1be570f and 57ffc5f, and this patch reverts the\nintention of those two commits.\n\n- t7201: Remove part of a test (introduced in 9188ed8) relying on a\nnon-branch as upstream.\n\nSigned-off-by: Johan Herland <johan@herland.net>\n---\n\nOn Wednesday 16 February 2011, Junio C Hamano wrote:\n> Thomas's \"HEAD\" patch 84c1a89 (branch: do not attempt to track HEAD\n> implicitly, 2010-12-14) has an extra action to reset real_ref to NULL\n> when not asking for \"explicit_tracking\" in the same codepath.\n> \n> ...\n> \n> Don't we need something similar here?\n\nIndeed. Here is v2, rebased on top of 84c1a89.\n\n...Johan\n\n branch.c                 |    5 +++--\n t/t3200-branch.sh        |    5 +++++\n t/t6040-tracking-info.sh |   16 ++++++++--------\n t/t7201-co.sh            |   16 +++++++++-------\n 4 files changed, 25 insertions(+), 17 deletions(-)\n\ndiff --git a/branch.c b/branch.c\nindex 19310e4..da5c03e 100644\n--- a/branch.c\n+++ b/branch.c\n@@ -175,8 +175,9 @@ void create_branch(const char *head,\n \t\t\tdie(\"Cannot setup tracking information; starting point is not a branch.\");\n \t\tbreak;\n \tcase 1:\n-\t\t/* Unique completion -- good, only if it is a real ref */\n-\t\tif (!strcmp(real_ref, \"HEAD\")) {\n+\t\t/* Unique completion -- good, only if it is a real branch */\n+\t\tif (prefixcmp(real_ref, \"refs/heads/\") &&\n+\t\t    prefixcmp(real_ref, \"refs/remotes/\")) {\n \t\t\tif (explicit_tracking)\n \t\t\t\tdie(\"Cannot setup tracking information; starting point is not a branch.\");\n \t\t\telse\ndiff --git a/t/t3200-branch.sh b/t/t3200-branch.sh\nindex dce90de..55af032 100755\n--- a/t/t3200-branch.sh\n+++ b/t/t3200-branch.sh\n@@ -212,6 +212,11 @@ test_expect_success \\\n     'branch from non-branch HEAD w/--track causes failure' \\\n     'test_must_fail git branch --track my10 HEAD^'\n \n+test_expect_success \\\n+    'branch from tag w/--track causes failure' \\\n+    'git tag foobar &&\n+     test_must_fail git branch --track my11 foobar'\n+\n # Keep this test last, as it changes the current branch\n cat >expect <<EOF\n 0000000000000000000000000000000000000000 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> \n1117150200 +0000\tbranch: Created from master\ndiff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh\nindex 1785e17..10bf3de 100755\n--- a/t/t6040-tracking-info.sh\n+++ b/t/t6040-tracking-info.sh\n@@ -74,20 +74,20 @@ test_expect_success 'status' '\n \tgrep \"have 1 and 1 different\" actual\n '\n \n-test_expect_success 'status when tracking lightweight tags' '\n+test_expect_success 'fail to track lightweight tags' '\n \tgit checkout master &&\n \tgit tag light &&\n-\tgit branch --track lighttrack light >actual &&\n-\tgrep \"set up to track\" actual &&\n-\tgit checkout lighttrack\n+\ttest_must_fail git branch --track lighttrack light >actual &&\n+\ttest_must_fail grep \"set up to track\" actual &&\n+\ttest_must_fail git checkout lighttrack\n '\n \n-test_expect_success 'status when tracking annotated tags' '\n+test_expect_success 'fail to track annotated tags' '\n \tgit checkout master &&\n \tgit tag -m heavy heavy &&\n-\tgit branch --track heavytrack heavy >actual &&\n-\tgrep \"set up to track\" actual &&\n-\tgit checkout heavytrack\n+\ttest_must_fail git branch --track heavytrack heavy >actual &&\n+\ttest_must_fail grep \"set up to track\" actual &&\n+\ttest_must_fail git checkout heavytrack\n '\n \n test_expect_success 'setup tracking with branch --set-upstream on existing branch' '\ndiff --git a/t/t7201-co.sh b/t/t7201-co.sh\nindex 1337fa5..0c002ab 100755\n--- a/t/t7201-co.sh\n+++ b/t/t7201-co.sh\n@@ -408,6 +408,15 @@ test_expect_success 'checkout w/--track from non-branch HEAD fails' '\n     test \"z$(git rev-parse master^0)\" = \"z$(git rev-parse HEAD)\"\n '\n \n+test_expect_success 'checkout w/--track from tag fails' '\n+    git checkout master^0 &&\n+    test_must_fail git symbolic-ref HEAD &&\n+    test_must_fail git checkout --track -b track frotz &&\n+    test_must_fail git rev-parse --verify track &&\n+    test_must_fail git symbolic-ref HEAD &&\n+    test \"z$(git rev-parse master^0)\" = \"z$(git rev-parse HEAD)\"\n+'\n+\n test_expect_success 'detach a symbolic link HEAD' '\n     git checkout master &&\n     git config --bool core.prefersymlinkrefs yes &&\n@@ -423,7 +432,6 @@ test_expect_success 'detach a symbolic link HEAD' '\n test_expect_success \\\n     'checkout with --track fakes a sensible -b <name>' '\n     git update-ref refs/remotes/origin/koala/bear renamer &&\n-    git update-ref refs/new/koala/bear renamer &&\n \n     git checkout --track origin/koala/bear &&\n     test \"refs/heads/koala/bear\" = \"$(git symbolic-ref HEAD)\" &&\n@@ -439,12 +447,6 @@ test_expect_success \\\n \n     git checkout --track remotes/origin/koala/bear &&\n     test \"refs/heads/koala/bear\" = \"$(git symbolic-ref HEAD)\" &&\n-    test \"$(git rev-parse HEAD)\" = \"$(git rev-parse renamer)\" &&\n-\n-    git checkout master && git branch -D koala/bear &&\n-\n-    git checkout --track refs/new/koala/bear &&\n-    test \"refs/heads/koala/bear\" = \"$(git symbolic-ref HEAD)\" &&\n     test \"$(git rev-parse HEAD)\" = \"$(git rev-parse renamer)\"\n '\n \n-- \n1.7.4\n"},{"id":"161477","messageId":"alpine.DEB.2.00.1102171937460.14950@debian","threadId":"26510","inReplyTo":"201102170012.20964.johan@herland.net","subject":"Re: [PATCH v2] branch/checkout --track: Ensure that upstream branch is indeed a branch","fromName":"Martin von Zweigbergk","fromEmail":"martin.von.zweigbergk@gmail.com","sentAt":"2011-02-18T00:45:59Z","receivedAt":"2011-02-18T00:45:59Z","isPatch":true,"sender":{"key":"martinvonz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/891642?v=4"},"body":"On Thu, 17 Feb 2011, Johan Herland wrote:\n\n> When creating a new branch using the --track option, we must make sure that\n> we don't try to set an upstream that does not make sense to follow (using\n> 'git pull') or update (using 'git push'). The current code checks against\n> using HEAD as upstream (since tracking a symref doesn't make sense). However,\n> tracking a tag doesn't make sense either. Indeed, tracking _any_ ref that is\n> not a (local or remote) branch doesn't make sense, and should be disallowed.\n> \n> This patch achieves this by checking that the ref we're trying to --track\n> resides within refs/heads/* or refs/remotes/*. This new check replaces the\n> previous check against HEAD.\n\nIn some workflows (e.g. Linux kernel, IIRC), it is recommended to base\nyour work on a tag. Is it worth considering that people might use a\ntag as upstream for such cases or would that be considered abuse of\nthe \"upstream\" concept? It could make sense to set an upstream to\npoint to a tag for reference and to be able to use e.g. 'rebase -i\n@{u}', 'git log @{u}..' and similar.\n\n\n/Martin\n"},{"id":"161503","messageId":"7vk4gy55er.fsf@alter.siamese.dyndns.org","threadId":"26510","inReplyTo":"alpine.DEB.2.00.1102171937460.14950@debian","subject":"Re: [PATCH v2] branch/checkout --track: Ensure that upstream branch is indeed a branch","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-02-18T04:32:28Z","receivedAt":"2011-02-18T04:32:28Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Martin von Zweigbergk <martin.von.zweigbergk@gmail.com> writes:\n\n> In some workflows (e.g. Linux kernel, IIRC), it is recommended to base\n> your work on a tag.\n\nBut the thing is, \"base your work on some known point\" is a rule invented\nexactly to discourage casual and frequent rebasing.\n\nIf you started your work on v2.6.36 and need to rebase to a more recent\nversion, you won't be using \"rebase @{upstream}\" notation _anyway_, as the\nold base you forked your work from that you would refer to as @{upstream}\nwill not be moving.  You will instead rebasing on top of a _different_\ncommit, perhaps v2.6.38 or something.\n\nSo the workflow would look more like: \n\n\t$ git checkout -b frotz-2.6.36 v2.6.36\n        ... develop \"frotz\" feature on top of 2.6.36\n\n        ... time passes ...\n\n\t$ git checkout -b frotz-2.6.38 frotz-2.6.36\n        $ git rebase --onto v2.6.38 v2.6.36\n\t... inspect the result and it looks good.\n        ... if  you don't want frotz in 2.6.36 then...\n        $ git branch -D frotz-2.6.36\n\nThere is not much point in using @{upstream} when your branch management\nis as disciplined as that recommended practice you cited.\n"}]}