You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

RefUpdateTest.java 32KB

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