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

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