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.

SimpleMergeTest.java 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502
  1. /*
  2. * Copyright (C) 2009, Google Inc.
  3. * Copyright (C) 2008, Robin Rosenberg
  4. * and other copyright owners as documented in the project's IP log.
  5. *
  6. * This program and the accompanying materials are made available
  7. * under the terms of the Eclipse Distribution License v1.0 which
  8. * accompanies this distribution, is reproduced below, and is
  9. * available at http://www.eclipse.org/org/documents/edl-v10.php
  10. *
  11. * All rights reserved.
  12. *
  13. * Redistribution and use in source and binary forms, with or
  14. * without modification, are permitted provided that the following
  15. * conditions are met:
  16. *
  17. * - Redistributions of source code must retain the above copyright
  18. * notice, this list of conditions and the following disclaimer.
  19. *
  20. * - Redistributions in binary form must reproduce the above
  21. * copyright notice, this list of conditions and the following
  22. * disclaimer in the documentation and/or other materials provided
  23. * with the distribution.
  24. *
  25. * - Neither the name of the Eclipse Foundation, Inc. nor the
  26. * names of its contributors may be used to endorse or promote
  27. * products derived from this software without specific prior
  28. * written permission.
  29. *
  30. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  31. * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  32. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  33. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  34. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  35. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  36. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  37. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  38. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  39. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  40. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  41. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  42. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  43. */
  44. package org.eclipse.jgit.merge;
  45. import static org.junit.Assert.assertEquals;
  46. import static org.junit.Assert.assertFalse;
  47. import static org.junit.Assert.assertTrue;
  48. import static org.junit.Assert.fail;
  49. import java.io.IOException;
  50. import java.util.Arrays;
  51. import java.util.List;
  52. import org.eclipse.jgit.dircache.DirCache;
  53. import org.eclipse.jgit.dircache.DirCacheBuilder;
  54. import org.eclipse.jgit.lib.AnyObjectId;
  55. import org.eclipse.jgit.lib.CommitBuilder;
  56. import org.eclipse.jgit.lib.FileMode;
  57. import org.eclipse.jgit.lib.ObjectId;
  58. import org.eclipse.jgit.lib.ObjectInserter;
  59. import org.eclipse.jgit.lib.PersonIdent;
  60. import org.eclipse.jgit.revwalk.RevCommit;
  61. import org.eclipse.jgit.revwalk.RevWalk;
  62. import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase;
  63. import org.eclipse.jgit.treewalk.TreeWalk;
  64. import org.junit.Test;
  65. public class SimpleMergeTest extends SampleDataRepositoryTestCase {
  66. @Test
  67. public void testOurs() throws IOException {
  68. Merger ourMerger = MergeStrategy.OURS.newMerger(db);
  69. boolean merge = ourMerger.merge(new ObjectId[] { db.resolve("a"), db.resolve("c") });
  70. assertTrue(merge);
  71. assertEquals(db.resolve("a^{tree}"), ourMerger.getResultTreeId());
  72. }
  73. @Test
  74. public void testTheirs() throws IOException {
  75. Merger ourMerger = MergeStrategy.THEIRS.newMerger(db);
  76. boolean merge = ourMerger.merge(new ObjectId[] { db.resolve("a"), db.resolve("c") });
  77. assertTrue(merge);
  78. assertEquals(db.resolve("c^{tree}"), ourMerger.getResultTreeId());
  79. }
  80. @Test
  81. public void testTrivialTwoWay() throws IOException {
  82. Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
  83. boolean merge = ourMerger.merge(new ObjectId[] { db.resolve("a"), db.resolve("c") });
  84. assertTrue(merge);
  85. assertEquals("02ba32d3649e510002c21651936b7077aa75ffa9",ourMerger.getResultTreeId().name());
  86. }
  87. @Test
  88. public void testDuplicateParents() throws Exception {
  89. ObjectId commitId;
  90. RevCommit newCommit;
  91. final ObjectInserter ow = db.newObjectInserter();
  92. RevWalk rw = new RevWalk(db);
  93. ObjectId parentA = db.resolve("a");
  94. ObjectId parentB = db.resolve("b");
  95. ObjectId[] parentIds_AA = new ObjectId[] { parentA, parentA };
  96. ObjectId[] parentIds_AB = new ObjectId[] { parentA, parentB };
  97. ObjectId[] parentIds_BA = new ObjectId[] { parentB, parentA };
  98. ObjectId[] parentIds_BBAB = new ObjectId[] { parentB, parentB, parentA,
  99. parentB };
  100. try {
  101. commitId = commit(ow, db.readDirCache(), parentA, parentA);
  102. fail("an expected exception did not occur");
  103. } catch (IllegalArgumentException e) {
  104. //
  105. }
  106. commitId = commit(ow, db.readDirCache(), parentA, parentB);
  107. newCommit = rw.parseCommit(commitId);
  108. assertEquals(2, newCommit.getParentCount());
  109. commitId = commit(ow, db.readDirCache(), parentB, parentA);
  110. newCommit = rw.parseCommit(commitId);
  111. assertEquals(2, newCommit.getParentCount());
  112. try {
  113. commitId = commit(ow, db.readDirCache(), parentIds_AA);
  114. fail("an expected exception did not occur");
  115. } catch (IllegalArgumentException e) {
  116. //
  117. }
  118. commitId = commit(ow, db.readDirCache(), parentIds_AB);
  119. newCommit = rw.parseCommit(commitId);
  120. assertEquals(2, newCommit.getParentCount());
  121. commitId = commit(ow, db.readDirCache(), parentIds_BA);
  122. newCommit = rw.parseCommit(commitId);
  123. assertEquals(2, newCommit.getParentCount());
  124. try {
  125. commitId = commit(ow, db.readDirCache(), parentIds_BBAB);
  126. fail("an expected exception did not occur");
  127. } catch (IllegalArgumentException e) {
  128. //
  129. }
  130. try {
  131. commitId = commit(ow, db.readDirCache(),
  132. Arrays.asList(parentIds_AA));
  133. fail("an expected exception did not occur");
  134. } catch (IllegalArgumentException e) {
  135. //
  136. }
  137. commitId = commit(ow, db.readDirCache(), parentIds_AB);
  138. newCommit = rw.parseCommit(commitId);
  139. assertEquals(2, newCommit.getParentCount());
  140. commitId = commit(ow, db.readDirCache(), parentIds_BA);
  141. newCommit = rw.parseCommit(commitId);
  142. assertEquals(2, newCommit.getParentCount());
  143. try {
  144. commitId = commit(ow, db.readDirCache(), parentIds_BBAB);
  145. fail("an expected exception did not occur");
  146. } catch (IllegalArgumentException e) {
  147. //
  148. }
  149. }
  150. @Test
  151. public void testTrivialTwoWay_disjointhistories() throws IOException {
  152. Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
  153. boolean merge = ourMerger.merge(new ObjectId[] { db.resolve("a"), db.resolve("c~4") });
  154. assertTrue(merge);
  155. assertEquals("86265c33b19b2be71bdd7b8cb95823f2743d03a8",ourMerger.getResultTreeId().name());
  156. }
  157. @Test
  158. public void testTrivialTwoWay_ok() throws IOException {
  159. Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
  160. boolean merge = ourMerger.merge(new ObjectId[] { db.resolve("a^0^0^0"), db.resolve("a^0^0^1") });
  161. assertTrue(merge);
  162. assertEquals(db.resolve("a^0^0^{tree}"), ourMerger.getResultTreeId());
  163. }
  164. @Test
  165. public void testTrivialTwoWay_conflict() throws IOException {
  166. Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
  167. boolean merge = ourMerger.merge(new ObjectId[] { db.resolve("f"), db.resolve("g") });
  168. assertFalse(merge);
  169. }
  170. @Test
  171. public void testTrivialTwoWay_validSubtreeSort() throws Exception {
  172. final DirCache treeB = db.readDirCache();
  173. final DirCache treeO = db.readDirCache();
  174. final DirCache treeT = db.readDirCache();
  175. {
  176. final DirCacheBuilder b = treeB.builder();
  177. final DirCacheBuilder o = treeO.builder();
  178. final DirCacheBuilder t = treeT.builder();
  179. b.add(createEntry("libelf-po/a", FileMode.REGULAR_FILE));
  180. b.add(createEntry("libelf/c", FileMode.REGULAR_FILE));
  181. o.add(createEntry("Makefile", FileMode.REGULAR_FILE));
  182. o.add(createEntry("libelf-po/a", FileMode.REGULAR_FILE));
  183. o.add(createEntry("libelf/c", FileMode.REGULAR_FILE));
  184. t.add(createEntry("libelf-po/a", FileMode.REGULAR_FILE));
  185. t.add(createEntry("libelf/c", FileMode.REGULAR_FILE, "blah"));
  186. b.finish();
  187. o.finish();
  188. t.finish();
  189. }
  190. final ObjectInserter ow = db.newObjectInserter();
  191. final ObjectId b = commit(ow, treeB, new ObjectId[] {});
  192. final ObjectId o = commit(ow, treeO, new ObjectId[] { b });
  193. final ObjectId t = commit(ow, treeT, new ObjectId[] { b });
  194. Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
  195. boolean merge = ourMerger.merge(new ObjectId[] { o, t });
  196. assertTrue(merge);
  197. final TreeWalk tw = new TreeWalk(db);
  198. tw.setRecursive(true);
  199. tw.reset(ourMerger.getResultTreeId());
  200. assertTrue(tw.next());
  201. assertEquals("Makefile", tw.getPathString());
  202. assertCorrectId(treeO, tw);
  203. assertTrue(tw.next());
  204. assertEquals("libelf-po/a", tw.getPathString());
  205. assertCorrectId(treeO, tw);
  206. assertTrue(tw.next());
  207. assertEquals("libelf/c", tw.getPathString());
  208. assertCorrectId(treeT, tw);
  209. assertFalse(tw.next());
  210. }
  211. @Test
  212. public void testTrivialTwoWay_concurrentSubtreeChange() throws Exception {
  213. final DirCache treeB = db.readDirCache();
  214. final DirCache treeO = db.readDirCache();
  215. final DirCache treeT = db.readDirCache();
  216. {
  217. final DirCacheBuilder b = treeB.builder();
  218. final DirCacheBuilder o = treeO.builder();
  219. final DirCacheBuilder t = treeT.builder();
  220. b.add(createEntry("d/o", FileMode.REGULAR_FILE));
  221. b.add(createEntry("d/t", FileMode.REGULAR_FILE));
  222. o.add(createEntry("d/o", FileMode.REGULAR_FILE, "o !"));
  223. o.add(createEntry("d/t", FileMode.REGULAR_FILE));
  224. t.add(createEntry("d/o", FileMode.REGULAR_FILE));
  225. t.add(createEntry("d/t", FileMode.REGULAR_FILE, "t !"));
  226. b.finish();
  227. o.finish();
  228. t.finish();
  229. }
  230. final ObjectInserter ow = db.newObjectInserter();
  231. final ObjectId b = commit(ow, treeB, new ObjectId[] {});
  232. final ObjectId o = commit(ow, treeO, new ObjectId[] { b });
  233. final ObjectId t = commit(ow, treeT, new ObjectId[] { b });
  234. Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
  235. boolean merge = ourMerger.merge(new ObjectId[] { o, t });
  236. assertTrue(merge);
  237. final TreeWalk tw = new TreeWalk(db);
  238. tw.setRecursive(true);
  239. tw.reset(ourMerger.getResultTreeId());
  240. assertTrue(tw.next());
  241. assertEquals("d/o", tw.getPathString());
  242. assertCorrectId(treeO, tw);
  243. assertTrue(tw.next());
  244. assertEquals("d/t", tw.getPathString());
  245. assertCorrectId(treeT, tw);
  246. assertFalse(tw.next());
  247. }
  248. @Test
  249. public void testTrivialTwoWay_conflictSubtreeChange() throws Exception {
  250. final DirCache treeB = db.readDirCache();
  251. final DirCache treeO = db.readDirCache();
  252. final DirCache treeT = db.readDirCache();
  253. {
  254. final DirCacheBuilder b = treeB.builder();
  255. final DirCacheBuilder o = treeO.builder();
  256. final DirCacheBuilder t = treeT.builder();
  257. b.add(createEntry("d/o", FileMode.REGULAR_FILE));
  258. b.add(createEntry("d/t", FileMode.REGULAR_FILE));
  259. o.add(createEntry("d/o", FileMode.REGULAR_FILE));
  260. o.add(createEntry("d/t", FileMode.REGULAR_FILE, "o !"));
  261. t.add(createEntry("d/o", FileMode.REGULAR_FILE, "t !"));
  262. t.add(createEntry("d/t", FileMode.REGULAR_FILE, "t !"));
  263. b.finish();
  264. o.finish();
  265. t.finish();
  266. }
  267. final ObjectInserter ow = db.newObjectInserter();
  268. final ObjectId b = commit(ow, treeB, new ObjectId[] {});
  269. final ObjectId o = commit(ow, treeO, new ObjectId[] { b });
  270. final ObjectId t = commit(ow, treeT, new ObjectId[] { b });
  271. Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
  272. boolean merge = ourMerger.merge(new ObjectId[] { o, t });
  273. assertFalse(merge);
  274. }
  275. @Test
  276. public void testTrivialTwoWay_leftDFconflict1() throws Exception {
  277. final DirCache treeB = db.readDirCache();
  278. final DirCache treeO = db.readDirCache();
  279. final DirCache treeT = db.readDirCache();
  280. {
  281. final DirCacheBuilder b = treeB.builder();
  282. final DirCacheBuilder o = treeO.builder();
  283. final DirCacheBuilder t = treeT.builder();
  284. b.add(createEntry("d/o", FileMode.REGULAR_FILE));
  285. b.add(createEntry("d/t", FileMode.REGULAR_FILE));
  286. o.add(createEntry("d", FileMode.REGULAR_FILE));
  287. t.add(createEntry("d/o", FileMode.REGULAR_FILE));
  288. t.add(createEntry("d/t", FileMode.REGULAR_FILE, "t !"));
  289. b.finish();
  290. o.finish();
  291. t.finish();
  292. }
  293. final ObjectInserter ow = db.newObjectInserter();
  294. final ObjectId b = commit(ow, treeB, new ObjectId[] {});
  295. final ObjectId o = commit(ow, treeO, new ObjectId[] { b });
  296. final ObjectId t = commit(ow, treeT, new ObjectId[] { b });
  297. Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
  298. boolean merge = ourMerger.merge(new ObjectId[] { o, t });
  299. assertFalse(merge);
  300. }
  301. @Test
  302. public void testTrivialTwoWay_rightDFconflict1() throws Exception {
  303. final DirCache treeB = db.readDirCache();
  304. final DirCache treeO = db.readDirCache();
  305. final DirCache treeT = db.readDirCache();
  306. {
  307. final DirCacheBuilder b = treeB.builder();
  308. final DirCacheBuilder o = treeO.builder();
  309. final DirCacheBuilder t = treeT.builder();
  310. b.add(createEntry("d/o", FileMode.REGULAR_FILE));
  311. b.add(createEntry("d/t", FileMode.REGULAR_FILE));
  312. o.add(createEntry("d/o", FileMode.REGULAR_FILE));
  313. o.add(createEntry("d/t", FileMode.REGULAR_FILE, "o !"));
  314. t.add(createEntry("d", FileMode.REGULAR_FILE));
  315. b.finish();
  316. o.finish();
  317. t.finish();
  318. }
  319. final ObjectInserter ow = db.newObjectInserter();
  320. final ObjectId b = commit(ow, treeB, new ObjectId[] {});
  321. final ObjectId o = commit(ow, treeO, new ObjectId[] { b });
  322. final ObjectId t = commit(ow, treeT, new ObjectId[] { b });
  323. Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
  324. boolean merge = ourMerger.merge(new ObjectId[] { o, t });
  325. assertFalse(merge);
  326. }
  327. @Test
  328. public void testTrivialTwoWay_leftDFconflict2() throws Exception {
  329. final DirCache treeB = db.readDirCache();
  330. final DirCache treeO = db.readDirCache();
  331. final DirCache treeT = db.readDirCache();
  332. {
  333. final DirCacheBuilder b = treeB.builder();
  334. final DirCacheBuilder o = treeO.builder();
  335. final DirCacheBuilder t = treeT.builder();
  336. b.add(createEntry("d", FileMode.REGULAR_FILE));
  337. o.add(createEntry("d", FileMode.REGULAR_FILE, "o !"));
  338. t.add(createEntry("d/o", FileMode.REGULAR_FILE));
  339. b.finish();
  340. o.finish();
  341. t.finish();
  342. }
  343. final ObjectInserter ow = db.newObjectInserter();
  344. final ObjectId b = commit(ow, treeB, new ObjectId[] {});
  345. final ObjectId o = commit(ow, treeO, new ObjectId[] { b });
  346. final ObjectId t = commit(ow, treeT, new ObjectId[] { b });
  347. Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
  348. boolean merge = ourMerger.merge(new ObjectId[] { o, t });
  349. assertFalse(merge);
  350. }
  351. @Test
  352. public void testTrivialTwoWay_rightDFconflict2() throws Exception {
  353. final DirCache treeB = db.readDirCache();
  354. final DirCache treeO = db.readDirCache();
  355. final DirCache treeT = db.readDirCache();
  356. {
  357. final DirCacheBuilder b = treeB.builder();
  358. final DirCacheBuilder o = treeO.builder();
  359. final DirCacheBuilder t = treeT.builder();
  360. b.add(createEntry("d", FileMode.REGULAR_FILE));
  361. o.add(createEntry("d/o", FileMode.REGULAR_FILE));
  362. t.add(createEntry("d", FileMode.REGULAR_FILE, "t !"));
  363. b.finish();
  364. o.finish();
  365. t.finish();
  366. }
  367. final ObjectInserter ow = db.newObjectInserter();
  368. final ObjectId b = commit(ow, treeB, new ObjectId[] {});
  369. final ObjectId o = commit(ow, treeO, new ObjectId[] { b });
  370. final ObjectId t = commit(ow, treeT, new ObjectId[] { b });
  371. Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
  372. boolean merge = ourMerger.merge(new ObjectId[] { o, t });
  373. assertFalse(merge);
  374. }
  375. private static void assertCorrectId(final DirCache treeT, final TreeWalk tw) {
  376. assertEquals(treeT.getEntry(tw.getPathString()).getObjectId(), tw
  377. .getObjectId(0));
  378. }
  379. private static ObjectId commit(final ObjectInserter odi,
  380. final DirCache treeB,
  381. final ObjectId[] parentIds) throws Exception {
  382. final CommitBuilder c = new CommitBuilder();
  383. c.setTreeId(treeB.writeTree(odi));
  384. c.setAuthor(new PersonIdent("A U Thor", "a.u.thor", 1L, 0));
  385. c.setCommitter(c.getAuthor());
  386. c.setParentIds(parentIds);
  387. c.setMessage("Tree " + c.getTreeId().name());
  388. ObjectId id = odi.insert(c);
  389. odi.flush();
  390. return id;
  391. }
  392. private ObjectId commit(final ObjectInserter odi, final DirCache treeB,
  393. final AnyObjectId parentId1, final AnyObjectId parentId2)
  394. throws Exception {
  395. final CommitBuilder c = new CommitBuilder();
  396. c.setTreeId(treeB.writeTree(odi));
  397. c.setAuthor(new PersonIdent("A U Thor", "a.u.thor", 1L, 0));
  398. c.setCommitter(c.getAuthor());
  399. c.setParentIds(parentId1, parentId2);
  400. c.setMessage("Tree " + c.getTreeId().name());
  401. ObjectId id = odi.insert(c);
  402. odi.flush();
  403. return id;
  404. }
  405. private ObjectId commit(final ObjectInserter odi, final DirCache treeB,
  406. List<ObjectId> parents) throws Exception {
  407. final CommitBuilder c = new CommitBuilder();
  408. c.setTreeId(treeB.writeTree(odi));
  409. c.setAuthor(new PersonIdent("A U Thor", "a.u.thor", 1L, 0));
  410. c.setCommitter(c.getAuthor());
  411. c.setParentIds(parents);
  412. c.setMessage("Tree " + c.getTreeId().name());
  413. ObjectId id = odi.insert(c);
  414. odi.flush();
  415. return id;
  416. }
  417. }