From 2004658b19bf781d446e14e3237f519e80ab0297 Mon Sep 17 00:00:00 2001 From: Michael Haggerty Date: Wed, 23 Oct 2013 17:50:34 +0200 Subject: t5510: use the correct tag name in test Fix an apparent copy-paste error: A few lines earlier, a tag "refs/tags/sometag" is created. Check for the (non-)existence of that tag, not "somebranch", which is otherwise never mentioned in the script. Signed-off-by: Michael Haggerty Signed-off-by: Junio C Hamano --- t/t5510-fetch.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 't') diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index 1f0f8e6827..c5e5dfc818 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -121,7 +121,7 @@ test_expect_success 'fetch --prune --tags does not delete the remote-tracking br git fetch --prune --tags origin && git rev-parse origin/master && - test_must_fail git rev-parse somebranch + test_must_fail git rev-parse sometag ' test_expect_success 'fetch --prune --tags with branch does not delete other remote-tracking branches' ' -- cgit v1.2.1 From d0d06e892a1a7bc6a1dfd76374da09f0170cae2c Mon Sep 17 00:00:00 2001 From: Michael Haggerty Date: Wed, 23 Oct 2013 17:50:35 +0200 Subject: t5510: prepare test refs more straightforwardly "git fetch" was being used with contrived refspecs to create tags and remote-tracking branches in test repositories in preparation for the actual tests. This is obscure and also makes one wonder whether this is indeed just preparation or whether some side-effect of "git fetch" is being tested. So use the more straightforward commands "git tag" / "git update-ref" when preparing branches in test repositories. Signed-off-by: Michael Haggerty Signed-off-by: Junio C Hamano --- t/t5510-fetch.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 't') diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index c5e5dfc818..08d8dbb917 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -88,7 +88,7 @@ test_expect_success 'fetch --prune on its own works as expected' ' cd "$D" && git clone . prune && cd prune && - git fetch origin refs/heads/master:refs/remotes/origin/extrabranch && + git update-ref refs/remotes/origin/extrabranch master && git fetch --prune origin && test_must_fail git rev-parse origin/extrabranch @@ -98,7 +98,7 @@ test_expect_success 'fetch --prune with a branch name keeps branches' ' cd "$D" && git clone . prune-branch && cd prune-branch && - git fetch origin refs/heads/master:refs/remotes/origin/extrabranch && + git update-ref refs/remotes/origin/extrabranch master && git fetch --prune origin master && git rev-parse origin/extrabranch @@ -117,7 +117,7 @@ test_expect_success 'fetch --prune --tags does not delete the remote-tracking br cd "$D" && git clone . prune-tags && cd prune-tags && - git fetch origin refs/heads/master:refs/tags/sometag && + git tag sometag master && git fetch --prune --tags origin && git rev-parse origin/master && @@ -128,7 +128,7 @@ test_expect_success 'fetch --prune --tags with branch does not delete other remo cd "$D" && git clone . prune-tags-branch && cd prune-tags-branch && - git fetch origin refs/heads/master:refs/remotes/origin/extrabranch && + git update-ref refs/remotes/origin/extrabranch master && git fetch --prune --tags origin master && git rev-parse origin/extrabranch -- cgit v1.2.1 From 68a304d5fed6657e452e8c1571fe9ca93d0a272a Mon Sep 17 00:00:00 2001 From: Michael Haggerty Date: Wed, 23 Oct 2013 17:50:36 +0200 Subject: t5510: check that "git fetch --prune --tags" does not prune branches "git fetch --prune --tags" is currently interpreted as follows: * "--tags" is equivalent to specifying a refspec "refs/tags/*:refs/tags/*", and supersedes any default refspecs configured via remote.$REMOTE.fetch. * "--prune" only operates on the refspecs being fetched. Therefore, "git fetch --prune --tags" prunes tags in refs/tags/* but does not fetch or prune other references. The fact that this command does not prune references outside of refs/tags/* was previously untested. So add a test that verifies the status quo. However, the status quo is surprising, so it will be changed later in this patch series. Signed-off-by: Michael Haggerty Signed-off-by: Junio C Hamano --- t/t5510-fetch.sh | 4 ++++ 1 file changed, 4 insertions(+) (limited to 't') diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index 08d8dbb917..8328be1347 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -118,9 +118,13 @@ test_expect_success 'fetch --prune --tags does not delete the remote-tracking br git clone . prune-tags && cd prune-tags && git tag sometag master && + # Create what looks like a remote-tracking branch from an earlier + # fetch that has since been deleted from the remote: + git update-ref refs/remotes/origin/fake-remote master && git fetch --prune --tags origin && git rev-parse origin/master && + git rev-parse origin/fake-remote && test_must_fail git rev-parse sometag ' -- cgit v1.2.1 From c5a84e92a2fe9e8748e32341c344d7a6c0f52a50 Mon Sep 17 00:00:00 2001 From: Michael Haggerty Date: Wed, 30 Oct 2013 06:32:59 +0100 Subject: fetch --tags: fetch tags *in addition to* other stuff Previously, fetch's "--tags" option was considered equivalent to specifying the refspec "refs/tags/*:refs/tags/*" on the command line; in particular, it caused the remote..refspec configuration to be ignored. But it is not very useful to fetch tags without also fetching other references, whereas it *is* quite useful to be able to fetch tags *in addition to* other references. So change the semantics of this option to do the latter. If a user wants to fetch *only* tags, then it is still possible to specifying an explicit refspec: git fetch 'refs/tags/*:refs/tags/*' Please note that the documentation prior to 1.8.0.3 was ambiguous about this aspect of "fetch --tags" behavior. Commit f0cb2f137c 2012-12-14 fetch --tags: clarify documentation made the documentation match the old behavior. This commit changes the documentation to match the new behavior. Signed-off-by: Michael Haggerty Signed-off-by: Junio C Hamano --- t/t5510-fetch.sh | 22 +++++++++++++++++++--- t/t5515/fetch.br-unconfig_--tags_.._.git | 1 + t/t5515/fetch.master_--tags_.._.git | 1 + t/t5525-fetch-tagopt.sh | 23 ++++++++++++++++++----- 4 files changed, 39 insertions(+), 8 deletions(-) (limited to 't') diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index 8328be1347..02e5901ab1 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -113,7 +113,7 @@ test_expect_success 'fetch --prune with a namespace keeps other namespaces' ' git rev-parse origin/master ' -test_expect_success 'fetch --prune --tags does not delete the remote-tracking branches' ' +test_expect_success 'fetch --prune --tags prunes tags and branches' ' cd "$D" && git clone . prune-tags && cd prune-tags && @@ -124,7 +124,7 @@ test_expect_success 'fetch --prune --tags does not delete the remote-tracking br git fetch --prune --tags origin && git rev-parse origin/master && - git rev-parse origin/fake-remote && + test_must_fail git rev-parse origin/fake-remote && test_must_fail git rev-parse sometag ' @@ -132,10 +132,26 @@ test_expect_success 'fetch --prune --tags with branch does not delete other remo cd "$D" && git clone . prune-tags-branch && cd prune-tags-branch && + git tag sometag master && git update-ref refs/remotes/origin/extrabranch master && git fetch --prune --tags origin master && - git rev-parse origin/extrabranch + git rev-parse origin/extrabranch && + test_must_fail git rev-parse sometag +' + +test_expect_success 'fetch --prune --tags with refspec prunes based on refspec' ' + cd "$D" && + git clone . prune-tags-refspec && + cd prune-tags-refspec && + git tag sometag master && + git update-ref refs/remotes/origin/foo/otherbranch master && + git update-ref refs/remotes/origin/extrabranch master && + + git fetch --prune --tags origin refs/heads/foo/*:refs/remotes/origin/foo/* && + test_must_fail git rev-parse refs/remotes/origin/foo/otherbranch && + git rev-parse origin/extrabranch && + test_must_fail git rev-parse sometag ' test_expect_success 'fetch tags when there is no tags' ' diff --git a/t/t5515/fetch.br-unconfig_--tags_.._.git b/t/t5515/fetch.br-unconfig_--tags_.._.git index 1669cc4af0..0f70f66c70 100644 --- a/t/t5515/fetch.br-unconfig_--tags_.._.git +++ b/t/t5515/fetch.br-unconfig_--tags_.._.git @@ -1,4 +1,5 @@ # br-unconfig --tags ../.git +0567da4d5edd2ff4bb292a465ba9e64dcad9536b ../ 6c9dec2b923228c9ff994c6cfe4ae16c12408dc5 not-for-merge tag 'tag-master' of ../ 8e32a6d901327a23ef831511badce7bf3bf46689 not-for-merge tag 'tag-one' of ../ 22feea448b023a2d864ef94b013735af34d238ba not-for-merge tag 'tag-one-tree' of ../ diff --git a/t/t5515/fetch.master_--tags_.._.git b/t/t5515/fetch.master_--tags_.._.git index 8a7493537b..ab473a6e1f 100644 --- a/t/t5515/fetch.master_--tags_.._.git +++ b/t/t5515/fetch.master_--tags_.._.git @@ -1,4 +1,5 @@ # master --tags ../.git +0567da4d5edd2ff4bb292a465ba9e64dcad9536b ../ 6c9dec2b923228c9ff994c6cfe4ae16c12408dc5 not-for-merge tag 'tag-master' of ../ 8e32a6d901327a23ef831511badce7bf3bf46689 not-for-merge tag 'tag-one' of ../ 22feea448b023a2d864ef94b013735af34d238ba not-for-merge tag 'tag-one-tree' of ../ diff --git a/t/t5525-fetch-tagopt.sh b/t/t5525-fetch-tagopt.sh index 4fbf7a120f..45815f7378 100755 --- a/t/t5525-fetch-tagopt.sh +++ b/t/t5525-fetch-tagopt.sh @@ -8,7 +8,8 @@ setup_clone () { git clone --mirror . $1 && git remote add remote_$1 $1 && (cd $1 && - git tag tag_$1) + git tag tag_$1 && + git branch branch_$1) } test_expect_success setup ' @@ -21,21 +22,33 @@ test_expect_success setup ' test_expect_success "fetch with tagopt=--no-tags does not get tag" ' git fetch remote_one && - test_must_fail git show-ref tag_one + test_must_fail git show-ref tag_one && + git show-ref remote_one/branch_one ' test_expect_success "fetch --tags with tagopt=--no-tags gets tag" ' + ( + cd one && + git branch second_branch_one + ) && git fetch --tags remote_one && - git show-ref tag_one + git show-ref tag_one && + git show-ref remote_one/second_branch_one ' test_expect_success "fetch --no-tags with tagopt=--tags does not get tag" ' git fetch --no-tags remote_two && - test_must_fail git show-ref tag_two + test_must_fail git show-ref tag_two && + git show-ref remote_two/branch_two ' test_expect_success "fetch with tagopt=--tags gets tag" ' + ( + cd two && + git branch second_branch_two + ) && git fetch remote_two && - git show-ref tag_two + git show-ref tag_two && + git show-ref remote_two/second_branch_two ' test_done -- cgit v1.2.1 From 0838bf47b3b37f6ff13b8de183316483958bf3bb Mon Sep 17 00:00:00 2001 From: Michael Haggerty Date: Wed, 30 Oct 2013 06:33:00 +0100 Subject: fetch --prune: prune only based on explicit refspecs The old behavior of "fetch --prune" was to prune whatever was being fetched. In particular, "fetch --prune --tags" caused tags not only to be fetched, but also to be pruned. This is inappropriate because there is only one tags namespace that is shared among the local repository and all remotes. Therefore, if the user defines a local tag and then runs "git fetch --prune --tags", then the local tag is deleted. Moreover, "--prune" and "--tags" can also be configured via fetch.prune / remote..prune and remote..tagopt, making it even less obvious that an invocation of "git fetch" could result in tag lossage. Since the command "git remote update" invokes "git fetch", it had the same problem. The command "git remote prune", on the other hand, disregarded the setting of remote..tagopt, and so its behavior was inconsistent with that of the other commands. So the old behavior made it too easy to lose tags. To fix this problem, change "fetch --prune" to prune references based only on refspecs specified explicitly by the user, either on the command line or via remote..fetch. Thus, tags are no longer made subject to pruning by the --tags option or the remote..tagopt setting. However, tags *are* still subject to pruning if they are fetched as part of a refspec, and that is good. For example: * On the command line, git fetch --prune 'refs/tags/*:refs/tags/*' causes tags, and only tags, to be fetched and pruned, and is therefore a simple way for the user to get the equivalent of the old behavior of "--prune --tag". * For a remote that was configured with the "--mirror" option, the configuration is set to include [remote "name"] fetch = +refs/*:refs/* , which causes tags to be subject to pruning along with all other references. This is the behavior that will typically be desired for a mirror. Signed-off-by: Michael Haggerty Signed-off-by: Junio C Hamano --- t/t5510-fetch.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 't') diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index 02e5901ab1..5d4581dac8 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -113,7 +113,7 @@ test_expect_success 'fetch --prune with a namespace keeps other namespaces' ' git rev-parse origin/master ' -test_expect_success 'fetch --prune --tags prunes tags and branches' ' +test_expect_success 'fetch --prune --tags prunes branches but not tags' ' cd "$D" && git clone . prune-tags && cd prune-tags && @@ -125,10 +125,10 @@ test_expect_success 'fetch --prune --tags prunes tags and branches' ' git fetch --prune --tags origin && git rev-parse origin/master && test_must_fail git rev-parse origin/fake-remote && - test_must_fail git rev-parse sometag + git rev-parse sometag ' -test_expect_success 'fetch --prune --tags with branch does not delete other remote-tracking branches' ' +test_expect_success 'fetch --prune --tags with branch does not prune other things' ' cd "$D" && git clone . prune-tags-branch && cd prune-tags-branch && @@ -137,7 +137,7 @@ test_expect_success 'fetch --prune --tags with branch does not delete other remo git fetch --prune --tags origin master && git rev-parse origin/extrabranch && - test_must_fail git rev-parse sometag + git rev-parse sometag ' test_expect_success 'fetch --prune --tags with refspec prunes based on refspec' ' @@ -151,7 +151,7 @@ test_expect_success 'fetch --prune --tags with refspec prunes based on refspec' git fetch --prune --tags origin refs/heads/foo/*:refs/remotes/origin/foo/* && test_must_fail git rev-parse refs/remotes/origin/foo/otherbranch && git rev-parse origin/extrabranch && - test_must_fail git rev-parse sometag + git rev-parse sometag ' test_expect_success 'fetch tags when there is no tags' ' -- cgit v1.2.1 From 2071e05ed27df847e300b51aca661a34a765aea3 Mon Sep 17 00:00:00 2001 From: Michael Haggerty Date: Wed, 30 Oct 2013 06:33:08 +0100 Subject: t5536: new test of refspec conflicts when fetching Add some tests that "git fetch" handles refspec conflicts (i.e., when the same local reference should be updated from two different remote references) correctly. There is a small bug when updating references opportunistically, namely that an explicit user wish like git fetch origin \ refs/heads/branch1:refs/remotes/origin/branch2 \ refs/heads/branch2:refs/remotes/origin/branch1 should override a configured refspec like +refs/heads/*:refs/remotes/origin/* The current code incorrectly treats this as a fatal error. In a few commits we will improve the error messages for refspec conflicts in general and also turn this buggy fatal error into a warning. Signed-off-by: Michael Haggerty Signed-off-by: Junio C Hamano --- t/t5536-fetch-conflicts.sh | 96 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100755 t/t5536-fetch-conflicts.sh (limited to 't') diff --git a/t/t5536-fetch-conflicts.sh b/t/t5536-fetch-conflicts.sh new file mode 100755 index 0000000000..679c53e044 --- /dev/null +++ b/t/t5536-fetch-conflicts.sh @@ -0,0 +1,96 @@ +#!/bin/sh + +test_description='fetch handles conflicting refspecs correctly' + +. ./test-lib.sh + +D=$(pwd) + +setup_repository () { + git init "$1" && ( + cd "$1" && + git config remote.origin.url "$D" && + shift && + for refspec in "$@" + do + git config --add remote.origin.fetch "$refspec" + done + ) +} + +verify_stderr () { + cat >expected && + # We're not interested in the error + # "fatal: The remote end hung up unexpectedly": + grep -v "hung up" actual && + test_cmp expected actual +} + +test_expect_success 'setup' ' + git commit --allow-empty -m "Initial" && + git branch branch1 && + git tag tag1 && + git commit --allow-empty -m "First" && + git branch branch2 && + git tag tag2 +' + +test_expect_success 'fetch with no conflict' ' + setup_repository ok "+refs/heads/*:refs/remotes/origin/*" && ( + cd ok && + git fetch origin + ) +' + +test_expect_success 'fetch conflict: config vs. config' ' + setup_repository ccc \ + "+refs/heads/branch1:refs/remotes/origin/branch1" \ + "+refs/heads/branch2:refs/remotes/origin/branch1" && ( + cd ccc && + test_must_fail git fetch origin 2>error && + verify_stderr <<-\EOF + fatal: refs/remotes/origin/branch1 tracks both refs/heads/branch1 and refs/heads/branch2 + EOF + ) +' + +test_expect_success 'fetch duplicate: config vs. config' ' + setup_repository dcc \ + "+refs/heads/*:refs/remotes/origin/*" \ + "+refs/heads/branch1:refs/remotes/origin/branch1" && ( + cd dcc && + git fetch origin + ) +' + +test_expect_success 'fetch conflict: arg overrides config' ' + setup_repository aoc \ + "+refs/heads/*:refs/remotes/origin/*" && ( + cd aoc && + git fetch origin refs/heads/branch2:refs/remotes/origin/branch1 + ) +' + +test_expect_success 'fetch conflict: arg vs. arg' ' + setup_repository caa && ( + cd caa && + test_must_fail git fetch origin \ + refs/heads/*:refs/remotes/origin/* \ + refs/heads/branch2:refs/remotes/origin/branch1 2>error && + verify_stderr <<-\EOF + fatal: refs/remotes/origin/branch1 tracks both refs/heads/branch1 and refs/heads/branch2 + EOF + ) +' + +test_expect_failure 'fetch conflict: criss-cross args' ' + setup_repository xaa \ + "+refs/heads/*:refs/remotes/origin/*" && ( + cd xaa && + git fetch origin \ + refs/heads/branch1:refs/remotes/origin/branch2 \ + refs/heads/branch2:refs/remotes/origin/branch1 + ) +' + +test_done -- cgit v1.2.1 From f096e6e826678c29e4bfde4d9d1ae1df79074ce3 Mon Sep 17 00:00:00 2001 From: Michael Haggerty Date: Wed, 30 Oct 2013 06:33:12 +0100 Subject: fetch: improve the error messages emitted for conflicting refspecs If we find two refspecs that want to update the same local reference, emit an error message that is more informative based on whether one of the conflicting refspecs is an opportunistic update during a fetch with explicit command-line refspecs. And especially, do not die if an opportunistic reference update conflicts with an express wish of the user; rather, just emit a warning and skip the opportunistic reference update. Signed-off-by: Michael Haggerty Signed-off-by: Junio C Hamano --- t/t5536-fetch-conflicts.sh | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 't') diff --git a/t/t5536-fetch-conflicts.sh b/t/t5536-fetch-conflicts.sh index 679c53e044..6c5d3a4ce0 100755 --- a/t/t5536-fetch-conflicts.sh +++ b/t/t5536-fetch-conflicts.sh @@ -22,7 +22,7 @@ verify_stderr () { cat >expected && # We're not interested in the error # "fatal: The remote end hung up unexpectedly": - grep -v "hung up" actual && + grep -E '^(fatal|warning):' actual | sort && test_cmp expected actual } @@ -49,7 +49,7 @@ test_expect_success 'fetch conflict: config vs. config' ' cd ccc && test_must_fail git fetch origin 2>error && verify_stderr <<-\EOF - fatal: refs/remotes/origin/branch1 tracks both refs/heads/branch1 and refs/heads/branch2 + fatal: Cannot fetch both refs/heads/branch1 and refs/heads/branch2 to refs/remotes/origin/branch1 EOF ) ' @@ -78,18 +78,22 @@ test_expect_success 'fetch conflict: arg vs. arg' ' refs/heads/*:refs/remotes/origin/* \ refs/heads/branch2:refs/remotes/origin/branch1 2>error && verify_stderr <<-\EOF - fatal: refs/remotes/origin/branch1 tracks both refs/heads/branch1 and refs/heads/branch2 + fatal: Cannot fetch both refs/heads/branch1 and refs/heads/branch2 to refs/remotes/origin/branch1 EOF ) ' -test_expect_failure 'fetch conflict: criss-cross args' ' +test_expect_success 'fetch conflict: criss-cross args' ' setup_repository xaa \ "+refs/heads/*:refs/remotes/origin/*" && ( cd xaa && git fetch origin \ refs/heads/branch1:refs/remotes/origin/branch2 \ - refs/heads/branch2:refs/remotes/origin/branch1 + refs/heads/branch2:refs/remotes/origin/branch1 2>error && + verify_stderr <<-\EOF + warning: refs/remotes/origin/branch1 usually tracks refs/heads/branch1, not refs/heads/branch2 + warning: refs/remotes/origin/branch2 usually tracks refs/heads/branch2, not refs/heads/branch1 + EOF ) ' -- cgit v1.2.1