git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* checkout/branch needs some extra safety around the --track option
@ 2011-02-15 17:52 Johan Herland
  2011-02-15 20:04 ` Junio C Hamano
  0 siblings, 1 reply; 7+ messages in thread
From: Johan Herland @ 2011-02-15 17:52 UTC (permalink / raw)
  To: git

Hi,

I just got a problem report from a Git user a $dayjob, who was confused 
about the following output from 'git push' (without arguments, in a 
repo with push.default == 'tracking'):

> ----------------------------------------------------------------
> $ git push
> Total 0 (delta 0), reused 0 (delta 0)
> To .
>     c9e7b5a..1bf9fed  mybranch -> v0.99
> ----------------------------------------------------------------

After some investigations, I could reproduce his problem with the 
following commands:

$ git checkout -b mybranch --track v0.99
# Do work on mybranch
$ git push

In other words. The branch was erroneously created with the --track 
option, setting up a bogus branch.mybranch config section. When 
pushing, this caused the v0.99 tag to be (unexpectedly, to him) updated 
in the local repo.

Obviously, this is rooted in user error, but it occurs to me that Git 
should be more helpful in this situation. I propose:

1. When given "--track", branch/checkout should verify that the tracked 
branch is indeed a branch (preferably a remote branch, although I guess 
tracking a local branch can make sense in some situations). At least, 
it should deny tracking a _tag_. Tracking a tag simply does not make 
sense at all (unless you expect the tag to move, in which case it 
should be a branch and not a tag).

2. 'git push' should not move tags by default (not even in your local 
repo). Moving tags might be ok if given the -f option (still a remote 
repo should be able to object). With the current version of Git, the 
following commands will transform an annotated tag into a lightweight 
tag with no warning:

$ git config push.default tracking
$ git checkout -b foo --track $annotated_tag
$ git push


...Johan

-- 
Johan Herland, <johan@herland.net>
www.herland.net

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: checkout/branch needs some extra safety around the --track option
  2011-02-15 17:52 checkout/branch needs some extra safety around the --track option Johan Herland
@ 2011-02-15 20:04 ` Junio C Hamano
  2011-02-16 10:46   ` [PATCH] branch/checkout --track: Ensure that upstream branch is indeed a branch Johan Herland
  0 siblings, 1 reply; 7+ messages in thread
From: Junio C Hamano @ 2011-02-15 20:04 UTC (permalink / raw)
  To: Johan Herland; +Cc: git

Johan Herland <johan@herland.net> writes:

> 1. When given "--track", branch/checkout should verify that the tracked 
> branch is indeed a branch (preferably a remote branch, although I guess 
> tracking a local branch can make sense in some situations). At least, 
> it should deny tracking a _tag_. Tracking a tag simply does not make 
> sense at all (unless you expect the tag to move, in which case it 
> should be a branch and not a tag).

Sensible, I think.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH] branch/checkout --track: Ensure that upstream branch is indeed a branch
  2011-02-15 20:04 ` Junio C Hamano
@ 2011-02-16 10:46   ` Johan Herland
  2011-02-16 22:00     ` Junio C Hamano
  0 siblings, 1 reply; 7+ messages in thread
From: Johan Herland @ 2011-02-16 10:46 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano

