@@ -10,8 +10,11 @@ static char* repo2_path;
1010
1111static const char * REPO1_REFNAME = "refs/heads/main" ;
1212static const char * REPO2_REFNAME = "refs/remotes/repo1/main" ;
13+ static const char * REPO1_UNDERSCORE_REFNAME = "refs/heads/_branch" ;
14+ static const char * REPO2_UNDERSCORE_REFNAME = "refs/remotes/repo1/_branch" ;
1315static char * FORCE_FETCHSPEC = "+refs/heads/main:refs/remotes/repo1/main" ;
1416static char * NON_FORCE_FETCHSPEC = "refs/heads/main:refs/remotes/repo1/main" ;
17+ static char * NEGATIVE_SPEC = "^refs/heads/_*" ;
1518
1619void test_remote_fetch__initialize (void ) {
1720 git_config * c ;
@@ -170,3 +173,61 @@ void test_remote_fetch__do_update_refs_if_not_descendant_and_force(void) {
170173
171174 git_reference_free (ref );
172175}
176+
177+ /**
178+ * This checks that negative refspecs are respected when fetching. We create a
179+ * repository with a '_' prefixed reference. A second repository is configured
180+ * with a negative refspec to ignore any refs prefixed with '_' and fetch the
181+ * first repository into the second.
182+ *
183+ * @param commit1id A pointer to an OID which will be populated with the first
184+ * commit.
185+ */
186+ static void do_fetch_repo_with_ref_matching_negative_refspec (git_oid * commit1id ) {
187+ /* create a commit in repo 1 and a reference to it with '_' prefix */
188+ {
189+ git_oid empty_tree_id ;
190+ git_tree * empty_tree ;
191+ git_signature * sig ;
192+ git_treebuilder * tb ;
193+ cl_git_pass (git_treebuilder_new (& tb , repo1 , NULL ));
194+ cl_git_pass (git_treebuilder_write (& empty_tree_id , tb ));
195+ cl_git_pass (git_tree_lookup (& empty_tree , repo1 , & empty_tree_id ));
196+ cl_git_pass (git_signature_default (& sig , repo1 ));
197+ cl_git_pass (git_commit_create (commit1id , repo1 , REPO1_UNDERSCORE_REFNAME , sig ,
198+ sig , NULL , "one" , empty_tree , 0 , NULL ));
199+
200+ git_tree_free (empty_tree );
201+ git_signature_free (sig );
202+ git_treebuilder_free (tb );
203+ }
204+
205+ /* fetch the remote with negative refspec for references prefixed with '_' */
206+ {
207+ char * refspec_strs = { NEGATIVE_SPEC };
208+ git_strarray refspecs = { & refspec_strs , 1 };
209+
210+ git_remote * remote ;
211+
212+ cl_git_pass (git_remote_create_anonymous (& remote , repo2 ,
213+ git_repository_path (repo1 )));
214+ cl_git_pass (git_remote_fetch (remote , & refspecs , NULL , "some message" ));
215+
216+ git_remote_free (remote );
217+ }
218+ }
219+
220+ void test_remote_fetch__skip_negative_refspec_match (void ) {
221+ git_oid commit1id ;
222+ git_reference * ref1 ;
223+ git_reference * ref2 ;
224+
225+ do_fetch_repo_with_ref_matching_negative_refspec (& commit1id );
226+
227+ /* assert that the reference in exists in repo1 but not in repo2 */
228+ cl_git_pass (git_reference_lookup (& ref1 , repo1 , REPO1_UNDERSCORE_REFNAME ));
229+ cl_assert_equal_b (git_reference_lookup (& ref2 , repo2 , REPO2_UNDERSCORE_REFNAME ), GIT_ENOTFOUND );
230+
231+ git_reference_free (ref1 );
232+ git_reference_free (ref2 );
233+ }
0 commit comments