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 37KB

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