When creating a new branch using the --track option, we must make sure that
we don't try to set an upstream that does not make sense to follow (using
'git pull') or update (using 'git push'). The current code checks against
using HEAD as upstream (since tracking a symref doesn't make sense). However,
tracking a tag doesn't make sense either. Indeed, tracking _any_ ref that is
not a (local or remote) branch doesn't make sense, and should be disallowed.

This patch achieves this by checking that the ref we're trying to --track
resides within refs/heads/* or refs/remotes/*. This new check replaces the
previous check against HEAD.

A couple of testcases are also added, verifying that we cannot create
branches with tags as upstreams.

Finally, some selftests relying on using a non-branch as an upstream have
been reworked or removed:

- t6040: Reverse the meaning of two tests that depend on the ability to
use (lightweight and annotated) tags as upstreams. These two tests were
originally added in commits 1be570f and 57ffc5f, and this patch reverts the
intention of those two commits.

- t7201: Remove part of a test (introduced in 9188ed8) relying on a
non-branch as upstream.

Signed-off-by: Johan Herland <johan@herland.net>
---

On Tuesday 15 February 2011, Junio C Hamano wrote:
> Johan Herland <johan@herland.net> writes:
> > 1. When given "--track", branch/checkout should verify that the tracked
> > branch is indeed a branch (preferably a remote branch, although I guess
> > tracking a local branch can make sense in some situations). At least,
> > it should deny tracking a _tag_. Tracking a tag simply does not make
> > sense at all (unless you expect the tag to move, in which case it
> > should be a branch and not a tag).
> 
> Sensible, I think.

Make it so.

...Johan

 branch.c                 |    6 ++++--
 t/t3200-branch.sh        |    5 +++++
 t/t6040-tracking-info.sh |   16 ++++++++--------
 t/t7201-co.sh            |   16 +++++++++-------
 4 files changed, 26 insertions(+), 17 deletions(-)

diff --git a/branch.c b/branch.c
index 93dc866..f46a43a 100644
--- a/branch.c
+++ b/branch.c
@@ -175,8 +175,10 @@ void create_branch(const char *head,
 			die("Cannot setup tracking information; starting point is not a branch.");
 		break;
 	case 1:
-		/* Unique completion -- good, only if it is a real ref */
-		if (explicit_tracking && !strcmp(real_ref, "HEAD"))
+		/* Unique completion -- good, only if it is a real branch */
+		if (explicit_tracking &&
+		    prefixcmp(real_ref, "refs/heads/") &&
+		    prefixcmp(real_ref, "refs/remotes/"))
 			die("Cannot setup tracking information; starting point is not a branch.");
 		break;
 	default:
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index f308235..78da358 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -223,6 +223,11 @@ test_expect_success \
     'branch from non-branch HEAD w/--track causes failure' \
     'test_must_fail git branch --track my10 HEAD^'
 
+test_expect_success \
+    'branch from tag w/--track causes failure' \
+    'git tag foobar &&
+     test_must_fail git branch --track my11 foobar'
+
 # Keep this test last, as it changes the current branch
 cat >expect <<EOF
 0000000000000000000000000000000000000000 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 
1117150200 +0000	branch: Created from master
diff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh
index 1e0447f..cb85132 100755
--- a/t/t6040-tracking-info.sh
+++ b/t/t6040-tracking-info.sh
@@ -74,20 +74,20 @@ test_expect_success 'status' '
 	grep "have 1 and 1 different" actual
 '
 
-test_expect_success 'status when tracking lightweight tags' '
+test_expect_success 'fail to track lightweight tags' '
 	git checkout master &&
 	git tag light &&
-	git branch --track lighttrack light >actual &&
-	grep "set up to track" actual &&
-	git checkout lighttrack
+	test_must_fail git branch --track lighttrack light >actual &&
+	test_must_fail grep "set up to track" actual &&
+	test_must_fail git checkout lighttrack
 '
 
-test_expect_success 'status when tracking annotated tags' '
+test_expect_success 'fail to track annotated tags' '
 	git checkout master &&
 	git tag -m heavy heavy &&
-	git branch --track heavytrack heavy >actual &&
-	grep "set up to track" actual &&
-	git checkout heavytrack
+	test_must_fail git branch --track heavytrack heavy >actual &&
+	test_must_fail grep "set up to track" actual &&
+	test_must_fail git checkout heavytrack
 '
 
 test_expect_success 'setup tracking with branch --set-upstream on existing branch' '
diff --git a/t/t7201-co.sh b/t/t7201-co.sh
index 1337fa5..0c002ab 100755
--- a/t/t7201-co.sh
+++ b/t/t7201-co.sh
@@ -408,6 +408,15 @@ test_expect_success 'checkout w/--track from non-branch HEAD fails' '
     test "z$(git rev-parse master^0)" = "z$(git rev-parse HEAD)"
 '
 
+test_expect_success 'checkout w/--track from tag fails' '
+    git checkout master^0 &&
+    test_must_fail git symbolic-ref HEAD &&
+    test_must_fail git checkout --track -b track frotz &&
+    test_must_fail git rev-parse --verify track &&
+    test_must_fail git symbolic-ref HEAD &&
+    test "z$(git rev-parse master^0)" = "z$(git rev-parse HEAD)"
+'
+
 test_expect_success 'detach a symbolic link HEAD' '
     git checkout master &&
     git config --bool core.prefersymlinkrefs yes &&
@@ -423,7 +432,6 @@ test_expect_success 'detach a symbolic link HEAD' '
 test_expect_success \
     'checkout with --track fakes a sensible -b <name>' '
     git update-ref refs/remotes/origin/koala/bear renamer &&
-    git update-ref refs/new/koala/bear renamer &&
 
     git checkout --track origin/koala/bear &&
     test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
@@ -439,12 +447,6 @@ test_expect_success \
 
     git checkout --track remotes/origin/koala/bear &&
     test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
-    test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)" &&
-
-    git checkout master && git branch -D koala/bear &&
-
-    git checkout --track refs/new/koala/bear &&
-    test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
     test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)"
 '
 
