1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 package org.eclipse.jgit.internal.storage.file;
45
46 import static org.eclipse.jgit.lib.Constants.HEAD;
47 import static org.eclipse.jgit.lib.Constants.R_HEADS;
48 import static org.eclipse.jgit.lib.Constants.R_TAGS;
49 import static org.eclipse.jgit.lib.Ref.Storage.LOOSE;
50 import static org.eclipse.jgit.lib.Ref.Storage.NEW;
51 import static org.junit.Assert.assertEquals;
52 import static org.junit.Assert.assertFalse;
53 import static org.junit.Assert.assertNotNull;
54 import static org.junit.Assert.assertNotSame;
55 import static org.junit.Assert.assertNull;
56 import static org.junit.Assert.assertSame;
57 import static org.junit.Assert.assertTrue;
58 import static org.junit.Assert.fail;
59
60 import java.io.File;
61 import java.io.IOException;
62 import java.util.ArrayList;
63 import java.util.Arrays;
64 import java.util.Map;
65 import java.util.concurrent.atomic.AtomicInteger;
66 import java.util.concurrent.atomic.AtomicReference;
67
68 import org.eclipse.jgit.errors.LockFailedException;
69 import org.eclipse.jgit.events.ListenerHandle;
70 import org.eclipse.jgit.events.RefsChangedEvent;
71 import org.eclipse.jgit.events.RefsChangedListener;
72 import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase;
73 import org.eclipse.jgit.junit.TestRepository;
74 import org.eclipse.jgit.lib.AnyObjectId;
75 import org.eclipse.jgit.lib.Ref;
76 import org.eclipse.jgit.lib.Ref.Storage;
77 import org.eclipse.jgit.lib.RefDatabase;
78 import org.eclipse.jgit.lib.Repository;
79 import org.eclipse.jgit.revwalk.RevCommit;
80 import org.eclipse.jgit.revwalk.RevTag;
81 import org.junit.Before;
82 import org.junit.Test;
83
84 @SuppressWarnings("boxing")
85 public class RefDirectoryTest extends LocalDiskRepositoryTestCase {
86 private Repository diskRepo;
87
88 private TestRepository<Repository> repo;
89
90 private RefDirectory refdir;
91
92 private RevCommit A;
93
94 private RevCommit B;
95
96 private RevTag v1_0;
97
98 @Override
99 @Before
100 public void setUp() throws Exception {
101 super.setUp();
102
103 diskRepo = createBareRepository();
104 refdir = (RefDirectory) diskRepo.getRefDatabase();
105
106 repo = new TestRepository<>(diskRepo);
107 A = repo.commit().create();
108 B = repo.commit(repo.getRevWalk().parseCommit(A));
109 v1_0 = repo.tag("v1_0", B);
110 repo.getRevWalk().parseBody(v1_0);
111 }
112
113 @Test
114 public void testCreate() throws IOException {
115
116 File d = diskRepo.getDirectory();
117 assertSame(diskRepo, refdir.getRepository());
118
119 assertTrue(new File(d, "refs").isDirectory());
120 assertTrue(new File(d, "logs").isDirectory());
121 assertTrue(new File(d, "logs/refs").isDirectory());
122 assertFalse(new File(d, "packed-refs").exists());
123
124 assertTrue(new File(d, "refs/heads").isDirectory());
125 assertTrue(new File(d, "refs/tags").isDirectory());
126 assertEquals(2, new File(d, "refs").list().length);
127 assertEquals(0, new File(d, "refs/heads").list().length);
128 assertEquals(0, new File(d, "refs/tags").list().length);
129
130 assertTrue(new File(d, "logs/refs/heads").isDirectory());
131 assertFalse(new File(d, "logs/HEAD").exists());
132 assertEquals(0, new File(d, "logs/refs/heads").list().length);
133
134 assertEquals("ref: refs/heads/master\n", read(new File(d, HEAD)));
135 }
136
137 @Test
138 public void testGetRefs_EmptyDatabase() throws IOException {
139 Map<String, Ref> all;
140
141 all = refdir.getRefs(RefDatabase.ALL);
142 assertTrue("no references", all.isEmpty());
143
144 all = refdir.getRefs(R_HEADS);
145 assertTrue("no references", all.isEmpty());
146
147 all = refdir.getRefs(R_TAGS);
148 assertTrue("no references", all.isEmpty());
149 }
150
151 @Test
152 public void testGetRefs_HeadOnOneBranch() throws IOException {
153 Map<String, Ref> all;
154 Ref head, master;
155
156 writeLooseRef("refs/heads/master", A);
157
158 all = refdir.getRefs(RefDatabase.ALL);
159 assertEquals(2, all.size());
160 assertTrue("has HEAD", all.containsKey(HEAD));
161 assertTrue("has master", all.containsKey("refs/heads/master"));
162
163 head = all.get(HEAD);
164 master = all.get("refs/heads/master");
165
166 assertEquals(HEAD, head.getName());
167 assertTrue(head.isSymbolic());
168 assertSame(LOOSE, head.getStorage());
169 assertSame("uses same ref as target", master, head.getTarget());
170
171 assertEquals("refs/heads/master", master.getName());
172 assertFalse(master.isSymbolic());
173 assertSame(LOOSE, master.getStorage());
174 assertEquals(A, master.getObjectId());
175 }
176
177 @Test
178 public void testGetRefs_DeatchedHead1() throws IOException {
179 Map<String, Ref> all;
180 Ref head;
181
182 writeLooseRef(HEAD, A);
183
184 all = refdir.getRefs(RefDatabase.ALL);
185 assertEquals(1, all.size());
186 assertTrue("has HEAD", all.containsKey(HEAD));
187
188 head = all.get(HEAD);
189
190 assertEquals(HEAD, head.getName());
191 assertFalse(head.isSymbolic());
192 assertSame(LOOSE, head.getStorage());
193 assertEquals(A, head.getObjectId());
194 }
195
196 @Test
197 public void testGetRefs_DeatchedHead2() throws IOException {
198 Map<String, Ref> all;
199 Ref head, master;
200
201 writeLooseRef(HEAD, A);
202 writeLooseRef("refs/heads/master", B);
203
204 all = refdir.getRefs(RefDatabase.ALL);
205 assertEquals(2, all.size());
206
207 head = all.get(HEAD);
208 master = all.get("refs/heads/master");
209
210 assertEquals(HEAD, head.getName());
211 assertFalse(head.isSymbolic());
212 assertSame(LOOSE, head.getStorage());
213 assertEquals(A, head.getObjectId());
214
215 assertEquals("refs/heads/master", master.getName());
216 assertFalse(master.isSymbolic());
217 assertSame(LOOSE, master.getStorage());
218 assertEquals(B, master.getObjectId());
219 }
220
221 @Test
222 public void testGetRefs_DeeplyNestedBranch() throws IOException {
223 String name = "refs/heads/a/b/c/d/e/f/g/h/i/j/k";
224 Map<String, Ref> all;
225 Ref r;
226
227 writeLooseRef(name, A);
228
229 all = refdir.getRefs(RefDatabase.ALL);
230 assertEquals(1, all.size());
231
232 r = all.get(name);
233 assertEquals(name, r.getName());
234 assertFalse(r.isSymbolic());
235 assertSame(LOOSE, r.getStorage());
236 assertEquals(A, r.getObjectId());
237 }
238
239 @Test
240 public void testGetRefs_HeadBranchNotBorn() throws IOException {
241 Map<String, Ref> all;
242 Ref a, b;
243
244 writeLooseRef("refs/heads/A", A);
245 writeLooseRef("refs/heads/B", B);
246
247 all = refdir.getRefs(RefDatabase.ALL);
248 assertEquals(2, all.size());
249 assertFalse("no HEAD", all.containsKey(HEAD));
250
251 a = all.get("refs/heads/A");
252 b = all.get("refs/heads/B");
253
254 assertEquals(A, a.getObjectId());
255 assertEquals(B, b.getObjectId());
256
257 assertEquals("refs/heads/A", a.getName());
258 assertEquals("refs/heads/B", b.getName());
259 }
260
261 @Test
262 public void testGetRefs_LooseOverridesPacked() throws IOException {
263 Map<String, Ref> heads;
264 Ref a;
265
266 writeLooseRef("refs/heads/master", B);
267 writePackedRef("refs/heads/master", A);
268
269 heads = refdir.getRefs(R_HEADS);
270 assertEquals(1, heads.size());
271
272 a = heads.get("master");
273 assertEquals("refs/heads/master", a.getName());
274 assertEquals(B, a.getObjectId());
275 }
276
277 @Test
278 public void testGetRefs_IgnoresGarbageRef1() throws IOException {
279 Map<String, Ref> heads;
280 Ref a;
281
282 writeLooseRef("refs/heads/A", A);
283 write(new File(diskRepo.getDirectory(), "refs/heads/bad"), "FAIL\n");
284
285 heads = refdir.getRefs(RefDatabase.ALL);
286 assertEquals(1, heads.size());
287
288 a = heads.get("refs/heads/A");
289 assertEquals("refs/heads/A", a.getName());
290 assertEquals(A, a.getObjectId());
291 }
292
293 @Test
294 public void testGetRefs_IgnoresGarbageRef2() throws IOException {
295 Map<String, Ref> heads;
296 Ref a;
297
298 writeLooseRef("refs/heads/A", A);
299 write(new File(diskRepo.getDirectory(), "refs/heads/bad"), "");
300
301 heads = refdir.getRefs(RefDatabase.ALL);
302 assertEquals(1, heads.size());
303
304 a = heads.get("refs/heads/A");
305 assertEquals("refs/heads/A", a.getName());
306 assertEquals(A, a.getObjectId());
307 }
308
309 @Test
310 public void testGetRefs_IgnoresGarbageRef3() throws IOException {
311 Map<String, Ref> heads;
312 Ref a;
313
314 writeLooseRef("refs/heads/A", A);
315 write(new File(diskRepo.getDirectory(), "refs/heads/bad"), "\n");
316
317 heads = refdir.getRefs(RefDatabase.ALL);
318 assertEquals(1, heads.size());
319
320 a = heads.get("refs/heads/A");
321 assertEquals("refs/heads/A", a.getName());
322 assertEquals(A, a.getObjectId());
323 }
324
325 @Test
326 public void testGetRefs_IgnoresGarbageRef4() throws IOException {
327 Map<String, Ref> heads;
328 Ref a, b, c;
329
330 writeLooseRef("refs/heads/A", A);
331 writeLooseRef("refs/heads/B", B);
332 writeLooseRef("refs/heads/C", A);
333 heads = refdir.getRefs(RefDatabase.ALL);
334 assertEquals(3, heads.size());
335 assertTrue(heads.containsKey("refs/heads/A"));
336 assertTrue(heads.containsKey("refs/heads/B"));
337 assertTrue(heads.containsKey("refs/heads/C"));
338
339 writeLooseRef("refs/heads/B", "FAIL\n");
340
341 heads = refdir.getRefs(RefDatabase.ALL);
342 assertEquals(2, heads.size());
343
344 a = heads.get("refs/heads/A");
345 b = heads.get("refs/heads/B");
346 c = heads.get("refs/heads/C");
347
348 assertEquals("refs/heads/A", a.getName());
349 assertEquals(A, a.getObjectId());
350
351 assertNull("no refs/heads/B", b);
352
353 assertEquals("refs/heads/C", c.getName());
354 assertEquals(A, c.getObjectId());
355 }
356
357 @Test
358 public void testFirstExactRef_IgnoresGarbageRef() throws IOException {
359 writeLooseRef("refs/heads/A", A);
360 write(new File(diskRepo.getDirectory(), "refs/heads/bad"), "FAIL\n");
361
362 Ref a = refdir.firstExactRef("refs/heads/bad", "refs/heads/A");
363 assertEquals("refs/heads/A", a.getName());
364 assertEquals(A, a.getObjectId());
365 }
366
367 @Test
368 public void testExactRef_IgnoresGarbageRef() throws IOException {
369 writeLooseRef("refs/heads/A", A);
370 write(new File(diskRepo.getDirectory(), "refs/heads/bad"), "FAIL\n");
371
372 Map<String, Ref> refs =
373 refdir.exactRef("refs/heads/bad", "refs/heads/A");
374
375 assertNull("no refs/heads/bad", refs.get("refs/heads/bad"));
376
377 Ref a = refs.get("refs/heads/A");
378 assertEquals("refs/heads/A", a.getName());
379 assertEquals(A, a.getObjectId());
380
381 assertEquals(1, refs.size());
382 }
383
384 @Test
385 public void testGetRefs_InvalidName() throws IOException {
386 writeLooseRef("refs/heads/A", A);
387
388 assertTrue("empty refs/heads", refdir.getRefs("refs/heads").isEmpty());
389 assertTrue("empty objects", refdir.getRefs("objects").isEmpty());
390 assertTrue("empty objects/", refdir.getRefs("objects/").isEmpty());
391 }
392
393 @Test
394 public void testReadNotExistingBranchConfig() throws IOException {
395 assertNull("find branch config", refdir.getRef("config"));
396 assertNull("find branch config", refdir.getRef("refs/heads/config"));
397 }
398
399 @Test
400 public void testReadBranchConfig() throws IOException {
401 writeLooseRef("refs/heads/config", A);
402
403 assertNotNull("find branch config", refdir.getRef("config"));
404 }
405
406 @Test
407 public void testGetRefs_HeadsOnly_AllLoose() throws IOException {
408 Map<String, Ref> heads;
409 Ref a, b;
410
411 writeLooseRef("refs/heads/A", A);
412 writeLooseRef("refs/heads/B", B);
413 writeLooseRef("refs/tags/v1.0", v1_0);
414
415 heads = refdir.getRefs(R_HEADS);
416 assertEquals(2, heads.size());
417
418 a = heads.get("A");
419 b = heads.get("B");
420
421 assertEquals("refs/heads/A", a.getName());
422 assertEquals("refs/heads/B", b.getName());
423
424 assertEquals(A, a.getObjectId());
425 assertEquals(B, b.getObjectId());
426 }
427
428 @Test
429 public void testGetRefs_HeadsOnly_AllPacked1() throws IOException {
430 Map<String, Ref> heads;
431 Ref a;
432
433 deleteLooseRef(HEAD);
434 writePackedRef("refs/heads/A", A);
435
436 heads = refdir.getRefs(R_HEADS);
437 assertEquals(1, heads.size());
438
439 a = heads.get("A");
440
441 assertEquals("refs/heads/A", a.getName());
442 assertEquals(A, a.getObjectId());
443 }
444
445 @Test
446 public void testGetRefs_HeadsOnly_SymrefToPacked() throws IOException {
447 Map<String, Ref> heads;
448 Ref master, other;
449
450 writeLooseRef("refs/heads/other", "ref: refs/heads/master\n");
451 writePackedRef("refs/heads/master", A);
452
453 heads = refdir.getRefs(R_HEADS);
454 assertEquals(2, heads.size());
455
456 master = heads.get("master");
457 other = heads.get("other");
458
459 assertEquals("refs/heads/master", master.getName());
460 assertEquals(A, master.getObjectId());
461
462 assertEquals("refs/heads/other", other.getName());
463 assertEquals(A, other.getObjectId());
464 assertSame(master, other.getTarget());
465 }
466
467 @Test
468 public void testGetRefs_HeadsOnly_Mixed() throws IOException {
469 Map<String, Ref> heads;
470 Ref a, b;
471
472 writeLooseRef("refs/heads/A", A);
473 writeLooseRef("refs/heads/B", B);
474 writePackedRef("refs/tags/v1.0", v1_0);
475
476 heads = refdir.getRefs(R_HEADS);
477 assertEquals(2, heads.size());
478
479 a = heads.get("A");
480 b = heads.get("B");
481
482 assertEquals("refs/heads/A", a.getName());
483 assertEquals("refs/heads/B", b.getName());
484
485 assertEquals(A, a.getObjectId());
486 assertEquals(B, b.getObjectId());
487 }
488
489 @Test
490 public void testFirstExactRef_Mixed() throws IOException {
491 writeLooseRef("refs/heads/A", A);
492 writePackedRef("refs/tags/v1.0", v1_0);
493
494 Ref a = refdir.firstExactRef("refs/heads/A", "refs/tags/v1.0");
495 Ref one = refdir.firstExactRef("refs/tags/v1.0", "refs/heads/A");
496
497 assertEquals("refs/heads/A", a.getName());
498 assertEquals("refs/tags/v1.0", one.getName());
499
500 assertEquals(A, a.getObjectId());
501 assertEquals(v1_0, one.getObjectId());
502 }
503
504 @Test
505 public void testGetRefs_TagsOnly_AllLoose() throws IOException {
506 Map<String, Ref> tags;
507 Ref a;
508
509 writeLooseRef("refs/heads/A", A);
510 writeLooseRef("refs/tags/v1.0", v1_0);
511
512 tags = refdir.getRefs(R_TAGS);
513 assertEquals(1, tags.size());
514
515 a = tags.get("v1.0");
516
517 assertEquals("refs/tags/v1.0", a.getName());
518 assertEquals(v1_0, a.getObjectId());
519 }
520
521 @Test
522 public void testGetRefs_LooseSortedCorrectly() throws IOException {
523 Map<String, Ref> refs;
524
525 writeLooseRef("refs/heads/project1/A", A);
526 writeLooseRef("refs/heads/project1-B", B);
527
528 refs = refdir.getRefs(RefDatabase.ALL);
529 assertEquals(2, refs.size());
530 assertEquals(A, refs.get("refs/heads/project1/A").getObjectId());
531 assertEquals(B, refs.get("refs/heads/project1-B").getObjectId());
532 }
533
534 @Test
535 public void testGetRefs_LooseSorting_Bug_348834() throws IOException {
536 Map<String, Ref> refs;
537
538 writeLooseRef("refs/heads/my/a+b", A);
539 writeLooseRef("refs/heads/my/a/b/c", B);
540
541 final int[] count = new int[1];
542
543 ListenerHandle listener = Repository.getGlobalListenerList()
544 .addRefsChangedListener(new RefsChangedListener() {
545
546 @Override
547 public void onRefsChanged(RefsChangedEvent event) {
548 count[0]++;
549 }
550 });
551
552 refs = refdir.getRefs(RefDatabase.ALL);
553 refs = refdir.getRefs(RefDatabase.ALL);
554 listener.remove();
555 assertEquals(1, count[0]);
556 assertEquals(2, refs.size());
557 assertEquals(A, refs.get("refs/heads/my/a+b").getObjectId());
558 assertEquals(B, refs.get("refs/heads/my/a/b/c").getObjectId());
559
560 }
561
562 @Test
563 public void testGetRefs_TagsOnly_AllPacked() throws IOException {
564 Map<String, Ref> tags;
565 Ref a;
566
567 deleteLooseRef(HEAD);
568 writePackedRef("refs/tags/v1.0", v1_0);
569
570 tags = refdir.getRefs(R_TAGS);
571 assertEquals(1, tags.size());
572
573 a = tags.get("v1.0");
574
575 assertEquals("refs/tags/v1.0", a.getName());
576 assertEquals(v1_0, a.getObjectId());
577 }
578
579 @Test
580 public void testGetRefs_DiscoversNewLoose1() throws IOException {
581 Map<String, Ref> orig, next;
582 Ref orig_r, next_r;
583
584 writeLooseRef("refs/heads/master", A);
585 orig = refdir.getRefs(RefDatabase.ALL);
586
587 writeLooseRef("refs/heads/next", B);
588 next = refdir.getRefs(RefDatabase.ALL);
589
590 assertEquals(2, orig.size());
591 assertEquals(3, next.size());
592
593 assertFalse(orig.containsKey("refs/heads/next"));
594 assertTrue(next.containsKey("refs/heads/next"));
595
596 orig_r = orig.get("refs/heads/master");
597 next_r = next.get("refs/heads/master");
598 assertEquals(A, orig_r.getObjectId());
599 assertSame("uses cached instance", orig_r, next_r);
600 assertSame("same HEAD", orig_r, orig.get(HEAD).getTarget());
601 assertSame("same HEAD", orig_r, next.get(HEAD).getTarget());
602
603 next_r = next.get("refs/heads/next");
604 assertSame(LOOSE, next_r.getStorage());
605 assertEquals(B, next_r.getObjectId());
606 }
607
608 @Test
609 public void testGetRefs_DiscoversNewLoose2() throws IOException {
610 Map<String, Ref> orig, next, news;
611
612 writeLooseRef("refs/heads/pu", A);
613 orig = refdir.getRefs(RefDatabase.ALL);
614
615 writeLooseRef("refs/heads/new/B", B);
616 news = refdir.getRefs("refs/heads/new/");
617 next = refdir.getRefs(RefDatabase.ALL);
618
619 assertEquals(1, orig.size());
620 assertEquals(2, next.size());
621 assertEquals(1, news.size());
622
623 assertTrue(orig.containsKey("refs/heads/pu"));
624 assertTrue(next.containsKey("refs/heads/pu"));
625 assertFalse(news.containsKey("refs/heads/pu"));
626
627 assertFalse(orig.containsKey("refs/heads/new/B"));
628 assertTrue(next.containsKey("refs/heads/new/B"));
629 assertTrue(news.containsKey("B"));
630 }
631
632 @Test
633 public void testGetRefs_DiscoversModifiedLoose() throws IOException {
634 Map<String, Ref> all;
635
636 writeLooseRef("refs/heads/master", A);
637 all = refdir.getRefs(RefDatabase.ALL);
638 assertEquals(A, all.get(HEAD).getObjectId());
639
640 writeLooseRef("refs/heads/master", B);
641 all = refdir.getRefs(RefDatabase.ALL);
642 assertEquals(B, all.get(HEAD).getObjectId());
643 }
644
645 @Test
646 public void testGetRef_DiscoversModifiedLoose() throws IOException {
647 Map<String, Ref> all;
648
649 writeLooseRef("refs/heads/master", A);
650 all = refdir.getRefs(RefDatabase.ALL);
651 assertEquals(A, all.get(HEAD).getObjectId());
652
653 writeLooseRef("refs/heads/master", B);
654
655 Ref master = refdir.getRef("refs/heads/master");
656 assertEquals(B, master.getObjectId());
657 }
658
659 @Test
660 public void testGetRefs_DiscoversDeletedLoose1() throws IOException {
661 Map<String, Ref> orig, next;
662 Ref orig_r, next_r;
663
664 writeLooseRef("refs/heads/B", B);
665 writeLooseRef("refs/heads/master", A);
666 orig = refdir.getRefs(RefDatabase.ALL);
667
668 deleteLooseRef("refs/heads/B");
669 next = refdir.getRefs(RefDatabase.ALL);
670
671 assertEquals(3, orig.size());
672 assertEquals(2, next.size());
673
674 assertTrue(orig.containsKey("refs/heads/B"));
675 assertFalse(next.containsKey("refs/heads/B"));
676
677 orig_r = orig.get("refs/heads/master");
678 next_r = next.get("refs/heads/master");
679 assertEquals(A, orig_r.getObjectId());
680 assertSame("uses cached instance", orig_r, next_r);
681 assertSame("same HEAD", orig_r, orig.get(HEAD).getTarget());
682 assertSame("same HEAD", orig_r, next.get(HEAD).getTarget());
683
684 orig_r = orig.get("refs/heads/B");
685 assertSame(LOOSE, orig_r.getStorage());
686 assertEquals(B, orig_r.getObjectId());
687 }
688
689 @Test
690 public void testGetRef_DiscoversDeletedLoose() throws IOException {
691 Map<String, Ref> all;
692
693 writeLooseRef("refs/heads/master", A);
694 all = refdir.getRefs(RefDatabase.ALL);
695 assertEquals(A, all.get(HEAD).getObjectId());
696
697 deleteLooseRef("refs/heads/master");
698 assertNull(refdir.getRef("refs/heads/master"));
699 assertTrue(refdir.getRefs(RefDatabase.ALL).isEmpty());
700 }
701
702 @Test
703 public void testGetRefs_DiscoversDeletedLoose2() throws IOException {
704 Map<String, Ref> orig, next;
705
706 writeLooseRef("refs/heads/master", A);
707 writeLooseRef("refs/heads/pu", B);
708 orig = refdir.getRefs(RefDatabase.ALL);
709
710 deleteLooseRef("refs/heads/pu");
711 next = refdir.getRefs(RefDatabase.ALL);
712
713 assertEquals(3, orig.size());
714 assertEquals(2, next.size());
715
716 assertTrue(orig.containsKey("refs/heads/pu"));
717 assertFalse(next.containsKey("refs/heads/pu"));
718 }
719
720 @Test
721 public void testGetRefs_DiscoversDeletedLoose3() throws IOException {
722 Map<String, Ref> orig, next;
723
724 writeLooseRef("refs/heads/master", A);
725 writeLooseRef("refs/heads/next", B);
726 writeLooseRef("refs/heads/pu", B);
727 writeLooseRef("refs/tags/v1.0", v1_0);
728 orig = refdir.getRefs(RefDatabase.ALL);
729
730 deleteLooseRef("refs/heads/pu");
731 deleteLooseRef("refs/heads/next");
732 next = refdir.getRefs(RefDatabase.ALL);
733
734 assertEquals(5, orig.size());
735 assertEquals(3, next.size());
736
737 assertTrue(orig.containsKey("refs/heads/pu"));
738 assertTrue(orig.containsKey("refs/heads/next"));
739 assertFalse(next.containsKey("refs/heads/pu"));
740 assertFalse(next.containsKey("refs/heads/next"));
741 }
742
743 @Test
744 public void testGetRefs_DiscoversDeletedLoose4() throws IOException {
745 Map<String, Ref> orig, next;
746 Ref orig_r, next_r;
747
748 writeLooseRef("refs/heads/B", B);
749 writeLooseRef("refs/heads/master", A);
750 orig = refdir.getRefs(RefDatabase.ALL);
751
752 deleteLooseRef("refs/heads/master");
753 next = refdir.getRefs("refs/heads/");
754
755 assertEquals(3, orig.size());
756 assertEquals(1, next.size());
757
758 assertTrue(orig.containsKey("refs/heads/B"));
759 assertTrue(orig.containsKey("refs/heads/master"));
760 assertTrue(next.containsKey("B"));
761 assertFalse(next.containsKey("master"));
762
763 orig_r = orig.get("refs/heads/B");
764 next_r = next.get("B");
765 assertEquals(B, orig_r.getObjectId());
766 assertSame("uses cached instance", orig_r, next_r);
767 }
768
769 @Test
770 public void testGetRefs_DiscoversDeletedLoose5() throws IOException {
771 Map<String, Ref> orig, next;
772
773 writeLooseRef("refs/heads/master", A);
774 writeLooseRef("refs/heads/pu", B);
775 orig = refdir.getRefs(RefDatabase.ALL);
776
777 deleteLooseRef("refs/heads/pu");
778 writeLooseRef("refs/tags/v1.0", v1_0);
779 next = refdir.getRefs(RefDatabase.ALL);
780
781 assertEquals(3, orig.size());
782 assertEquals(3, next.size());
783
784 assertTrue(orig.containsKey("refs/heads/pu"));
785 assertFalse(orig.containsKey("refs/tags/v1.0"));
786 assertFalse(next.containsKey("refs/heads/pu"));
787 assertTrue(next.containsKey("refs/tags/v1.0"));
788 }
789
790 @Test
791 public void testGetRefs_SkipsLockFiles() throws IOException {
792 Map<String, Ref> all;
793
794 writeLooseRef("refs/heads/master", A);
795 writeLooseRef("refs/heads/pu.lock", B);
796 all = refdir.getRefs(RefDatabase.ALL);
797
798 assertEquals(2, all.size());
799
800 assertTrue(all.containsKey(HEAD));
801 assertTrue(all.containsKey("refs/heads/master"));
802 assertFalse(all.containsKey("refs/heads/pu.lock"));
803 }
804
805 @Test
806 public void testGetRefs_CycleInSymbolicRef() throws IOException {
807 Map<String, Ref> all;
808 Ref r;
809
810 writeLooseRef("refs/1", "ref: refs/2\n");
811 writeLooseRef("refs/2", "ref: refs/3\n");
812 writeLooseRef("refs/3", "ref: refs/4\n");
813 writeLooseRef("refs/4", "ref: refs/5\n");
814 writeLooseRef("refs/5", "ref: refs/end\n");
815 writeLooseRef("refs/end", A);
816
817 all = refdir.getRefs(RefDatabase.ALL);
818 r = all.get("refs/1");
819 assertNotNull("has 1", r);
820
821 assertEquals("refs/1", r.getName());
822 assertEquals(A, r.getObjectId());
823 assertTrue(r.isSymbolic());
824
825 r = r.getTarget();
826 assertEquals("refs/2", r.getName());
827 assertEquals(A, r.getObjectId());
828 assertTrue(r.isSymbolic());
829
830 r = r.getTarget();
831 assertEquals("refs/3", r.getName());
832 assertEquals(A, r.getObjectId());
833 assertTrue(r.isSymbolic());
834
835 r = r.getTarget();
836 assertEquals("refs/4", r.getName());
837 assertEquals(A, r.getObjectId());
838 assertTrue(r.isSymbolic());
839
840 r = r.getTarget();
841 assertEquals("refs/5", r.getName());
842 assertEquals(A, r.getObjectId());
843 assertTrue(r.isSymbolic());
844
845 r = r.getTarget();
846 assertEquals("refs/end", r.getName());
847 assertEquals(A, r.getObjectId());
848 assertFalse(r.isSymbolic());
849
850 writeLooseRef("refs/5", "ref: refs/6\n");
851 writeLooseRef("refs/6", "ref: refs/end\n");
852 all = refdir.getRefs(RefDatabase.ALL);
853 r = all.get("refs/1");
854 assertNull("mising 1 due to cycle", r);
855 }
856
857 @Test
858 public void testGetRef_CycleInSymbolicRef() throws IOException {
859 Ref r;
860
861 writeLooseRef("refs/1", "ref: refs/2\n");
862 writeLooseRef("refs/2", "ref: refs/3\n");
863 writeLooseRef("refs/3", "ref: refs/4\n");
864 writeLooseRef("refs/4", "ref: refs/5\n");
865 writeLooseRef("refs/5", "ref: refs/end\n");
866 writeLooseRef("refs/end", A);
867
868 r = refdir.getRef("1");
869 assertEquals("refs/1", r.getName());
870 assertEquals(A, r.getObjectId());
871 assertTrue(r.isSymbolic());
872
873 writeLooseRef("refs/5", "ref: refs/6\n");
874 writeLooseRef("refs/6", "ref: refs/end\n");
875
876 r = refdir.getRef("1");
877 assertNull("missing 1 due to cycle", r);
878
879 writeLooseRef("refs/heads/1", B);
880
881 r = refdir.getRef("1");
882 assertEquals("refs/heads/1", r.getName());
883 assertEquals(B, r.getObjectId());
884 assertFalse(r.isSymbolic());
885 }
886
887 @Test
888 public void testGetRefs_PackedNotPeeled_Sorted() throws IOException {
889 Map<String, Ref> all;
890
891 writePackedRefs("" +
892 A.name() + " refs/heads/master\n" +
893 B.name() + " refs/heads/other\n" +
894 v1_0.name() + " refs/tags/v1.0\n");
895 all = refdir.getRefs(RefDatabase.ALL);
896
897 assertEquals(4, all.size());
898 final Ref head = all.get(HEAD);
899 final Ref master = all.get("refs/heads/master");
900 final Ref other = all.get("refs/heads/other");
901 final Ref tag = all.get("refs/tags/v1.0");
902
903 assertEquals(A, master.getObjectId());
904 assertFalse(master.isPeeled());
905 assertNull(master.getPeeledObjectId());
906
907 assertEquals(B, other.getObjectId());
908 assertFalse(other.isPeeled());
909 assertNull(other.getPeeledObjectId());
910
911 assertSame(master, head.getTarget());
912 assertEquals(A, head.getObjectId());
913 assertFalse(head.isPeeled());
914 assertNull(head.getPeeledObjectId());
915
916 assertEquals(v1_0, tag.getObjectId());
917 assertFalse(tag.isPeeled());
918 assertNull(tag.getPeeledObjectId());
919 }
920
921 @Test
922 public void testGetRef_PackedNotPeeled_WrongSort() throws IOException {
923 writePackedRefs("" +
924 v1_0.name() + " refs/tags/v1.0\n" +
925 B.name() + " refs/heads/other\n" +
926 A.name() + " refs/heads/master\n");
927
928 final Ref head = refdir.getRef(HEAD);
929 final Ref master = refdir.getRef("refs/heads/master");
930 final Ref other = refdir.getRef("refs/heads/other");
931 final Ref tag = refdir.getRef("refs/tags/v1.0");
932
933 assertEquals(A, master.getObjectId());
934 assertFalse(master.isPeeled());
935 assertNull(master.getPeeledObjectId());
936
937 assertEquals(B, other.getObjectId());
938 assertFalse(other.isPeeled());
939 assertNull(other.getPeeledObjectId());
940
941 assertSame(master, head.getTarget());
942 assertEquals(A, head.getObjectId());
943 assertFalse(head.isPeeled());
944 assertNull(head.getPeeledObjectId());
945
946 assertEquals(v1_0, tag.getObjectId());
947 assertFalse(tag.isPeeled());
948 assertNull(tag.getPeeledObjectId());
949 }
950
951 @Test
952 public void testGetRefs_PackedWithPeeled() throws IOException {
953 Map<String, Ref> all;
954
955 writePackedRefs("# pack-refs with: peeled \n" +
956 A.name() + " refs/heads/master\n" +
957 B.name() + " refs/heads/other\n" +
958 v1_0.name() + " refs/tags/v1.0\n" +
959 "^" + v1_0.getObject().name() + "\n");
960 all = refdir.getRefs(RefDatabase.ALL);
961
962 assertEquals(4, all.size());
963 final Ref head = all.get(HEAD);
964 final Ref master = all.get("refs/heads/master");
965 final Ref other = all.get("refs/heads/other");
966 final Ref tag = all.get("refs/tags/v1.0");
967
968 assertEquals(A, master.getObjectId());
969 assertTrue(master.isPeeled());
970 assertNull(master.getPeeledObjectId());
971
972 assertEquals(B, other.getObjectId());
973 assertTrue(other.isPeeled());
974 assertNull(other.getPeeledObjectId());
975
976 assertSame(master, head.getTarget());
977 assertEquals(A, head.getObjectId());
978 assertTrue(head.isPeeled());
979 assertNull(head.getPeeledObjectId());
980
981 assertEquals(v1_0, tag.getObjectId());
982 assertTrue(tag.isPeeled());
983 assertEquals(v1_0.getObject(), tag.getPeeledObjectId());
984 }
985
986 @Test
987 public void test_repack() throws Exception {
988 Map<String, Ref> all;
989
990 writePackedRefs("# pack-refs with: peeled \n" +
991 A.name() + " refs/heads/master\n" +
992 B.name() + " refs/heads/other\n" +
993 v1_0.name() + " refs/tags/v1.0\n" +
994 "^" + v1_0.getObject().name() + "\n");
995 all = refdir.getRefs(RefDatabase.ALL);
996
997 assertEquals(4, all.size());
998 assertEquals(Storage.LOOSE, all.get(HEAD).getStorage());
999 assertEquals(Storage.PACKED, all.get("refs/heads/master").getStorage());
1000 assertEquals(A.getId(), all.get("refs/heads/master").getObjectId());
1001 assertEquals(Storage.PACKED, all.get("refs/heads/other").getStorage());
1002 assertEquals(Storage.PACKED, all.get("refs/tags/v1.0").getStorage());
1003
1004 repo.update("refs/heads/master", B.getId());
1005 RevTag v0_1 = repo.tag("v0.1", A);
1006 repo.update("refs/tags/v0.1", v0_1);
1007
1008 all = refdir.getRefs(RefDatabase.ALL);
1009 assertEquals(5, all.size());
1010 assertEquals(Storage.LOOSE, all.get(HEAD).getStorage());
1011
1012 assertEquals(Storage.LOOSE, all.get("refs/heads/master")
1013 .getStorage());
1014 assertEquals(B.getId(), all.get("refs/heads/master").getObjectId());
1015 assertEquals(Storage.PACKED, all.get("refs/heads/other").getStorage());
1016 assertEquals(Storage.PACKED, all.get("refs/tags/v1.0").getStorage());
1017 assertEquals(Storage.LOOSE, all.get("refs/tags/v0.1").getStorage());
1018 assertEquals(v0_1.getId(), all.get("refs/tags/v0.1").getObjectId());
1019
1020 all = refdir.getRefs(RefDatabase.ALL);
1021 refdir.pack(new ArrayList<>(all.keySet()));
1022
1023 all = refdir.getRefs(RefDatabase.ALL);
1024 assertEquals(5, all.size());
1025 assertEquals(Storage.LOOSE, all.get(HEAD).getStorage());
1026
1027 assertEquals(Storage.PACKED, all.get("refs/heads/master").getStorage());
1028 assertEquals(B.getId(), all.get("refs/heads/master").getObjectId());
1029 assertEquals(Storage.PACKED, all.get("refs/heads/other").getStorage());
1030 assertEquals(Storage.PACKED, all.get("refs/tags/v1.0").getStorage());
1031 assertEquals(Storage.PACKED, all.get("refs/tags/v0.1").getStorage());
1032 assertEquals(v0_1.getId(), all.get("refs/tags/v0.1").getObjectId());
1033 }
1034
1035 @Test
1036 public void testGetRef_EmptyDatabase() throws IOException {
1037 Ref r;
1038
1039 r = refdir.getRef(HEAD);
1040 assertTrue(r.isSymbolic());
1041 assertSame(LOOSE, r.getStorage());
1042 assertEquals("refs/heads/master", r.getTarget().getName());
1043 assertSame(NEW, r.getTarget().getStorage());
1044 assertNull(r.getTarget().getObjectId());
1045
1046 assertNull(refdir.getRef("refs/heads/master"));
1047 assertNull(refdir.getRef("refs/tags/v1.0"));
1048 assertNull(refdir.getRef("FETCH_HEAD"));
1049 assertNull(refdir.getRef("NOT.A.REF.NAME"));
1050 assertNull(refdir.getRef("master"));
1051 assertNull(refdir.getRef("v1.0"));
1052 }
1053
1054 @Test
1055 public void testExactRef_EmptyDatabase() throws IOException {
1056 Ref r;
1057
1058 r = refdir.exactRef(HEAD);
1059 assertTrue(r.isSymbolic());
1060 assertSame(LOOSE, r.getStorage());
1061 assertEquals("refs/heads/master", r.getTarget().getName());
1062 assertSame(NEW, r.getTarget().getStorage());
1063 assertNull(r.getTarget().getObjectId());
1064
1065 assertNull(refdir.exactRef("refs/heads/master"));
1066 assertNull(refdir.exactRef("refs/tags/v1.0"));
1067 assertNull(refdir.exactRef("FETCH_HEAD"));
1068 assertNull(refdir.exactRef("NOT.A.REF.NAME"));
1069 assertNull(refdir.exactRef("master"));
1070 assertNull(refdir.exactRef("v1.0"));
1071 }
1072
1073 @Test
1074 public void testGetRef_FetchHead() throws IOException {
1075
1076
1077
1078 write(new File(diskRepo.getDirectory(), "FETCH_HEAD"), A.name()
1079 + "\tnot-for-merge"
1080 + "\tbranch 'master' of git://egit.eclipse.org/jgit\n");
1081
1082 Ref r = refdir.getRef("FETCH_HEAD");
1083 assertFalse(r.isSymbolic());
1084 assertEquals(A, r.getObjectId());
1085 assertEquals("FETCH_HEAD", r.getName());
1086 assertFalse(r.isPeeled());
1087 assertNull(r.getPeeledObjectId());
1088 }
1089
1090 @Test
1091 public void testExactRef_FetchHead() throws IOException {
1092
1093
1094
1095 write(new File(diskRepo.getDirectory(), "FETCH_HEAD"), A.name()
1096 + "\tnot-for-merge"
1097 + "\tbranch 'master' of git://egit.eclipse.org/jgit\n");
1098
1099 Ref r = refdir.exactRef("FETCH_HEAD");
1100 assertFalse(r.isSymbolic());
1101 assertEquals(A, r.getObjectId());
1102 assertEquals("FETCH_HEAD", r.getName());
1103 assertFalse(r.isPeeled());
1104 assertNull(r.getPeeledObjectId());
1105 }
1106
1107 @Test
1108 public void testGetRef_AnyHeadWithGarbage() throws IOException {
1109 write(new File(diskRepo.getDirectory(), "refs/heads/A"), A.name()
1110 + "012345 . this is not a standard reference\n"
1111 + "#and even more junk\n");
1112
1113 Ref r = refdir.getRef("refs/heads/A");
1114 assertFalse(r.isSymbolic());
1115 assertEquals(A, r.getObjectId());
1116 assertEquals("refs/heads/A", r.getName());
1117 assertFalse(r.isPeeled());
1118 assertNull(r.getPeeledObjectId());
1119 }
1120
1121 @Test
1122 public void testGetRefs_CorruptSymbolicReference() throws IOException {
1123 String name = "refs/heads/A";
1124 writeLooseRef(name, "ref: \n");
1125 assertTrue(refdir.getRefs(RefDatabase.ALL).isEmpty());
1126 }
1127
1128 @Test
1129 public void testGetRef_CorruptSymbolicReference() throws IOException {
1130 String name = "refs/heads/A";
1131 writeLooseRef(name, "ref: \n");
1132 try {
1133 refdir.getRef(name);
1134 fail("read an invalid reference");
1135 } catch (IOException err) {
1136 String msg = err.getMessage();
1137 assertEquals("Not a ref: " + name + ": ref:", msg);
1138 }
1139 }
1140
1141 @Test
1142 public void testGetRefs_CorruptObjectIdReference() throws IOException {
1143 String name = "refs/heads/A";
1144 String content = "zoo" + A.name();
1145 writeLooseRef(name, content + "\n");
1146 assertTrue(refdir.getRefs(RefDatabase.ALL).isEmpty());
1147 }
1148
1149 @Test
1150 public void testGetRef_CorruptObjectIdReference() throws IOException {
1151 String name = "refs/heads/A";
1152 String content = "zoo" + A.name();
1153 writeLooseRef(name, content + "\n");
1154 try {
1155 refdir.getRef(name);
1156 fail("read an invalid reference");
1157 } catch (IOException err) {
1158 String msg = err.getMessage();
1159 assertEquals("Not a ref: " + name + ": " + content, msg);
1160 }
1161 }
1162
1163 @Test
1164 public void testIsNameConflicting() throws IOException {
1165 writeLooseRef("refs/heads/a/b", A);
1166 writePackedRef("refs/heads/q", B);
1167
1168
1169 assertTrue(refdir.isNameConflicting("refs"));
1170 assertTrue(refdir.isNameConflicting("refs/heads"));
1171 assertTrue(refdir.isNameConflicting("refs/heads/a"));
1172
1173
1174 assertFalse(refdir.isNameConflicting("refs/heads/a/b"));
1175
1176
1177 assertFalse(refdir.isNameConflicting("refs/heads/a/d"));
1178 assertFalse(refdir.isNameConflicting("refs/heads/master"));
1179
1180
1181 assertTrue(refdir.isNameConflicting("refs/heads/a/b/c"));
1182 assertTrue(refdir.isNameConflicting("refs/heads/q/master"));
1183 }
1184
1185 @Test
1186 public void testPeelLooseTag() throws IOException {
1187 writeLooseRef("refs/tags/v1_0", v1_0);
1188 writeLooseRef("refs/tags/current", "ref: refs/tags/v1_0\n");
1189
1190 final Ref tag = refdir.getRef("refs/tags/v1_0");
1191 final Ref cur = refdir.getRef("refs/tags/current");
1192
1193 assertEquals(v1_0, tag.getObjectId());
1194 assertFalse(tag.isSymbolic());
1195 assertFalse(tag.isPeeled());
1196 assertNull(tag.getPeeledObjectId());
1197
1198 assertEquals(v1_0, cur.getObjectId());
1199 assertTrue(cur.isSymbolic());
1200 assertFalse(cur.isPeeled());
1201 assertNull(cur.getPeeledObjectId());
1202
1203 final Ref tag_p = refdir.peel(tag);
1204 final Ref cur_p = refdir.peel(cur);
1205
1206 assertNotSame(tag, tag_p);
1207 assertFalse(tag_p.isSymbolic());
1208 assertTrue(tag_p.isPeeled());
1209 assertEquals(v1_0, tag_p.getObjectId());
1210 assertEquals(v1_0.getObject(), tag_p.getPeeledObjectId());
1211 assertSame(tag_p, refdir.peel(tag_p));
1212
1213 assertNotSame(cur, cur_p);
1214 assertEquals("refs/tags/current", cur_p.getName());
1215 assertTrue(cur_p.isSymbolic());
1216 assertEquals("refs/tags/v1_0", cur_p.getTarget().getName());
1217 assertTrue(cur_p.isPeeled());
1218 assertEquals(v1_0, cur_p.getObjectId());
1219 assertEquals(v1_0.getObject(), cur_p.getPeeledObjectId());
1220
1221
1222
1223 final Ref tag_p2 = refdir.getRef("refs/tags/v1_0");
1224 assertFalse(tag_p2.isSymbolic());
1225 assertTrue(tag_p2.isPeeled());
1226 assertEquals(v1_0, tag_p2.getObjectId());
1227 assertEquals(v1_0.getObject(), tag_p2.getPeeledObjectId());
1228
1229 assertSame(tag_p2, refdir.getRef("refs/tags/v1_0"));
1230 assertSame(tag_p2, refdir.getRef("refs/tags/current").getTarget());
1231 assertSame(tag_p2, refdir.peel(tag_p2));
1232 }
1233
1234 @Test
1235 public void testPeelCommit() throws IOException {
1236 writeLooseRef("refs/heads/master", A);
1237
1238 Ref master = refdir.getRef("refs/heads/master");
1239 assertEquals(A, master.getObjectId());
1240 assertFalse(master.isPeeled());
1241 assertNull(master.getPeeledObjectId());
1242
1243 Ref master_p = refdir.peel(master);
1244 assertNotSame(master, master_p);
1245 assertEquals(A, master_p.getObjectId());
1246 assertTrue(master_p.isPeeled());
1247 assertNull(master_p.getPeeledObjectId());
1248
1249
1250
1251 Ref master_p2 = refdir.getRef("refs/heads/master");
1252 assertNotSame(master, master_p2);
1253 assertEquals(A, master_p2.getObjectId());
1254 assertTrue(master_p2.isPeeled());
1255 assertNull(master_p2.getPeeledObjectId());
1256 assertSame(master_p2, refdir.peel(master_p2));
1257 }
1258
1259 @Test
1260 public void testRefsChangedStackOverflow() throws Exception {
1261 final FileRepository newRepo = createBareRepository();
1262 final RefDatabase refDb = newRepo.getRefDatabase();
1263 File packedRefs = new File(newRepo.getDirectory(), "packed-refs");
1264 assertTrue(packedRefs.createNewFile());
1265 final AtomicReference<StackOverflowError> error = new AtomicReference<>();
1266 final AtomicReference<IOException> exception = new AtomicReference<>();
1267 final AtomicInteger changeCount = new AtomicInteger();
1268 newRepo.getListenerList().addRefsChangedListener(
1269 new RefsChangedListener() {
1270
1271 @Override
1272 public void onRefsChanged(RefsChangedEvent event) {
1273 try {
1274 refDb.getRefsByPrefix("ref");
1275 changeCount.incrementAndGet();
1276 } catch (StackOverflowError soe) {
1277 error.set(soe);
1278 } catch (IOException ioe) {
1279 exception.set(ioe);
1280 }
1281 }
1282 });
1283 refDb.getRefsByPrefix("ref");
1284 refDb.getRefsByPrefix("ref");
1285 assertNull(error.get());
1286 assertNull(exception.get());
1287 assertEquals(1, changeCount.get());
1288 }
1289
1290 @Test
1291 public void testPackedRefsLockFailure() throws Exception {
1292 writeLooseRef("refs/heads/master", A);
1293 refdir.setRetrySleepMs(Arrays.asList(0, 0));
1294 LockFile myLock = refdir.lockPackedRefs();
1295 try {
1296 refdir.pack(Arrays.asList("refs/heads/master"));
1297 fail("expected LockFailedException");
1298 } catch (LockFailedException e) {
1299 assertEquals(refdir.packedRefsFile.getPath(), e.getFile().getPath());
1300 } finally {
1301 myLock.unlock();
1302 }
1303 Ref ref = refdir.getRef("refs/heads/master");
1304 assertEquals(Storage.LOOSE, ref.getStorage());
1305 }
1306
1307 private void writeLooseRef(String name, AnyObjectId id) throws IOException {
1308 writeLooseRef(name, id.name() + "\n");
1309 }
1310
1311 private void writeLooseRef(String name, String content) throws IOException {
1312 write(new File(diskRepo.getDirectory(), name), content);
1313 }
1314
1315 private void writePackedRef(String name, AnyObjectId id) throws IOException {
1316 writePackedRefs(id.name() + " " + name + "\n");
1317 }
1318
1319 private void writePackedRefs(String content) throws IOException {
1320 File pr = new File(diskRepo.getDirectory(), "packed-refs");
1321 write(pr, content);
1322
1323 final long now = System.currentTimeMillis();
1324 final int oneHourAgo = 3600 * 1000;
1325 pr.setLastModified(now - oneHourAgo);
1326 }
1327
1328 private void deleteLooseRef(String name) {
1329 File path = new File(diskRepo.getDirectory(), name);
1330 assertTrue("deleted " + name, path.delete());
1331 }
1332 }