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
45
46 package org.eclipse.jgit.internal.storage.file;
47
48 import static org.eclipse.jgit.junit.Assert.assertEquals;
49 import static java.nio.charset.StandardCharsets.UTF_8;
50 import static org.eclipse.jgit.lib.Constants.LOCK_SUFFIX;
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.List;
63 import java.util.Map;
64 import java.util.Map.Entry;
65 import java.util.Optional;
66
67 import org.eclipse.jgit.lib.AnyObjectId;
68 import org.eclipse.jgit.lib.Constants;
69 import org.eclipse.jgit.lib.ObjectId;
70 import org.eclipse.jgit.lib.ObjectInserter;
71 import org.eclipse.jgit.lib.PersonIdent;
72 import org.eclipse.jgit.lib.Ref;
73 import org.eclipse.jgit.lib.RefRename;
74 import org.eclipse.jgit.lib.RefUpdate;
75 import org.eclipse.jgit.lib.RefUpdate.Result;
76 import org.eclipse.jgit.lib.ReflogEntry;
77 import org.eclipse.jgit.lib.ReflogReader;
78 import org.eclipse.jgit.lib.Repository;
79 import org.eclipse.jgit.revwalk.RevCommit;
80 import org.eclipse.jgit.revwalk.RevWalk;
81 import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase;
82 import org.junit.Test;
83
84 public class RefUpdateTest extends SampleDataRepositoryTestCase {
85
86 private void writeSymref(String src, String dst) throws IOException {
87 RefUpdate u = db.updateRef(src);
88 switch (u.link(dst)) {
89 case NEW:
90 case FORCED:
91 case NO_CHANGE:
92 break;
93 default:
94 fail("link " + src + " to " + dst);
95 }
96 }
97
98 private RefUpdate updateRef(String name) throws IOException {
99 final RefUpdate ref = db.updateRef(name);
100 ref.setNewObjectId(db.resolve(Constants.HEAD));
101 return ref;
102 }
103
104 private void delete(RefUpdate ref, Result expected)
105 throws IOException {
106 delete(ref, expected, true, true);
107 }
108
109 private void delete(final RefUpdate ref, final Result expected,
110 final boolean exists, final boolean removed) throws IOException {
111 delete(db, ref, expected, exists, removed);
112 }
113
114 private void delete(Repository repo, final RefUpdate ref,
115 final Result expected, final boolean exists, final boolean removed)
116 throws IOException {
117 assertEquals(exists, getRef(repo, ref.getName()).isPresent());
118 assertEquals(expected, ref.delete());
119 assertEquals(!removed, getRef(repo, ref.getName()).isPresent());
120 }
121
122 private Optional<Ref> getRef(Repository repo, String name)
123 throws IOException {
124 return getRef(repo.getRefDatabase().getRefs(), name);
125 }
126
127 private Optional<Ref> getRef(List<Ref> refs, String name) {
128 return refs.stream().filter(r -> r.getName().equals(name)).findAny();
129 }
130
131 @Test
132 public void testNoCacheObjectIdSubclass() throws IOException {
133 final String newRef = "refs/heads/abc";
134 final RefUpdate ru = updateRef(newRef);
135 final SubclassedId newid = new SubclassedId(ru.getNewObjectId());
136 ru.setNewObjectId(newid);
137 Result update = ru.update();
138 assertEquals(Result.NEW, update);
139 final Ref r = getRef(db, newRef).get();
140 assertEquals(newRef, r.getName());
141 assertNotNull(r.getObjectId());
142 assertNotSame(newid, r.getObjectId());
143 assertSame(ObjectId.class, r.getObjectId().getClass());
144 assertEquals(newid, r.getObjectId());
145 List<ReflogEntry> reverseEntries1 = db
146 .getReflogReader("refs/heads/abc").getReverseEntries();
147 ReflogEntry entry1 = reverseEntries1.get(0);
148 assertEquals(1, reverseEntries1.size());
149 assertEquals(ObjectId.zeroId(), entry1.getOldId());
150 assertEquals(r.getObjectId(), entry1.getNewId());
151 assertEquals(new PersonIdent(db).toString(), entry1.getWho().toString());
152 assertEquals("", entry1.getComment());
153 List<ReflogEntry> reverseEntries2 = db.getReflogReader("HEAD")
154 .getReverseEntries();
155 assertEquals(0, reverseEntries2.size());
156 }
157
158 @Test
159 public void testNewNamespaceConflictWithLoosePrefixNameExists()
160 throws IOException {
161 final String newRef = "refs/heads/z";
162 final RefUpdate ru = updateRef(newRef);
163 Result update = ru.update();
164 assertEquals(Result.NEW, update);
165
166 final String newRef2 = "refs/heads/z/a";
167 final RefUpdate ru2 = updateRef(newRef2);
168 Result update2 = ru2.update();
169 assertEquals(Result.LOCK_FAILURE, update2);
170 assertEquals(1, db.getReflogReader("refs/heads/z").getReverseEntries().size());
171 assertEquals(0, db.getReflogReader("HEAD").getReverseEntries().size());
172 }
173
174 @Test
175 public void testNewNamespaceConflictWithPackedPrefixNameExists()
176 throws IOException {
177 final String newRef = "refs/heads/master/x";
178 final RefUpdate ru = updateRef(newRef);
179 Result update = ru.update();
180 assertEquals(Result.LOCK_FAILURE, update);
181 assertNull(db.getReflogReader("refs/heads/master/x"));
182 assertEquals(0, db.getReflogReader("HEAD").getReverseEntries().size());
183 }
184
185 @Test
186 public void testNewNamespaceConflictWithLoosePrefixOfExisting()
187 throws IOException {
188 final String newRef = "refs/heads/z/a";
189 final RefUpdate ru = updateRef(newRef);
190 Result update = ru.update();
191 assertEquals(Result.NEW, update);
192
193 final String newRef2 = "refs/heads/z";
194 final RefUpdate ru2 = updateRef(newRef2);
195 Result update2 = ru2.update();
196 assertEquals(Result.LOCK_FAILURE, update2);
197 assertEquals(1, db.getReflogReader("refs/heads/z/a").getReverseEntries().size());
198 assertNull(db.getReflogReader("refs/heads/z"));
199 assertEquals(0, db.getReflogReader("HEAD").getReverseEntries().size());
200 }
201
202 @Test
203 public void testNewNamespaceConflictWithPackedPrefixOfExisting()
204 throws IOException {
205 final String newRef = "refs/heads/prefix";
206 final RefUpdate ru = updateRef(newRef);
207 Result update = ru.update();
208 assertEquals(Result.LOCK_FAILURE, update);
209 assertNull(db.getReflogReader("refs/heads/prefix"));
210 assertEquals(0, db.getReflogReader("HEAD").getReverseEntries().size());
211 }
212
213
214
215
216
217
218 @Test
219 public void testDeleteHEADreferencedRef() throws IOException {
220 ObjectId pid = db.resolve("refs/heads/master^");
221 RefUpdate updateRef = db.updateRef("refs/heads/master");
222 updateRef.setNewObjectId(pid);
223 updateRef.setForceUpdate(true);
224 Result update = updateRef.update();
225 assertEquals(Result.FORCED, update);
226
227 RefUpdate updateRef2 = db.updateRef("refs/heads/master");
228 Result delete = updateRef2.delete();
229 assertEquals(Result.REJECTED_CURRENT_BRANCH, delete);
230 assertEquals(pid, db.resolve("refs/heads/master"));
231 assertEquals(1,db.getReflogReader("refs/heads/master").getReverseEntries().size());
232 assertEquals(0,db.getReflogReader("HEAD").getReverseEntries().size());
233 }
234
235 @Test
236 public void testLooseDelete() throws IOException {
237 final String newRef = "refs/heads/abc";
238 RefUpdate ref = updateRef(newRef);
239 ref.update();
240 ref = updateRef(newRef);
241 delete(ref, Result.NO_CHANGE);
242 assertNull(db.getReflogReader("refs/heads/abc"));
243 }
244
245 @Test
246 public void testDeleteHead() throws IOException {
247 final RefUpdate ref = updateRef(Constants.HEAD);
248 delete(ref, Result.REJECTED_CURRENT_BRANCH, true, false);
249 assertEquals(0, db.getReflogReader("refs/heads/master").getReverseEntries().size());
250 assertEquals(0, db.getReflogReader("HEAD").getReverseEntries().size());
251 }
252
253 @Test
254 public void testDeleteHeadInBareRepo() throws IOException {
255 Repository bareRepo = createBareRepository();
256 String master = "refs/heads/master";
257 Ref head = bareRepo.exactRef(Constants.HEAD);
258 assertNotNull(head);
259 assertTrue(head.isSymbolic());
260 assertEquals(master, head.getLeaf().getName());
261 assertNull(head.getObjectId());
262 assertNull(bareRepo.exactRef(master));
263
264 ObjectId blobId;
265 try (ObjectInserter ins = bareRepo.newObjectInserter()) {
266 blobId = ins.insert(Constants.OBJ_BLOB, "contents".getBytes(UTF_8));
267 ins.flush();
268 }
269
270
271 RefUpdate ref = bareRepo.updateRef(Constants.HEAD);
272 ref.setNewObjectId(blobId);
273 assertEquals(Result.NEW, ref.update());
274
275 head = bareRepo.exactRef(Constants.HEAD);
276 assertTrue(head.isSymbolic());
277 assertEquals(master, head.getLeaf().getName());
278 assertEquals(blobId, head.getLeaf().getObjectId());
279 assertEquals(blobId, bareRepo.exactRef(master).getObjectId());
280
281
282
283 ref = bareRepo.updateRef(Constants.HEAD);
284 ref.setExpectedOldObjectId(blobId);
285 ref.setForceUpdate(true);
286 delete(bareRepo, ref, Result.FORCED, true, true);
287
288 head = bareRepo.exactRef(Constants.HEAD);
289 assertNotNull(head);
290 assertTrue(head.isSymbolic());
291 assertEquals(master, head.getLeaf().getName());
292 assertNull(head.getObjectId());
293 assertNull(bareRepo.exactRef(master));
294 }
295
296 @Test
297 public void testDeleteSymref() throws IOException {
298 RefUpdate dst = updateRef("refs/heads/abc");
299 assertEquals(Result.NEW, dst.update());
300 ObjectId id = dst.getNewObjectId();
301
302 RefUpdate u = db.updateRef("refs/symref");
303 assertEquals(Result.NEW, u.link(dst.getName()));
304
305 Ref ref = db.exactRef(u.getName());
306 assertNotNull(ref);
307 assertTrue(ref.isSymbolic());
308 assertEquals(dst.getName(), ref.getLeaf().getName());
309 assertEquals(id, ref.getLeaf().getObjectId());
310
311 u = db.updateRef(u.getName());
312 u.setDetachingSymbolicRef();
313 u.setForceUpdate(true);
314 assertEquals(Result.FORCED, u.delete());
315
316 assertNull(db.exactRef(u.getName()));
317 ref = db.exactRef(dst.getName());
318 assertNotNull(ref);
319 assertFalse(ref.isSymbolic());
320 assertEquals(id, ref.getObjectId());
321 }
322
323
324
325
326
327
328
329 @Test
330 public void testDeleteLooseAndItsDirectory() throws IOException {
331 ObjectId pid = db.resolve("refs/heads/c^");
332 RefUpdate updateRef = db.updateRef("refs/heads/z/c");
333 updateRef.setNewObjectId(pid);
334 updateRef.setForceUpdate(true);
335 updateRef.setRefLogMessage("new test ref", false);
336 Result update = updateRef.update();
337 assertEquals(Result.NEW, update);
338 assertTrue(new File(db.getDirectory(), Constants.R_HEADS + "z")
339 .exists());
340 assertTrue(new File(db.getDirectory(), "logs/refs/heads/z").exists());
341
342
343 RefUpdate updateRef2 = db.updateRef("refs/heads/z/c");
344 updateRef2.setForceUpdate(true);
345 Result delete = updateRef2.delete();
346 assertEquals(Result.FORCED, delete);
347 assertNull(db.resolve("refs/heads/z/c"));
348 assertFalse(new File(db.getDirectory(), Constants.R_HEADS + "z")
349 .exists());
350 assertFalse(new File(db.getDirectory(), "logs/refs/heads/z").exists());
351 }
352
353 @Test
354 public void testDeleteNotFound() throws IOException {
355 final RefUpdate ref = updateRef("refs/heads/xyz");
356 delete(ref, Result.NEW, false, true);
357 }
358
359 @Test
360 public void testDeleteFastForward() throws IOException {
361 final RefUpdate ref = updateRef("refs/heads/a");
362 delete(ref, Result.FAST_FORWARD);
363 }
364
365 @Test
366 public void testDeleteForce() throws IOException {
367 final RefUpdate ref = db.updateRef("refs/heads/b");
368 ref.setNewObjectId(db.resolve("refs/heads/a"));
369 delete(ref, Result.REJECTED, true, false);
370 ref.setForceUpdate(true);
371 delete(ref, Result.FORCED);
372 }
373
374 @Test
375 public void testDeleteWithoutHead() throws IOException {
376
377 RefUpdate refUpdate = db.updateRef(Constants.HEAD, true);
378 refUpdate.setForceUpdate(true);
379 refUpdate.setNewObjectId(ObjectId.zeroId());
380 Result updateResult = refUpdate.update();
381 assertEquals(Result.FORCED, updateResult);
382 Result deleteHeadResult = db.updateRef(Constants.HEAD).delete();
383 assertEquals(Result.NO_CHANGE, deleteHeadResult);
384
385
386 db.updateRef(Constants.R_HEADS + "master").delete();
387 }
388
389 @Test
390 public void testRefKeySameAsName() {
391 @SuppressWarnings("deprecation")
392 Map<String, Ref> allRefs = db.getAllRefs();
393 for (Entry<String, Ref> e : allRefs.entrySet()) {
394 assertEquals(e.getKey(), e.getValue().getName());
395 }
396 }
397
398
399
400
401
402
403 @Test
404 public void testUpdateRefForward() throws IOException {
405 ObjectId ppid = db.resolve("refs/heads/master^");
406 ObjectId pid = db.resolve("refs/heads/master");
407
408 RefUpdate updateRef = db.updateRef("refs/heads/master");
409 updateRef.setNewObjectId(ppid);
410 updateRef.setForceUpdate(true);
411 Result update = updateRef.update();
412 assertEquals(Result.FORCED, update);
413 assertEquals(ppid, db.resolve("refs/heads/master"));
414
415
416 RefUpdate updateRef2 = db.updateRef("refs/heads/master");
417 updateRef2.setNewObjectId(pid);
418 Result update2 = updateRef2.update();
419 assertEquals(Result.FAST_FORWARD, update2);
420 assertEquals(pid, db.resolve("refs/heads/master"));
421 }
422
423
424
425
426
427
428 @Test
429 public void testUpdateRefDetached() throws Exception {
430 ObjectId pid = db.resolve("refs/heads/master");
431 ObjectId ppid = db.resolve("refs/heads/master^");
432 RefUpdate updateRef = db.updateRef("HEAD", true);
433 updateRef.setForceUpdate(true);
434 updateRef.setNewObjectId(ppid);
435 Result update = updateRef.update();
436 assertEquals(Result.FORCED, update);
437 assertEquals(ppid, db.resolve("HEAD"));
438 Ref ref = db.exactRef("HEAD");
439 assertEquals("HEAD", ref.getName());
440 assertTrue("is detached", !ref.isSymbolic());
441
442
443 assertEquals(pid, db.resolve("refs/heads/master"));
444 ReflogReader reflogReader = db.getReflogReader("HEAD");
445 ReflogEntry e = reflogReader.getReverseEntries().get(0);
446 assertEquals(pid, e.getOldId());
447 assertEquals(ppid, e.getNewId());
448 assertEquals("GIT_COMMITTER_EMAIL", e.getWho().getEmailAddress());
449 assertEquals("GIT_COMMITTER_NAME", e.getWho().getName());
450 assertEquals(1250379778000L, e.getWho().getWhen().getTime());
451 }
452
453
454
455
456
457
458 @Test
459 public void testUpdateRefDetachedUnbornHead() throws Exception {
460 ObjectId ppid = db.resolve("refs/heads/master^");
461 writeSymref("HEAD", "refs/heads/unborn");
462 RefUpdate updateRef = db.updateRef("HEAD", true);
463 updateRef.setForceUpdate(true);
464 updateRef.setNewObjectId(ppid);
465 Result update = updateRef.update();
466 assertEquals(Result.NEW, update);
467 assertEquals(ppid, db.resolve("HEAD"));
468 Ref ref = db.exactRef("HEAD");
469 assertEquals("HEAD", ref.getName());
470 assertTrue("is detached", !ref.isSymbolic());
471
472
473 assertNull(db.resolve("refs/heads/unborn"));
474 ReflogReader reflogReader = db.getReflogReader("HEAD");
475 ReflogEntry e = reflogReader.getReverseEntries().get(0);
476 assertEquals(ObjectId.zeroId(), e.getOldId());
477 assertEquals(ppid, e.getNewId());
478 assertEquals("GIT_COMMITTER_EMAIL", e.getWho().getEmailAddress());
479 assertEquals("GIT_COMMITTER_NAME", e.getWho().getName());
480 assertEquals(1250379778000L, e.getWho().getWhen().getTime());
481 }
482
483
484
485
486
487
488
489 @Test
490 public void testDeleteLoosePacked() throws IOException {
491 ObjectId pid = db.resolve("refs/heads/c^");
492 RefUpdate updateRef = db.updateRef("refs/heads/c");
493 updateRef.setNewObjectId(pid);
494 updateRef.setForceUpdate(true);
495 Result update = updateRef.update();
496 assertEquals(Result.FORCED, update);
497
498
499 RefUpdate updateRef2 = db.updateRef("refs/heads/c");
500 updateRef2.setForceUpdate(true);
501 Result delete = updateRef2.delete();
502 assertEquals(Result.FORCED, delete);
503 assertNull(db.resolve("refs/heads/c"));
504 }
505
506
507
508
509
510
511 @Test
512 public void testUpdateRefNoChange() throws IOException {
513 ObjectId pid = db.resolve("refs/heads/master");
514 RefUpdate updateRef = db.updateRef("refs/heads/master");
515 updateRef.setNewObjectId(pid);
516 Result update = updateRef.update();
517 assertEquals(Result.NO_CHANGE, update);
518 assertEquals(pid, db.resolve("refs/heads/master"));
519 }
520
521
522
523
524
525
526
527
528
529
530
531 @Test
532 public void testRefsCacheAfterUpdate() throws Exception {
533
534 List<Ref> allRefs = db.getRefDatabase().getRefs();
535 ObjectId oldValue = db.resolve("HEAD");
536 ObjectId newValue = db.resolve("HEAD^");
537
538 RefUpdate updateRef = db.updateRef(Constants.HEAD);
539 updateRef.setForceUpdate(true);
540 updateRef.setNewObjectId(newValue);
541 Result update = updateRef.update();
542 assertEquals(Result.FORCED, update);
543
544
545 updateRef = db.updateRef(Constants.HEAD);
546 updateRef.setNewObjectId(oldValue);
547 update = updateRef.update();
548 assertEquals(Result.FAST_FORWARD, update);
549
550 allRefs = db.getRefDatabase().getRefs();
551 Ref master = getRef(allRefs, "refs/heads/master").get();
552 Ref head = getRef(allRefs, "HEAD").get();
553 assertEquals("refs/heads/master", master.getName());
554 assertEquals("HEAD", head.getName());
555 assertTrue("is symbolic reference", head.isSymbolic());
556 assertSame(master, head.getTarget());
557 }
558
559
560
561
562
563
564
565
566
567
568 @Test
569 public void testRefsCacheAfterUpdateLooseOnly() throws Exception {
570
571 List<Ref> allRefs = db.getRefDatabase().getRefs();
572 ObjectId oldValue = db.resolve("HEAD");
573 writeSymref(Constants.HEAD, "refs/heads/newref");
574 RefUpdate updateRef = db.updateRef(Constants.HEAD);
575 updateRef.setForceUpdate(true);
576 updateRef.setNewObjectId(oldValue);
577 Result update = updateRef.update();
578 assertEquals(Result.NEW, update);
579
580 allRefs = db.getRefDatabase().getRefs();
581 Ref head = getRef(allRefs, "HEAD").get();
582 Ref newref = getRef(allRefs, "refs/heads/newref").get();
583 assertEquals("refs/heads/newref", newref.getName());
584 assertEquals("HEAD", head.getName());
585 assertTrue("is symbolic reference", head.isSymbolic());
586 assertSame(newref, head.getTarget());
587 }
588
589
590
591
592
593
594 @Test
595 public void testUpdateRefLockFailureWrongOldValue() throws IOException {
596 ObjectId pid = db.resolve("refs/heads/master");
597 RefUpdate updateRef = db.updateRef("refs/heads/master");
598 updateRef.setNewObjectId(pid);
599 updateRef.setExpectedOldObjectId(db.resolve("refs/heads/master^"));
600 Result update = updateRef.update();
601 assertEquals(Result.LOCK_FAILURE, update);
602 assertEquals(pid, db.resolve("refs/heads/master"));
603 }
604
605
606
607
608
609
610 @Test
611 public void testUpdateRefForwardWithCheck1() throws IOException {
612 ObjectId ppid = db.resolve("refs/heads/master^");
613 ObjectId pid = db.resolve("refs/heads/master");
614
615 RefUpdate updateRef = db.updateRef("refs/heads/master");
616 updateRef.setNewObjectId(ppid);
617 updateRef.setForceUpdate(true);
618 Result update = updateRef.update();
619 assertEquals(Result.FORCED, update);
620 assertEquals(ppid, db.resolve("refs/heads/master"));
621
622
623 RefUpdate updateRef2 = db.updateRef("refs/heads/master");
624 updateRef2.setExpectedOldObjectId(ppid);
625 updateRef2.setNewObjectId(pid);
626 Result update2 = updateRef2.update();
627 assertEquals(Result.FAST_FORWARD, update2);
628 assertEquals(pid, db.resolve("refs/heads/master"));
629 }
630
631
632
633
634
635
636 @Test
637 public void testUpdateRefForwardWithCheck2() throws IOException {
638 ObjectId ppid = db.resolve("refs/heads/master^");
639 ObjectId pid = db.resolve("refs/heads/master");
640
641 RefUpdate updateRef = db.updateRef("refs/heads/master");
642 updateRef.setNewObjectId(ppid);
643 updateRef.setForceUpdate(true);
644 Result update = updateRef.update();
645 assertEquals(Result.FORCED, update);
646 assertEquals(ppid, db.resolve("refs/heads/master"));
647
648
649 try (RevWalk rw = new RevWalk(db)) {
650 RevCommit old = rw.parseCommit(ppid);
651 RefUpdate updateRef2 = db.updateRef("refs/heads/master");
652 updateRef2.setExpectedOldObjectId(old);
653 updateRef2.setNewObjectId(pid);
654 Result update2 = updateRef2.update();
655 assertEquals(Result.FAST_FORWARD, update2);
656 assertEquals(pid, db.resolve("refs/heads/master"));
657 }
658 }
659
660
661
662
663
664
665 @Test
666 public void testUpdateRefLockFailureLocked() throws IOException {
667 ObjectId opid = db.resolve("refs/heads/master");
668 ObjectId pid = db.resolve("refs/heads/master^");
669 RefUpdate updateRef = db.updateRef("refs/heads/master");
670 updateRef.setNewObjectId(pid);
671 LockFile lockFile1 = new LockFile(new File(db.getDirectory(),
672 "refs/heads/master"));
673 try {
674 assertTrue(lockFile1.lock());
675 Result update = updateRef.update();
676 assertEquals(Result.LOCK_FAILURE, update);
677 assertEquals(opid, db.resolve("refs/heads/master"));
678 LockFile lockFile2 = new LockFile(new File(db.getDirectory(),"refs/heads/master"));
679 assertFalse(lockFile2.lock());
680 } finally {
681 lockFile1.unlock();
682 }
683 }
684
685
686
687
688
689
690 @Test
691 public void testDeleteLoosePackedRejected() throws IOException {
692 ObjectId pid = db.resolve("refs/heads/c^");
693 ObjectId oldpid = db.resolve("refs/heads/c");
694 RefUpdate updateRef = db.updateRef("refs/heads/c");
695 updateRef.setNewObjectId(pid);
696 Result update = updateRef.update();
697 assertEquals(Result.REJECTED, update);
698 assertEquals(oldpid, db.resolve("refs/heads/c"));
699 }
700
701 @Test
702 public void testRenameBranchNoPreviousLog() throws IOException {
703 assertFalse("precondition, no log on old branchg", new File(db
704 .getDirectory(), "logs/refs/heads/b").exists());
705 ObjectId rb = db.resolve("refs/heads/b");
706 ObjectId oldHead = db.resolve(Constants.HEAD);
707 assertFalse(rb.equals(oldHead));
708 RefRename renameRef = db.renameRef("refs/heads/b",
709 "refs/heads/new/name");
710 Result result = renameRef.rename();
711 assertEquals(Result.RENAMED, result);
712 assertEquals(rb, db.resolve("refs/heads/new/name"));
713 assertNull(db.resolve("refs/heads/b"));
714 assertEquals(1, db.getReflogReader("new/name").getReverseEntries().size());
715 assertEquals("Branch: renamed b to new/name", db.getReflogReader("new/name")
716 .getLastEntry().getComment());
717 assertFalse(new File(db.getDirectory(), "logs/refs/heads/b").exists());
718 assertEquals(oldHead, db.resolve(Constants.HEAD));
719 }
720
721 @Test
722 public void testRenameBranchHasPreviousLog() throws IOException {
723 ObjectId rb = db.resolve("refs/heads/b");
724 ObjectId oldHead = db.resolve(Constants.HEAD);
725 assertFalse("precondition for this test, branch b != HEAD", rb
726 .equals(oldHead));
727 writeReflog(db, rb, "Just a message", "refs/heads/b");
728 assertTrue("log on old branch", new File(db.getDirectory(),
729 "logs/refs/heads/b").exists());
730 RefRename renameRef = db.renameRef("refs/heads/b",
731 "refs/heads/new/name");
732 Result result = renameRef.rename();
733 assertEquals(Result.RENAMED, result);
734 assertEquals(rb, db.resolve("refs/heads/new/name"));
735 assertNull(db.resolve("refs/heads/b"));
736 assertEquals(2, db.getReflogReader("new/name").getReverseEntries().size());
737 assertEquals("Branch: renamed b to new/name", db.getReflogReader("new/name")
738 .getLastEntry().getComment());
739 assertEquals("Just a message", db.getReflogReader("new/name")
740 .getReverseEntries().get(1).getComment());
741 assertFalse(new File(db.getDirectory(), "logs/refs/heads/b").exists());
742 assertEquals(oldHead, db.resolve(Constants.HEAD));
743 }
744
745 @Test
746 public void testRenameCurrentBranch() throws IOException {
747 ObjectId rb = db.resolve("refs/heads/b");
748 writeSymref(Constants.HEAD, "refs/heads/b");
749 ObjectId oldHead = db.resolve(Constants.HEAD);
750 assertEquals("internal test condition, b == HEAD", oldHead, rb);
751 writeReflog(db, rb, "Just a message", "refs/heads/b");
752 assertTrue("log on old branch", new File(db.getDirectory(),
753 "logs/refs/heads/b").exists());
754 RefRename renameRef = db.renameRef("refs/heads/b",
755 "refs/heads/new/name");
756 Result result = renameRef.rename();
757 assertEquals(Result.RENAMED, result);
758 assertEquals(rb, db.resolve("refs/heads/new/name"));
759 assertNull(db.resolve("refs/heads/b"));
760 assertEquals("Branch: renamed b to new/name", db.getReflogReader(
761 "new/name").getLastEntry().getComment());
762 assertFalse(new File(db.getDirectory(), "logs/refs/heads/b").exists());
763 assertEquals(rb, db.resolve(Constants.HEAD));
764 assertEquals(2, db.getReflogReader("new/name").getReverseEntries().size());
765 assertEquals("Branch: renamed b to new/name", db.getReflogReader("new/name").getReverseEntries().get(0).getComment());
766 assertEquals("Just a message", db.getReflogReader("new/name").getReverseEntries().get(1).getComment());
767 }
768
769 @Test
770 public void testRenameBranchAlsoInPack() throws IOException {
771 ObjectId rb = db.resolve("refs/heads/b");
772 ObjectId rb2 = db.resolve("refs/heads/b~1");
773 assertEquals(Ref.Storage.PACKED, db.exactRef("refs/heads/b").getStorage());
774 RefUpdate updateRef = db.updateRef("refs/heads/b");
775 updateRef.setNewObjectId(rb2);
776 updateRef.setForceUpdate(true);
777 Result update = updateRef.update();
778 assertEquals("internal check new ref is loose", Result.FORCED, update);
779 assertEquals(Ref.Storage.LOOSE, db.exactRef("refs/heads/b").getStorage());
780 writeReflog(db, rb, "Just a message", "refs/heads/b");
781 assertTrue("log on old branch", new File(db.getDirectory(),
782 "logs/refs/heads/b").exists());
783 RefRename renameRef = db.renameRef("refs/heads/b",
784 "refs/heads/new/name");
785 Result result = renameRef.rename();
786 assertEquals(Result.RENAMED, result);
787 assertEquals(rb2, db.resolve("refs/heads/new/name"));
788 assertNull(db.resolve("refs/heads/b"));
789 assertEquals("Branch: renamed b to new/name", db.getReflogReader(
790 "new/name").getLastEntry().getComment());
791 assertEquals(3, db.getReflogReader("refs/heads/new/name").getReverseEntries().size());
792 assertEquals("Branch: renamed b to new/name", db.getReflogReader("refs/heads/new/name").getReverseEntries().get(0).getComment());
793 assertEquals(0, db.getReflogReader("HEAD").getReverseEntries().size());
794
795 assertFalse(new File(db.getDirectory(), "logs/refs/heads/b").exists());
796
797
798
799 try (Repository ndb = new FileRepository(db.getDirectory())) {
800 assertEquals(rb2, ndb.resolve("refs/heads/new/name"));
801 assertNull(ndb.resolve("refs/heads/b"));
802 }
803 }
804
805 public void tryRenameWhenLocked(String toLock, String fromName,
806 String toName, String headPointsTo) throws IOException {
807
808 writeSymref(Constants.HEAD, headPointsTo);
809 ObjectId oldfromId = db.resolve(fromName);
810 ObjectId oldHeadId = db.resolve(Constants.HEAD);
811 writeReflog(db, oldfromId, "Just a message", fromName);
812 List<ReflogEntry> oldFromLog = db
813 .getReflogReader(fromName).getReverseEntries();
814 List<ReflogEntry> oldHeadLog = oldHeadId != null ? db
815 .getReflogReader(Constants.HEAD).getReverseEntries() : null;
816
817 assertTrue("internal check, we have a log", new File(db.getDirectory(),
818 "logs/" + fromName).exists());
819
820
821 LockFile lockFile = new LockFile(new File(db.getDirectory(), toLock));
822 try {
823 assertTrue(lockFile.lock());
824
825
826 RefRename renameRef = db.renameRef(fromName, toName);
827 Result result = renameRef.rename();
828 assertEquals(Result.LOCK_FAILURE, result);
829
830
831 assertExists(false, toName);
832 if (!toLock.equals(toName))
833 assertExists(false, toName + LOCK_SUFFIX);
834 assertExists(true, toLock + LOCK_SUFFIX);
835 if (!toLock.equals(fromName))
836 assertExists(false, "logs/" + fromName + LOCK_SUFFIX);
837 assertExists(false, "logs/" + toName + LOCK_SUFFIX);
838 assertEquals(oldHeadId, db.resolve(Constants.HEAD));
839 assertEquals(oldfromId, db.resolve(fromName));
840 assertNull(db.resolve(toName));
841 assertEquals(oldFromLog.toString(), db.getReflogReader(fromName)
842 .getReverseEntries().toString());
843 if (oldHeadId != null && oldHeadLog != null)
844 assertEquals(oldHeadLog.toString(), db.getReflogReader(
845 Constants.HEAD).getReverseEntries().toString());
846 } finally {
847 lockFile.unlock();
848 }
849 }
850
851 private void assertExists(boolean positive, String toName) {
852 assertEquals(toName + (positive ? " " : " does not ") + "exist",
853 positive, new File(db.getDirectory(), toName).exists());
854 }
855
856 @Test
857 public void testRenameBranchCannotLockAFileHEADisFromLockHEAD()
858 throws IOException {
859 tryRenameWhenLocked("HEAD", "refs/heads/b", "refs/heads/new/name",
860 "refs/heads/b");
861 }
862
863 @Test
864 public void testRenameBranchCannotLockAFileHEADisFromLockFrom()
865 throws IOException {
866 tryRenameWhenLocked("refs/heads/b", "refs/heads/b",
867 "refs/heads/new/name", "refs/heads/b");
868 }
869
870 @Test
871 public void testRenameBranchCannotLockAFileHEADisFromLockTo()
872 throws IOException {
873 tryRenameWhenLocked("refs/heads/new/name", "refs/heads/b",
874 "refs/heads/new/name", "refs/heads/b");
875 }
876
877 @Test
878 public void testRenameBranchCannotLockAFileHEADisToLockFrom()
879 throws IOException {
880 tryRenameWhenLocked("refs/heads/b", "refs/heads/b",
881 "refs/heads/new/name", "refs/heads/new/name");
882 }
883
884 @Test
885 public void testRenameBranchCannotLockAFileHEADisToLockTo()
886 throws IOException {
887 tryRenameWhenLocked("refs/heads/new/name", "refs/heads/b",
888 "refs/heads/new/name", "refs/heads/new/name");
889 }
890
891 @Test
892 public void testRenameBranchCannotLockAFileHEADisOtherLockFrom()
893 throws IOException {
894 tryRenameWhenLocked("refs/heads/b", "refs/heads/b",
895 "refs/heads/new/name", "refs/heads/a");
896 }
897
898 @Test
899 public void testRenameBranchCannotLockAFileHEADisOtherLockTo()
900 throws IOException {
901 tryRenameWhenLocked("refs/heads/new/name", "refs/heads/b",
902 "refs/heads/new/name", "refs/heads/a");
903 }
904
905 @Test
906 public void testRenameRefNameColission1avoided() throws IOException {
907
908 ObjectId rb = db.resolve("refs/heads/b");
909 writeSymref(Constants.HEAD, "refs/heads/a");
910 RefUpdate updateRef = db.updateRef("refs/heads/a");
911 updateRef.setNewObjectId(rb);
912 updateRef.setRefLogMessage("Setup", false);
913 assertEquals(Result.FAST_FORWARD, updateRef.update());
914 ObjectId oldHead = db.resolve(Constants.HEAD);
915 assertEquals(oldHead, rb);
916 writeReflog(db, rb, "Just a message", "refs/heads/a");
917 assertTrue("internal check, we have a log", new File(db.getDirectory(),
918 "logs/refs/heads/a").exists());
919
920
921 RefRename renameRef = db.renameRef("refs/heads/a", "refs/heads/a/b");
922 Result result = renameRef.rename();
923 assertEquals(Result.RENAMED, result);
924 assertNull(db.resolve("refs/heads/a"));
925 assertEquals(rb, db.resolve("refs/heads/a/b"));
926 assertEquals(3, db.getReflogReader("a/b").getReverseEntries().size());
927 assertEquals("Branch: renamed a to a/b", db.getReflogReader("a/b")
928 .getReverseEntries().get(0).getComment());
929 assertEquals("Just a message", db.getReflogReader("a/b")
930 .getReverseEntries().get(1).getComment());
931 assertEquals("Setup", db.getReflogReader("a/b").getReverseEntries()
932 .get(2).getComment());
933
934 assertEquals("Branch: renamed a to a/b", db.getReflogReader("HEAD")
935 .getReverseEntries().get(0).getComment());
936 }
937
938 @Test
939 public void testRenameRefNameColission2avoided() throws IOException {
940
941 ObjectId rb = db.resolve("refs/heads/b");
942 writeSymref(Constants.HEAD, "refs/heads/prefix/a");
943 RefUpdate updateRef = db.updateRef("refs/heads/prefix/a");
944 updateRef.setNewObjectId(rb);
945 updateRef.setRefLogMessage("Setup", false);
946 updateRef.setForceUpdate(true);
947 assertEquals(Result.FORCED, updateRef.update());
948 ObjectId oldHead = db.resolve(Constants.HEAD);
949 assertEquals(oldHead, rb);
950 writeReflog(db, rb, "Just a message", "refs/heads/prefix/a");
951 assertTrue("internal check, we have a log", new File(db.getDirectory(),
952 "logs/refs/heads/prefix/a").exists());
953
954
955 RefRename renameRef = db.renameRef("refs/heads/prefix/a",
956 "refs/heads/prefix");
957 Result result = renameRef.rename();
958 assertEquals(Result.RENAMED, result);
959
960 assertNull(db.resolve("refs/heads/prefix/a"));
961 assertEquals(rb, db.resolve("refs/heads/prefix"));
962 assertEquals(3, db.getReflogReader("prefix").getReverseEntries().size());
963 assertEquals("Branch: renamed prefix/a to prefix", db.getReflogReader(
964 "prefix").getReverseEntries().get(0).getComment());
965 assertEquals("Just a message", db.getReflogReader("prefix")
966 .getReverseEntries().get(1).getComment());
967 assertEquals("Setup", db.getReflogReader("prefix").getReverseEntries()
968 .get(2).getComment());
969 assertEquals("Branch: renamed prefix/a to prefix", db.getReflogReader(
970 "HEAD").getReverseEntries().get(0).getComment());
971 }
972
973 @Test
974 public void testCreateMissingObject() throws IOException {
975 String name = "refs/heads/abc";
976 ObjectId bad =
977 ObjectId.fromString("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef");
978 RefUpdate ru = db.updateRef(name);
979 ru.setNewObjectId(bad);
980 Result update = ru.update();
981 assertEquals(Result.REJECTED_MISSING_OBJECT, update);
982
983 Ref ref = db.exactRef(name);
984 assertNull(ref);
985 }
986
987 @Test
988 public void testUpdateMissingObject() throws IOException {
989 String name = "refs/heads/abc";
990 RefUpdate ru = updateRef(name);
991 Result update = ru.update();
992 assertEquals(Result.NEW, update);
993 ObjectId oldId = ru.getNewObjectId();
994
995 ObjectId bad =
996 ObjectId.fromString("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef");
997 ru = db.updateRef(name);
998 ru.setNewObjectId(bad);
999 update = ru.update();
1000 assertEquals(Result.REJECTED_MISSING_OBJECT, update);
1001
1002 Ref ref = db.exactRef(name);
1003 assertNotNull(ref);
1004 assertEquals(oldId, ref.getObjectId());
1005 }
1006
1007 @Test
1008 public void testForceUpdateMissingObject() throws IOException {
1009 String name = "refs/heads/abc";
1010 RefUpdate ru = updateRef(name);
1011 Result update = ru.update();
1012 assertEquals(Result.NEW, update);
1013 ObjectId oldId = ru.getNewObjectId();
1014
1015 ObjectId bad =
1016 ObjectId.fromString("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef");
1017 ru = db.updateRef(name);
1018 ru.setNewObjectId(bad);
1019 update = ru.forceUpdate();
1020 assertEquals(Result.REJECTED_MISSING_OBJECT, update);
1021
1022 Ref ref = db.exactRef(name);
1023 assertNotNull(ref);
1024 assertEquals(oldId, ref.getObjectId());
1025 }
1026
1027 private static void writeReflog(Repository db, ObjectId newId, String msg,
1028 String refName) throws IOException {
1029 RefDirectory refs = (RefDirectory) db.getRefDatabase();
1030 RefDirectoryUpdate update = refs.newUpdate(refName, true);
1031 update.setNewObjectId(newId);
1032 refs.log(false, update, msg, true);
1033 }
1034
1035 private static class SubclassedId extends ObjectId {
1036 SubclassedId(AnyObjectId src) {
1037 super(src);
1038 }
1039 }
1040 }