-- 
1.7.4

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH] branch/checkout --track: Ensure that upstream branch is indeed a branch
  2011-02-16 10:46   ` [PATCH] branch/checkout --track: Ensure that upstream branch is indeed a branch Johan Herland
@ 2011-02-16 22:00     ` Junio C Hamano
  2011-02-16 23:12       ` [PATCH v2] " Johan Herland
  0 siblings, 1 reply; 7+ messages in thread
From: Junio C Hamano @ 2011-02-16 22:00 UTC (permalink / raw)
  To: Johan Herland; +Cc: git, Junio C Hamano

Johan Herland <johan@herland.net> writes:

> When creating a new branch using the --track option, we must make sure that
> we don't try to set an upstream that does not make sense to follow (using
> 'git pull') or update (using 'git push'). The current code checks against
> using HEAD as upstream (since tracking a symref doesn't make sense). However,
> tracking a tag doesn't make sense either. Indeed, tracking _any_ ref that is
> not a (local or remote) branch doesn't make sense, and should be disallowed.
>
> This patch achieves this by checking that the ref we're trying to --track
> resides within refs/heads/* or refs/remotes/*. This new check replaces the
> previous check against HEAD.
> ...
> Make it so.
>
> diff --git a/branch.c b/branch.c
> index 93dc866..f46a43a 100644
> --- a/branch.c
> +++ b/branch.c
> @@ -175,8 +175,10 @@ void create_branch(const char *head,
>  			die("Cannot setup tracking information; starting point is not a branch.");
>  		break;
>  	case 1:
> -		/* Unique completion -- good, only if it is a real ref */
> -		if (explicit_tracking && !strcmp(real_ref, "HEAD"))
> +		/* Unique completion -- good, only if it is a real branch */
> +		if (explicit_tracking &&
> +		    prefixcmp(real_ref, "refs/heads/") &&
> +		    prefixcmp(real_ref, "refs/remotes/"))
>  			die("Cannot setup tracking information; starting point is not a branch.");
>  		break;
>  	default:

Thomas's "HEAD" patch 84c1a89 (branch: do not attempt to track HEAD
implicitly, 2010-12-14) has an extra action to reset real_ref to NULL when
not asking for "explicit_tracking" in the same codepath.

<<<<<<< HEAD
		/* Unique completion -- good, only if it is a real ref */
		if (!strcmp(real_ref, "HEAD")) {
			if (explicit_tracking)
				die("Cannot setup tracking information; starting point is not a branch.");
			else
				real_ref = NULL;
		}
=======
		/* Unique completion -- good, only if it is a real branch */
		if (explicit_tracking &&
		    prefixcmp(real_ref, "refs/heads/") &&
		    prefixcmp(real_ref, "refs/remotes/"))
			die("Cannot setup tracking information; starting point is not a branch.");
>>>>>>> @{-1}

Don't we need something similar here?

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v2] branch/checkout --track: Ensure that upstream branch is indeed a branch
  2011-02-16 22:00     ` Junio C Hamano
@ 2011-02-16 23:12       ` Johan Herland
  2011-02-18  0:45         ` Martin von Zweigbergk
  0 siblings, 1 reply; 7+ messages in thread
From: Johan Herland @ 2011-02-16 23:12 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

