Add support for creating detached heads
[jgit.git] / org.eclipse.jgit.test / tst / org / eclipse / jgit / lib / RefUpdateTest.java
blobd851528cdd7c347007f561a912b1765057afaccd
1 /*
2 * Copyright (C) 2008, Charles O'Farrell <charleso@charleso.org>
3 * Copyright (C) 2008-2009, Robin Rosenberg <robin.rosenberg@dewire.com>
4 * and other copyright owners as documented in the project's IP log.
6 * This program and the accompanying materials are made available
7 * under the terms of the Eclipse Distribution License v1.0 which
8 * accompanies this distribution, is reproduced below, and is
9 * available at http://www.eclipse.org/org/documents/edl-v10.php
11 * All rights reserved.
13 * Redistribution and use in source and binary forms, with or
14 * without modification, are permitted provided that the following
15 * conditions are met:
17 * - Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
20 * - Redistributions in binary form must reproduce the above
21 * copyright notice, this list of conditions and the following
22 * disclaimer in the documentation and/or other materials provided
23 * with the distribution.
25 * - Neither the name of the Eclipse Foundation, Inc. nor the
26 * names of its contributors may be used to endorse or promote
27 * products derived from this software without specific prior
28 * written permission.
30 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
31 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
32 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
33 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
35 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
36 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
37 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
38 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
39 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
41 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
42 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45 package org.eclipse.jgit.lib;
47 import java.io.File;
48 import java.io.IOException;
49 import java.util.List;
50 import java.util.Map;
51 import java.util.Map.Entry;
53 import org.eclipse.jgit.lib.RefUpdate.Result;
54 import org.eclipse.jgit.revwalk.RevCommit;
55 import org.eclipse.jgit.revwalk.RevWalk;
57 public class RefUpdateTest extends SampleDataRepositoryTestCase {
59 private RefUpdate updateRef(final String name) throws IOException {
60 final RefUpdate ref = db.updateRef(name);
61 ref.setNewObjectId(db.resolve(Constants.HEAD));
62 return ref;
65 private void delete(final RefUpdate ref, final Result expected)
66 throws IOException {
67 delete(ref, expected, true, true);
70 private void delete(final RefUpdate ref, final Result expected,
71 final boolean exists, final boolean removed) throws IOException {
72 assertEquals(exists, db.getAllRefs().containsKey(ref.getName()));
73 assertEquals(expected, ref.delete());
74 assertEquals(!removed, db.getAllRefs().containsKey(ref.getName()));
77 public void testNoCacheObjectIdSubclass() throws IOException {
78 final String newRef = "refs/heads/abc";
79 final RefUpdate ru = updateRef(newRef);
80 final RevCommit newid = new RevCommit(ru.getNewObjectId()) {
81 // empty
83 ru.setNewObjectId(newid);
84 Result update = ru.update();
85 assertEquals(Result.NEW, update);
86 final Ref r = db.getAllRefs().get(newRef);
87 assertNotNull(r);
88 assertEquals(newRef, r.getName());
89 assertNotNull(r.getObjectId());
90 assertNotSame(newid, r.getObjectId());
91 assertSame(ObjectId.class, r.getObjectId().getClass());
92 assertEquals(newid.copy(), r.getObjectId());
93 List<org.eclipse.jgit.lib.ReflogReader.Entry> reverseEntries1 = db.getReflogReader("refs/heads/abc").getReverseEntries();
94 org.eclipse.jgit.lib.ReflogReader.Entry entry1 = reverseEntries1.get(0);
95 assertEquals(1, reverseEntries1.size());
96 assertEquals(ObjectId.zeroId(), entry1.getOldId());
97 assertEquals(r.getObjectId(), entry1.getNewId());
98 assertEquals(new PersonIdent(db).toString(), entry1.getWho().toString());
99 assertEquals("", entry1.getComment());
100 List<org.eclipse.jgit.lib.ReflogReader.Entry> reverseEntries2 = db.getReflogReader("HEAD").getReverseEntries();
101 assertEquals(0, reverseEntries2.size());
104 public void testNewNamespaceConflictWithLoosePrefixNameExists()
105 throws IOException {
106 final String newRef = "refs/heads/z";
107 final RefUpdate ru = updateRef(newRef);
108 final RevCommit newid = new RevCommit(ru.getNewObjectId()) {
109 // empty
111 ru.setNewObjectId(newid);
112 Result update = ru.update();
113 assertEquals(Result.NEW, update);
114 // end setup
115 final String newRef2 = "refs/heads/z/a";
116 final RefUpdate ru2 = updateRef(newRef2);
117 final RevCommit newid2 = new RevCommit(ru2.getNewObjectId()) {
118 // empty
120 ru.setNewObjectId(newid2);
121 Result update2 = ru2.update();
122 assertEquals(Result.LOCK_FAILURE, update2);
123 assertEquals(1, db.getReflogReader("refs/heads/z").getReverseEntries().size());
124 assertEquals(0, db.getReflogReader("HEAD").getReverseEntries().size());
127 public void testNewNamespaceConflictWithPackedPrefixNameExists()
128 throws IOException {
129 final String newRef = "refs/heads/master/x";
130 final RefUpdate ru = updateRef(newRef);
131 final RevCommit newid = new RevCommit(ru.getNewObjectId()) {
132 // empty
134 ru.setNewObjectId(newid);
135 Result update = ru.update();
136 assertEquals(Result.LOCK_FAILURE, update);
137 assertNull(db.getReflogReader("refs/heads/master/x"));
138 assertEquals(0, db.getReflogReader("HEAD").getReverseEntries().size());
141 public void testNewNamespaceConflictWithLoosePrefixOfExisting()
142 throws IOException {
143 final String newRef = "refs/heads/z/a";
144 final RefUpdate ru = updateRef(newRef);
145 final RevCommit newid = new RevCommit(ru.getNewObjectId()) {
146 // empty
148 ru.setNewObjectId(newid);
149 Result update = ru.update();
150 assertEquals(Result.NEW, update);
151 // end setup
152 final String newRef2 = "refs/heads/z";
153 final RefUpdate ru2 = updateRef(newRef2);
154 final RevCommit newid2 = new RevCommit(ru2.getNewObjectId()) {
155 // empty
157 ru.setNewObjectId(newid2);
158 Result update2 = ru2.update();
159 assertEquals(Result.LOCK_FAILURE, update2);
160 assertEquals(1, db.getReflogReader("refs/heads/z/a").getReverseEntries().size());
161 assertNull(db.getReflogReader("refs/heads/z"));
162 assertEquals(0, db.getReflogReader("HEAD").getReverseEntries().size());
165 public void testNewNamespaceConflictWithPackedPrefixOfExisting()
166 throws IOException {
167 final String newRef = "refs/heads/prefix";
168 final RefUpdate ru = updateRef(newRef);
169 final RevCommit newid = new RevCommit(ru.getNewObjectId()) {
170 // empty
172 ru.setNewObjectId(newid);
173 Result update = ru.update();
174 assertEquals(Result.LOCK_FAILURE, update);
175 assertNull(db.getReflogReader("refs/heads/prefix"));
176 assertEquals(0, db.getReflogReader("HEAD").getReverseEntries().size());
180 * Delete a ref that is pointed to by HEAD
182 * @throws IOException
184 public void testDeleteHEADreferencedRef() throws IOException {
185 ObjectId pid = db.resolve("refs/heads/master^");
186 RefUpdate updateRef = db.updateRef("refs/heads/master");
187 updateRef.setNewObjectId(pid);
188 updateRef.setForceUpdate(true);
189 Result update = updateRef.update();
190 assertEquals(Result.FORCED, update); // internal
192 RefUpdate updateRef2 = db.updateRef("refs/heads/master");
193 Result delete = updateRef2.delete();
194 assertEquals(Result.REJECTED_CURRENT_BRANCH, delete);
195 assertEquals(pid, db.resolve("refs/heads/master"));
196 assertEquals(1,db.getReflogReader("refs/heads/master").getReverseEntries().size());
197 assertEquals(0,db.getReflogReader("HEAD").getReverseEntries().size());
200 public void testLooseDelete() throws IOException {
201 final String newRef = "refs/heads/abc";
202 RefUpdate ref = updateRef(newRef);
203 ref.update(); // create loose ref
204 ref = updateRef(newRef); // refresh
205 delete(ref, Result.NO_CHANGE);
206 assertNull(db.getReflogReader("refs/heads/abc"));
209 public void testDeleteHead() throws IOException {
210 final RefUpdate ref = updateRef(Constants.HEAD);
211 delete(ref, Result.REJECTED_CURRENT_BRANCH, true, false);
212 assertEquals(0, db.getReflogReader("refs/heads/master").getReverseEntries().size());
213 assertEquals(0, db.getReflogReader("HEAD").getReverseEntries().size());
217 * Delete a loose ref and make sure the directory in refs is deleted too,
218 * and the reflog dir too
220 * @throws IOException
222 public void testDeleteLooseAndItsDirectory() throws IOException {
223 ObjectId pid = db.resolve("refs/heads/c^");
224 RefUpdate updateRef = db.updateRef("refs/heads/z/c");
225 updateRef.setNewObjectId(pid);
226 updateRef.setForceUpdate(true);
227 updateRef.setRefLogMessage("new test ref", false);
228 Result update = updateRef.update();
229 assertEquals(Result.NEW, update); // internal
230 assertTrue(new File(db.getDirectory(), Constants.R_HEADS + "z")
231 .exists());
232 assertTrue(new File(db.getDirectory(), "logs/refs/heads/z").exists());
234 // The real test here
235 RefUpdate updateRef2 = db.updateRef("refs/heads/z/c");
236 updateRef2.setForceUpdate(true);
237 Result delete = updateRef2.delete();
238 assertEquals(Result.FORCED, delete);
239 assertNull(db.resolve("refs/heads/z/c"));
240 assertFalse(new File(db.getDirectory(), Constants.R_HEADS + "z")
241 .exists());
242 assertFalse(new File(db.getDirectory(), "logs/refs/heads/z").exists());
245 public void testDeleteNotFound() throws IOException {
246 final RefUpdate ref = updateRef("refs/heads/xyz");
247 delete(ref, Result.NEW, false, true);
250 public void testDeleteFastForward() throws IOException {
251 final RefUpdate ref = updateRef("refs/heads/a");
252 delete(ref, Result.FAST_FORWARD);
255 public void testDeleteForce() throws IOException {
256 final RefUpdate ref = db.updateRef("refs/heads/b");
257 ref.setNewObjectId(db.resolve("refs/heads/a"));
258 delete(ref, Result.REJECTED, true, false);
259 ref.setForceUpdate(true);
260 delete(ref, Result.FORCED);
263 public void testRefKeySameAsOrigName() {
264 Map<String, Ref> allRefs = db.getAllRefs();
265 for (Entry<String, Ref> e : allRefs.entrySet()) {
266 assertEquals(e.getKey(), e.getValue().getOrigName());
272 * Try modify a ref forward, fast forward
274 * @throws IOException
276 public void testUpdateRefForward() throws IOException {
277 ObjectId ppid = db.resolve("refs/heads/master^");
278 ObjectId pid = db.resolve("refs/heads/master");
280 RefUpdate updateRef = db.updateRef("refs/heads/master");
281 updateRef.setNewObjectId(ppid);
282 updateRef.setForceUpdate(true);
283 Result update = updateRef.update();
284 assertEquals(Result.FORCED, update);
285 assertEquals(ppid, db.resolve("refs/heads/master"));
287 // real test
288 RefUpdate updateRef2 = db.updateRef("refs/heads/master");
289 updateRef2.setNewObjectId(pid);
290 Result update2 = updateRef2.update();
291 assertEquals(Result.FAST_FORWARD, update2);
292 assertEquals(pid, db.resolve("refs/heads/master"));
296 * Update the HEAD ref. Only it should be changed, not what it points to.
298 * @throws Exception
300 public void testUpdateRefDetached() throws Exception {
301 ObjectId pid = db.resolve("refs/heads/master");
302 ObjectId ppid = db.resolve("refs/heads/master^");
303 RefUpdate updateRef = db.updateRef("HEAD", true);
304 updateRef.setForceUpdate(true);
305 updateRef.setNewObjectId(ppid);
306 Result update = updateRef.update();
307 assertEquals(Result.FORCED, update);
308 assertEquals(ppid, db.resolve("HEAD"));
309 Ref ref = db.getRef("HEAD");
310 assertEquals("HEAD", ref.getName());
311 assertEquals("HEAD", ref.getOrigName());
313 // the branch HEAD referred to is left untouched
314 assertEquals(pid, db.resolve("refs/heads/master"));
315 ReflogReader reflogReader = new ReflogReader(db, "HEAD");
316 org.eclipse.jgit.lib.ReflogReader.Entry e = reflogReader.getReverseEntries().get(0);
317 assertEquals(pid, e.getOldId());
318 assertEquals(ppid, e.getNewId());
319 assertEquals("GIT_COMMITTER_EMAIL", e.getWho().getEmailAddress());
320 assertEquals("GIT_COMMITTER_NAME", e.getWho().getName());
321 assertEquals(1250379778000L, e.getWho().getWhen().getTime());
325 * Update the HEAD ref when the referenced branch is unborn
327 * @throws Exception
329 public void testUpdateRefDetachedUnbornHead() throws Exception {
330 ObjectId ppid = db.resolve("refs/heads/master^");
331 db.writeSymref("HEAD", "refs/heads/unborn");
332 RefUpdate updateRef = db.updateRef("HEAD", true);
333 updateRef.setForceUpdate(true);
334 updateRef.setNewObjectId(ppid);
335 Result update = updateRef.update();
336 assertEquals(Result.NEW, update);
337 assertEquals(ppid, db.resolve("HEAD"));
338 Ref ref = db.getRef("HEAD");
339 assertEquals("HEAD", ref.getName());
340 assertEquals("HEAD", ref.getOrigName());
342 // the branch HEAD referred to is left untouched
343 assertNull(db.resolve("refs/heads/unborn"));
344 ReflogReader reflogReader = new ReflogReader(db, "HEAD");
345 org.eclipse.jgit.lib.ReflogReader.Entry e = reflogReader.getReverseEntries().get(0);
346 assertEquals(ObjectId.zeroId(), e.getOldId());
347 assertEquals(ppid, e.getNewId());
348 assertEquals("GIT_COMMITTER_EMAIL", e.getWho().getEmailAddress());
349 assertEquals("GIT_COMMITTER_NAME", e.getWho().getName());
350 assertEquals(1250379778000L, e.getWho().getWhen().getTime());
354 * Delete a ref that exists both as packed and loose. Make sure the ref
355 * cannot be resolved after delete.
357 * @throws IOException
359 public void testDeleteLoosePacked() throws IOException {
360 ObjectId pid = db.resolve("refs/heads/c^");
361 RefUpdate updateRef = db.updateRef("refs/heads/c");
362 updateRef.setNewObjectId(pid);
363 updateRef.setForceUpdate(true);
364 Result update = updateRef.update();
365 assertEquals(Result.FORCED, update); // internal
367 // The real test here
368 RefUpdate updateRef2 = db.updateRef("refs/heads/c");
369 updateRef2.setForceUpdate(true);
370 Result delete = updateRef2.delete();
371 assertEquals(Result.FORCED, delete);
372 assertNull(db.resolve("refs/heads/c"));
376 * Try modify a ref to same
378 * @throws IOException
380 public void testUpdateRefNoChange() throws IOException {
381 ObjectId pid = db.resolve("refs/heads/master");
382 RefUpdate updateRef = db.updateRef("refs/heads/master");
383 updateRef.setNewObjectId(pid);
384 Result update = updateRef.update();
385 assertEquals(Result.NO_CHANGE, update);
386 assertEquals(pid, db.resolve("refs/heads/master"));
390 * Test case originating from
391 * <a href="http://bugs.eclipse.org/285991">bug 285991</a>
393 * Make sure the in memory cache is updated properly after
394 * update of symref. This one did not fail because the
395 * ref was packed due to implementation issues.
397 * @throws Exception
399 public void testRefsCacheAfterUpdate() throws Exception {
400 // Do not use the defalt repo for this case.
401 Map<String, Ref> allRefs = db.getAllRefs();
402 ObjectId oldValue = db.resolve("HEAD");
403 ObjectId newValue = db.resolve("HEAD^");
404 // first make HEAD refer to loose ref
405 RefUpdate updateRef = db.updateRef(Constants.HEAD);
406 updateRef.setForceUpdate(true);
407 updateRef.setNewObjectId(newValue);
408 Result update = updateRef.update();
409 assertEquals(Result.FORCED, update);
411 // now update that ref
412 updateRef = db.updateRef(Constants.HEAD);
413 updateRef.setForceUpdate(true);
414 updateRef.setNewObjectId(oldValue);
415 update = updateRef.update();
416 assertEquals(Result.FAST_FORWARD, update);
417 allRefs = db.getAllRefs();
418 assertEquals("refs/heads/master", allRefs.get("refs/heads/master").getName());
419 assertEquals("refs/heads/master", allRefs.get("refs/heads/master").getOrigName());
420 assertEquals("refs/heads/master", allRefs.get("HEAD").getName());
421 assertEquals("HEAD", allRefs.get("HEAD").getOrigName());
425 * Test case originating from
426 * <a href="http://bugs.eclipse.org/285991">bug 285991</a>
428 * Make sure the in memory cache is updated properly after
429 * update of symref.
431 * @throws Exception
433 public void testRefsCacheAfterUpdateLoosOnly() throws Exception {
434 // Do not use the defalt repo for this case.
435 Map<String, Ref> allRefs = db.getAllRefs();
436 ObjectId oldValue = db.resolve("HEAD");
437 db.writeSymref(Constants.HEAD, "refs/heads/newref");
438 RefUpdate updateRef = db.updateRef(Constants.HEAD);
439 updateRef.setForceUpdate(true);
440 updateRef.setNewObjectId(oldValue);
441 Result update = updateRef.update();
442 assertEquals(Result.NEW, update);
443 allRefs = db.getAllRefs();
444 assertEquals("refs/heads/newref", allRefs.get("HEAD").getName());
445 assertEquals("HEAD", allRefs.get("HEAD").getOrigName());
446 assertEquals("refs/heads/newref", allRefs.get("refs/heads/newref").getName());
447 assertEquals("refs/heads/newref", allRefs.get("refs/heads/newref").getOrigName());
451 * Try modify a ref, but get wrong expected old value
453 * @throws IOException
455 public void testUpdateRefLockFailureWrongOldValue() throws IOException {
456 ObjectId pid = db.resolve("refs/heads/master");
457 RefUpdate updateRef = db.updateRef("refs/heads/master");
458 updateRef.setNewObjectId(pid);
459 updateRef.setExpectedOldObjectId(db.resolve("refs/heads/master^"));
460 Result update = updateRef.update();
461 assertEquals(Result.LOCK_FAILURE, update);
462 assertEquals(pid, db.resolve("refs/heads/master"));
466 * Try modify a ref forward, fast forward, checking old value first
468 * @throws IOException
470 public void testUpdateRefForwardWithCheck1() throws IOException {
471 ObjectId ppid = db.resolve("refs/heads/master^");
472 ObjectId pid = db.resolve("refs/heads/master");
474 RefUpdate updateRef = db.updateRef("refs/heads/master");
475 updateRef.setNewObjectId(ppid);
476 updateRef.setForceUpdate(true);
477 Result update = updateRef.update();
478 assertEquals(Result.FORCED, update);
479 assertEquals(ppid, db.resolve("refs/heads/master"));
481 // real test
482 RefUpdate updateRef2 = db.updateRef("refs/heads/master");
483 updateRef2.setExpectedOldObjectId(ppid);
484 updateRef2.setNewObjectId(pid);
485 Result update2 = updateRef2.update();
486 assertEquals(Result.FAST_FORWARD, update2);
487 assertEquals(pid, db.resolve("refs/heads/master"));
491 * Try modify a ref forward, fast forward, checking old commit first
493 * @throws IOException
495 public void testUpdateRefForwardWithCheck2() throws IOException {
496 ObjectId ppid = db.resolve("refs/heads/master^");
497 ObjectId pid = db.resolve("refs/heads/master");
499 RefUpdate updateRef = db.updateRef("refs/heads/master");
500 updateRef.setNewObjectId(ppid);
501 updateRef.setForceUpdate(true);
502 Result update = updateRef.update();
503 assertEquals(Result.FORCED, update);
504 assertEquals(ppid, db.resolve("refs/heads/master"));
506 // real test
507 RevCommit old = new RevWalk(db).parseCommit(ppid);
508 RefUpdate updateRef2 = db.updateRef("refs/heads/master");
509 updateRef2.setExpectedOldObjectId(old);
510 updateRef2.setNewObjectId(pid);
511 Result update2 = updateRef2.update();
512 assertEquals(Result.FAST_FORWARD, update2);
513 assertEquals(pid, db.resolve("refs/heads/master"));
517 * Try modify a ref that is locked
519 * @throws IOException
521 public void testUpdateRefLockFailureLocked() throws IOException {
522 ObjectId opid = db.resolve("refs/heads/master");
523 ObjectId pid = db.resolve("refs/heads/master^");
524 RefUpdate updateRef = db.updateRef("refs/heads/master");
525 updateRef.setNewObjectId(pid);
526 LockFile lockFile1 = new LockFile(new File(db.getDirectory(),"refs/heads/master"));
527 try {
528 assertTrue(lockFile1.lock()); // precondition to test
529 Result update = updateRef.update();
530 assertEquals(Result.LOCK_FAILURE, update);
531 assertEquals(opid, db.resolve("refs/heads/master"));
532 LockFile lockFile2 = new LockFile(new File(db.getDirectory(),"refs/heads/master"));
533 assertFalse(lockFile2.lock()); // was locked, still is
534 } finally {
535 lockFile1.unlock();
540 * Try to delete a ref. Delete requires force.
542 * @throws IOException
544 public void testDeleteLoosePackedRejected() throws IOException {
545 ObjectId pid = db.resolve("refs/heads/c^");
546 ObjectId oldpid = db.resolve("refs/heads/c");
547 RefUpdate updateRef = db.updateRef("refs/heads/c");
548 updateRef.setNewObjectId(pid);
549 Result update = updateRef.update();
550 assertEquals(Result.REJECTED, update);
551 assertEquals(oldpid, db.resolve("refs/heads/c"));
554 public void testRenameBranchNoPreviousLog() throws IOException {
555 assertFalse("precondition, no log on old branchg", new File(db
556 .getDirectory(), "logs/refs/heads/b").exists());
557 ObjectId rb = db.resolve("refs/heads/b");
558 ObjectId oldHead = db.resolve(Constants.HEAD);
559 assertFalse(rb.equals(oldHead)); // assumption for this test
560 RefRename renameRef = db.renameRef("refs/heads/b",
561 "refs/heads/new/name");
562 Result result = renameRef.rename();
563 assertEquals(Result.RENAMED, result);
564 assertEquals(rb, db.resolve("refs/heads/new/name"));
565 assertNull(db.resolve("refs/heads/b"));
566 assertEquals(1, db.getReflogReader("new/name").getReverseEntries().size());
567 assertEquals("Branch: renamed b to new/name", db.getReflogReader("new/name")
568 .getLastEntry().getComment());
569 assertFalse(new File(db.getDirectory(), "logs/refs/heads/b").exists());
570 assertEquals(oldHead, db.resolve(Constants.HEAD)); // unchanged
573 public void testRenameBranchHasPreviousLog() throws IOException {
574 ObjectId rb = db.resolve("refs/heads/b");
575 ObjectId oldHead = db.resolve(Constants.HEAD);
576 assertFalse("precondition for this test, branch b != HEAD", rb
577 .equals(oldHead));
578 RefLogWriter.writeReflog(db, rb, rb, "Just a message", "refs/heads/b");
579 assertTrue("no log on old branch", new File(db.getDirectory(),
580 "logs/refs/heads/b").exists());
581 RefRename renameRef = db.renameRef("refs/heads/b",
582 "refs/heads/new/name");
583 Result result = renameRef.rename();
584 assertEquals(Result.RENAMED, result);
585 assertEquals(rb, db.resolve("refs/heads/new/name"));
586 assertNull(db.resolve("refs/heads/b"));
587 assertEquals(2, db.getReflogReader("new/name").getReverseEntries().size());
588 assertEquals("Branch: renamed b to new/name", db.getReflogReader("new/name")
589 .getLastEntry().getComment());
590 assertEquals("Just a message", db.getReflogReader("new/name")
591 .getReverseEntries().get(1).getComment());
592 assertFalse(new File(db.getDirectory(), "logs/refs/heads/b").exists());
593 assertEquals(oldHead, db.resolve(Constants.HEAD)); // unchanged
596 public void testRenameCurrentBranch() throws IOException {
597 ObjectId rb = db.resolve("refs/heads/b");
598 db.writeSymref(Constants.HEAD, "refs/heads/b");
599 ObjectId oldHead = db.resolve(Constants.HEAD);
600 assertTrue("internal test condition, b == HEAD", rb.equals(oldHead));
601 RefLogWriter.writeReflog(db, rb, rb, "Just a message", "refs/heads/b");
602 assertTrue("no log on old branch", new File(db.getDirectory(),
603 "logs/refs/heads/b").exists());
604 RefRename renameRef = db.renameRef("refs/heads/b",
605 "refs/heads/new/name");
606 Result result = renameRef.rename();
607 assertEquals(Result.RENAMED, result);
608 assertEquals(rb, db.resolve("refs/heads/new/name"));
609 assertNull(db.resolve("refs/heads/b"));
610 assertEquals("Branch: renamed b to new/name", db.getReflogReader(
611 "new/name").getLastEntry().getComment());
612 assertFalse(new File(db.getDirectory(), "logs/refs/heads/b").exists());
613 assertEquals(rb, db.resolve(Constants.HEAD));
614 assertEquals(2, db.getReflogReader("new/name").getReverseEntries().size());
615 assertEquals("Branch: renamed b to new/name", db.getReflogReader("new/name").getReverseEntries().get(0).getComment());
616 assertEquals("Just a message", db.getReflogReader("new/name").getReverseEntries().get(1).getComment());
619 public void testRenameBranchAlsoInPack() throws IOException {
620 ObjectId rb = db.resolve("refs/heads/b");
621 ObjectId rb2 = db.resolve("refs/heads/b~1");
622 assertEquals(Ref.Storage.PACKED, db.getRef("refs/heads/b").getStorage());
623 RefUpdate updateRef = db.updateRef("refs/heads/b");
624 updateRef.setNewObjectId(rb2);
625 updateRef.setForceUpdate(true);
626 Result update = updateRef.update();
627 assertEquals("internal check new ref is loose", Result.FORCED, update);
628 assertEquals(Ref.Storage.LOOSE_PACKED, db.getRef("refs/heads/b")
629 .getStorage());
630 RefLogWriter.writeReflog(db, rb, rb, "Just a message", "refs/heads/b");
631 assertTrue("no log on old branch", new File(db.getDirectory(),
632 "logs/refs/heads/b").exists());
633 RefRename renameRef = db.renameRef("refs/heads/b",
634 "refs/heads/new/name");
635 Result result = renameRef.rename();
636 assertEquals(Result.RENAMED, result);
637 assertEquals(rb2, db.resolve("refs/heads/new/name"));
638 assertNull(db.resolve("refs/heads/b"));
639 assertEquals("Branch: renamed b to new/name", db.getReflogReader(
640 "new/name").getLastEntry().getComment());
641 assertEquals(3, db.getReflogReader("refs/heads/new/name").getReverseEntries().size());
642 assertEquals("Branch: renamed b to new/name", db.getReflogReader("refs/heads/new/name").getReverseEntries().get(0).getComment());
643 assertEquals(0, db.getReflogReader("HEAD").getReverseEntries().size());
644 // make sure b's log file is gone too.
645 assertFalse(new File(db.getDirectory(), "logs/refs/heads/b").exists());
647 // Create new Repository instance, to reread caches and make sure our
648 // assumptions are persistent.
649 Repository ndb = new Repository(db.getDirectory());
650 assertEquals(rb2, ndb.resolve("refs/heads/new/name"));
651 assertNull(ndb.resolve("refs/heads/b"));
654 public void tryRenameWhenLocked(String toLock, String fromName,
655 String toName, String headPointsTo) throws IOException {
656 // setup
657 db.writeSymref(Constants.HEAD, headPointsTo);
658 ObjectId oldfromId = db.resolve(fromName);
659 ObjectId oldHeadId = db.resolve(Constants.HEAD);
660 RefLogWriter.writeReflog(db, oldfromId, oldfromId, "Just a message",
661 fromName);
662 List<org.eclipse.jgit.lib.ReflogReader.Entry> oldFromLog = db
663 .getReflogReader(fromName).getReverseEntries();
664 List<org.eclipse.jgit.lib.ReflogReader.Entry> oldHeadLog = oldHeadId != null ? db
665 .getReflogReader(Constants.HEAD).getReverseEntries() : null;
667 assertTrue("internal check, we have a log", new File(db.getDirectory(),
668 "logs/" + fromName).exists());
670 // "someone" has branch X locked
671 LockFile lockFile = new LockFile(new File(db.getDirectory(), toLock));
672 try {
673 assertTrue(lockFile.lock());
675 // Now this is our test
676 RefRename renameRef = db.renameRef(fromName, toName);
677 Result result = renameRef.rename();
678 assertEquals(Result.LOCK_FAILURE, result);
680 // Check that the involved refs are the same despite the failure
681 assertExists(false, toName);
682 if (!toLock.equals(toName))
683 assertExists(false, toName + ".lock");
684 assertExists(true, toLock + ".lock");
685 if (!toLock.equals(fromName))
686 assertExists(false, "logs/" + fromName + ".lock");
687 assertExists(false, "logs/" + toName + ".lock");
688 assertEquals(oldHeadId, db.resolve(Constants.HEAD));
689 assertEquals(oldfromId, db.resolve(fromName));
690 assertNull(db.resolve(toName));
691 assertEquals(oldFromLog.toString(), db.getReflogReader(fromName)
692 .getReverseEntries().toString());
693 if (oldHeadId != null)
694 assertEquals(oldHeadLog, db.getReflogReader(Constants.HEAD)
695 .getReverseEntries());
696 } finally {
697 lockFile.unlock();
701 private void assertExists(boolean positive, String toName) {
702 assertEquals(toName + (positive ? " " : " does not ") + "exist",
703 positive, new File(db.getDirectory(), toName).exists());
706 public void testRenameBranchCannotLockAFileHEADisFromLockHEAD()
707 throws IOException {
708 tryRenameWhenLocked("HEAD", "refs/heads/b", "refs/heads/new/name",
709 "refs/heads/b");
712 public void testRenameBranchCannotLockAFileHEADisFromLockFrom()
713 throws IOException {
714 tryRenameWhenLocked("refs/heads/b", "refs/heads/b",
715 "refs/heads/new/name", "refs/heads/b");
718 public void testRenameBranchCannotLockAFileHEADisFromLockTo()
719 throws IOException {
720 tryRenameWhenLocked("refs/heads/new/name", "refs/heads/b",
721 "refs/heads/new/name", "refs/heads/b");
724 public void testRenameBranchCannotLockAFileHEADisToLockFrom()
725 throws IOException {
726 tryRenameWhenLocked("refs/heads/b", "refs/heads/b",
727 "refs/heads/new/name", "refs/heads/new/name");
730 public void testRenameBranchCannotLockAFileHEADisToLockTo()
731 throws IOException {
732 tryRenameWhenLocked("refs/heads/new/name", "refs/heads/b",
733 "refs/heads/new/name", "refs/heads/new/name");
736 public void testRenameBranchCannotLockAFileHEADisToLockTmp()
737 throws IOException {
738 tryRenameWhenLocked("RENAMED-REF.." + Thread.currentThread().getId(),
739 "refs/heads/b", "refs/heads/new/name", "refs/heads/new/name");
742 public void testRenameBranchCannotLockAFileHEADisOtherLockFrom()
743 throws IOException {
744 tryRenameWhenLocked("refs/heads/b", "refs/heads/b",
745 "refs/heads/new/name", "refs/heads/a");
748 public void testRenameBranchCannotLockAFileHEADisOtherLockTo()
749 throws IOException {
750 tryRenameWhenLocked("refs/heads/new/name", "refs/heads/b",
751 "refs/heads/new/name", "refs/heads/a");
754 public void testRenameBranchCannotLockAFileHEADisOtherLockTmp()
755 throws IOException {
756 tryRenameWhenLocked("RENAMED-REF.." + Thread.currentThread().getId(),
757 "refs/heads/b", "refs/heads/new/name", "refs/heads/a");
760 public void testRenameRefNameColission1avoided() throws IOException {
761 // setup
762 ObjectId rb = db.resolve("refs/heads/b");
763 db.writeSymref(Constants.HEAD, "refs/heads/a");
764 RefUpdate updateRef = db.updateRef("refs/heads/a");
765 updateRef.setNewObjectId(rb);
766 updateRef.setRefLogMessage("Setup", false);
767 assertEquals(Result.FAST_FORWARD, updateRef.update());
768 ObjectId oldHead = db.resolve(Constants.HEAD);
769 assertTrue(rb.equals(oldHead)); // assumption for this test
770 RefLogWriter.writeReflog(db, rb, rb, "Just a message", "refs/heads/a");
771 assertTrue("internal check, we have a log", new File(db.getDirectory(),
772 "logs/refs/heads/a").exists());
774 // Now this is our test
775 RefRename renameRef = db.renameRef("refs/heads/a", "refs/heads/a/b");
776 Result result = renameRef.rename();
777 assertEquals(Result.RENAMED, result);
778 assertNull(db.resolve("refs/heads/a"));
779 assertEquals(rb, db.resolve("refs/heads/a/b"));
780 assertEquals(3, db.getReflogReader("a/b").getReverseEntries().size());
781 assertEquals("Branch: renamed a to a/b", db.getReflogReader("a/b")
782 .getReverseEntries().get(0).getComment());
783 assertEquals("Just a message", db.getReflogReader("a/b")
784 .getReverseEntries().get(1).getComment());
785 assertEquals("Setup", db.getReflogReader("a/b").getReverseEntries()
786 .get(2).getComment());
787 // same thing was logged to HEAD
788 assertEquals("Branch: renamed a to a/b", db.getReflogReader("HEAD")
789 .getReverseEntries().get(0).getComment());
792 public void testRenameRefNameColission2avoided() throws IOException {
793 // setup
794 ObjectId rb = db.resolve("refs/heads/b");
795 db.writeSymref(Constants.HEAD, "refs/heads/prefix/a");
796 RefUpdate updateRef = db.updateRef("refs/heads/prefix/a");
797 updateRef.setNewObjectId(rb);
798 updateRef.setRefLogMessage("Setup", false);
799 updateRef.setForceUpdate(true);
800 assertEquals(Result.FORCED, updateRef.update());
801 ObjectId oldHead = db.resolve(Constants.HEAD);
802 assertTrue(rb.equals(oldHead)); // assumption for this test
803 RefLogWriter.writeReflog(db, rb, rb, "Just a message",
804 "refs/heads/prefix/a");
805 assertTrue("internal check, we have a log", new File(db.getDirectory(),
806 "logs/refs/heads/prefix/a").exists());
808 // Now this is our test
809 RefRename renameRef = db.renameRef("refs/heads/prefix/a",
810 "refs/heads/prefix");
811 Result result = renameRef.rename();
812 assertEquals(Result.RENAMED, result);
814 assertNull(db.resolve("refs/heads/prefix/a"));
815 assertEquals(rb, db.resolve("refs/heads/prefix"));
816 assertEquals(3, db.getReflogReader("prefix").getReverseEntries().size());
817 assertEquals("Branch: renamed prefix/a to prefix", db.getReflogReader(
818 "prefix").getReverseEntries().get(0).getComment());
819 assertEquals("Just a message", db.getReflogReader("prefix")
820 .getReverseEntries().get(1).getComment());
821 assertEquals("Setup", db.getReflogReader("prefix").getReverseEntries()
822 .get(2).getComment());
823 assertEquals("Branch: renamed prefix/a to prefix", db.getReflogReader(
824 "HEAD").getReverseEntries().get(0).getComment());