When creating a new branch using the --track option, we must make sure that
we don't try to set an upstream that does not make sense to follow (using
'git pull') or update (using 'git push'). The current code checks against
using HEAD as upstream (since tracking a symref doesn't make sense). However,
tracking a tag doesn't make sense either. Indeed, tracking _any_ ref that is
not a (local or remote) branch doesn't make sense, and should be disallowed.

This patch achieves this by checking that the ref we're trying to --track
resides within refs/heads/* or refs/remotes/*. This new check replaces the
previous check against HEAD.

A couple of testcases are also added, verifying that we cannot create
branches with tags as upstreams.

Finally, some selftests relying on using a non-branch as an upstream have
been reworked or removed:

- t6040: Reverse the meaning of two tests that depend on the ability to
use (lightweight and annotated) tags as upstreams. These two tests were
originally added in commits 1be570f and 57ffc5f, and this patch reverts the
intention of those two commits.

- t7201: Remove part of a test (introduced in 9188ed8) relying on a
non-branch as upstream.

Signed-off-by: Johan Herland <johan@herland.net>
---

On Wednesday 16 February 2011, Junio C Hamano wrote:
> Thomas's "HEAD" patch 84c1a89 (branch: do not attempt to track HEAD
> implicitly, 2010-12-14) has an extra action to reset real_ref to NULL
> when not asking for "explicit_tracking" in the same codepath.
> 
> ...
> 
> Don't we need something similar here?

Indeed. Here is v2, rebased on top of 84c1a89.

...Johan

 branch.c                 |    5 +++--
 t/t3200-branch.sh        |    5 +++++
 t/t6040-tracking-info.sh |   16 ++++++++--------
 t/t7201-co.sh            |   16 +++++++++-------
 4 files changed, 25 insertions(+), 17 deletions(-)

diff --git a/branch.c b/branch.c
index 19310e4..da5c03e 100644
--- a/branch.c
+++ b/branch.c
@@ -175,8 +175,9 @@ void create_branch(const char *head,
 			die("Cannot setup tracking information; starting point is not a branch.");
 		break;
 	case 1:
-		/* Unique completion -- good, only if it is a real ref */
-		if (!strcmp(real_ref, "HEAD")) {
+		/* Unique completion -- good, only if it is a real branch */
+		if (prefixcmp(real_ref, "refs/heads/") &&
+		    prefixcmp(real_ref, "refs/remotes/")) {
 			if (explicit_tracking)
 				die("Cannot setup tracking information; starting point is not a branch.");
 			else
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index dce90de..55af032 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -212,6 +212,11 @@ test_expect_success \
     'branch from non-branch HEAD w/--track causes failure' \
     'test_must_fail git branch --track my10 HEAD^'
 
+test_expect_success \
+    'branch from tag w/--track causes failure' \
+    'git tag foobar &&
+     test_must_fail git branch --track my11 foobar'
+
 # Keep this test last, as it changes the current branch
 cat >expect <<EOF
 0000000000000000000000000000000000000000 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 
1117150200 +0000	branch: Created from master
diff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh
index 1785e17..10bf3de 100755
--- a/t/t6040-tracking-info.sh
+++ b/t/t6040-tracking-info.sh
@@ -74,20 +74,20 @@ test_expect_success 'status' '
 	grep "have 1 and 1 different" actual
 '
 
-test_expect_success 'status when tracking lightweight tags' '
+test_expect_success 'fail to track lightweight tags' '
 	git checkout master &&
 	git tag light &&
-	git branch --track lighttrack light >actual &&
-	grep "set up to track" actual &&
-	git checkout lighttrack
+	test_must_fail git branch --track lighttrack light >actual &&
+	test_must_fail grep "set up to track" actual &&
+	test_must_fail git checkout lighttrack
 '
 
-test_expect_success 'status when tracking annotated tags' '
+test_expect_success 'fail to track annotated tags' '
 	git checkout master &&
 	git tag -m heavy heavy &&
-	git branch --track heavytrack heavy >actual &&
-	grep "set up to track" actual &&
-	git checkout heavytrack
+	test_must_fail git branch --track heavytrack heavy >actual &&
+	test_must_fail grep "set up to track" actual &&
+	test_must_fail git checkout heavytrack
 '
 
 test_expect_success 'setup tracking with branch --set-upstream on existing branch' '
diff --git a/t/t7201-co.sh b/t/t7201-co.sh
index 1337fa5..0c002ab 100755
--- a/t/t7201-co.sh
+++ b/t/t7201-co.sh
@@ -408,6 +408,15 @@ test_expect_success 'checkout w/--track from non-branch HEAD fails' '
     test "z$(git rev-parse master^0)" = "z$(git rev-parse HEAD)"
 '
 
+test_expect_success 'checkout w/--track from tag fails' '
+    git checkout master^0 &&
+    test_must_fail git symbolic-ref HEAD &&
+    test_must_fail git checkout --track -b track frotz &&
+    test_must_fail git rev-parse --verify track &&
+    test_must_fail git symbolic-ref HEAD &&
+    test "z$(git rev-parse master^0)" = "z$(git rev-parse HEAD)"
+'
+
 test_expect_success 'detach a symbolic link HEAD' '
     git checkout master &&
     git config --bool core.prefersymlinkrefs yes &&
@@ -423,7 +432,6 @@ test_expect_success 'detach a symbolic link HEAD' '
 test_expect_success \
     'checkout with --track fakes a sensible -b <name>' '
     git update-ref refs/remotes/origin/koala/bear renamer &&
-    git update-ref refs/new/koala/bear renamer &&
 
     git checkout --track origin/koala/bear &&
     test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
@@ -439,12 +447,6 @@ test_expect_success \
 
     git checkout --track remotes/origin/koala/bear &&
     test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
-    test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)" &&
-
-    git checkout master && git branch -D koala/bear &&
-
-    git checkout --track refs/new/koala/bear &&
-    test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
     test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)"
 '
 
-- 
1.7.4

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH v2] branch/checkout --track: Ensure that upstream branch is indeed a branch
  2011-02-16 23:12       ` [PATCH v2] " Johan Herland
@ 2011-02-18  0:45         ` Martin von Zweigbergk
  2011-02-18  4:32           ` Junio C Hamano
  0 siblings, 1 reply; 7+ messages in thread
From: Martin von Zweigbergk @ 2011-02-18  0:45 UTC (permalink / raw)
  To: Johan Herland; +Cc: Junio C Hamano, git

On Thu, 17 Feb 2011, Johan Herland wrote:

> When creating a new branch using the --track option, we must make sure that
> we don't try to set an upstream that does not make sense to follow (using
> 'git pull') or update (using 'git push'). The current code checks against
> using HEAD as upstream (since tracking a symref doesn't make sense). However,
> tracking a tag doesn't make sense either. Indeed, tracking _any_ ref that is
> not a (local or remote) branch doesn't make sense, and should be disallowed.
> 
> This patch achieves this by checking that the ref we're trying to --track
> resides within refs/heads/* or refs/remotes/*. This new check replaces the
> previous check against HEAD.

In some workflows (e.g. Linux kernel, IIRC), it is recommended to base
your work on a tag. Is it worth considering that people might use a
tag as upstream for such cases or would that be considered abuse of
the "upstream" concept? It could make sense to set an upstream to
point to a tag for reference and to be able to use e.g. 'rebase -i
@{u}', 'git log @{u}..' and similar.


/Martin

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v2] branch/checkout --track: Ensure that upstream branch is indeed a branch
  2011-02-18  0:45         ` Martin von Zweigbergk
@ 2011-02-18  4:32           ` Junio C Hamano
  0 siblings, 0 replies; 7+ messages in thread
From: Junio C Hamano @ 2011-02-18  4:32 UTC (permalink / raw)
  To: Martin von Zweigbergk; +Cc: Johan Herland, git

Martin von Zweigbergk <martin.von.zweigbergk@gmail.com> writes:

> In some workflows (e.g. Linux kernel, IIRC), it is recommended to base
> your work on a tag.

But the thing is, "base your work on some known point" is a rule invented
exactly to discourage casual and frequent rebasing.

If you started your work on v2.6.36 and need to rebase to a more recent
version, you won't be using "rebase @{upstream}" notation _anyway_, as the
old base you forked your work from that you would refer to as @{upstream}
will not be moving.  You will instead rebasing on top of a _different_
commit, perhaps v2.6.38 or something.

So the workflow would look more like: 

	$ git checkout -b frotz-2.6.36 v2.6.36
        ... develop "frotz" feature on top of 2.6.36

        ... time passes ...

	$ git checkout -b frotz-2.6.38 frotz-2.6.36
        $ git rebase --onto v2.6.38 v2.6.36
	... inspect the result and it looks good.
        ... if  you don't want frotz in 2.6.36 then...
        $ git branch -D frotz-2.6.36

There is not much point in using @{upstream} when your branch management
is as disciplined as that recommended practice you cited.

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2011-02-18  4:32 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-02-15 17:52 checkout/branch needs some extra safety around the --track option Johan Herland
2011-02-15 20:04 ` Junio C Hamano
2011-02-16 10:46   ` [PATCH] branch/checkout --track: Ensure that upstream branch is indeed a branch Johan Herland
2011-02-16 22:00     ` Junio C Hamano
2011-02-16 23:12       ` [PATCH v2] " Johan Herland
2011-02-18  0:45         ` Martin von Zweigbergk
2011-02-18  4:32           ` Junio C Hamano

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).