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.

MergeCommandTest.java 60KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719
  1. /*
  2. * Copyright (C) 2010, Stefan Lay <stefan.lay@sap.com>
  3. * Copyright (C) 2010-2014, Christian Halstrick <christian.halstrick@sap.com>
  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.api;
  45. import static org.eclipse.jgit.lib.Constants.MASTER;
  46. import static org.eclipse.jgit.lib.Constants.R_HEADS;
  47. import static org.junit.Assert.assertEquals;
  48. import static org.junit.Assert.assertFalse;
  49. import static org.junit.Assert.assertNull;
  50. import static org.junit.Assert.assertTrue;
  51. import static org.junit.Assert.fail;
  52. import static org.junit.Assume.assumeTrue;
  53. import java.io.File;
  54. import java.util.Iterator;
  55. import java.util.regex.Pattern;
  56. import org.eclipse.jgit.api.MergeCommand.FastForwardMode;
  57. import org.eclipse.jgit.api.MergeResult.MergeStatus;
  58. import org.eclipse.jgit.api.errors.InvalidMergeHeadsException;
  59. import org.eclipse.jgit.junit.RepositoryTestCase;
  60. import org.eclipse.jgit.junit.TestRepository;
  61. import org.eclipse.jgit.junit.TestRepository.BranchBuilder;
  62. import org.eclipse.jgit.lib.Constants;
  63. import org.eclipse.jgit.lib.Ref;
  64. import org.eclipse.jgit.lib.Repository;
  65. import org.eclipse.jgit.lib.RepositoryState;
  66. import org.eclipse.jgit.lib.Sets;
  67. import org.eclipse.jgit.merge.MergeStrategy;
  68. import org.eclipse.jgit.merge.ResolveMerger.MergeFailureReason;
  69. import org.eclipse.jgit.revwalk.RevCommit;
  70. import org.eclipse.jgit.util.FS;
  71. import org.eclipse.jgit.util.FileUtils;
  72. import org.eclipse.jgit.util.GitDateFormatter;
  73. import org.eclipse.jgit.util.GitDateFormatter.Format;
  74. import org.junit.Before;
  75. import org.junit.Test;
  76. import org.junit.experimental.theories.DataPoints;
  77. import org.junit.experimental.theories.Theories;
  78. import org.junit.experimental.theories.Theory;
  79. import org.junit.runner.RunWith;
  80. @RunWith(Theories.class)
  81. public class MergeCommandTest extends RepositoryTestCase {
  82. public static @DataPoints
  83. MergeStrategy[] mergeStrategies = MergeStrategy.get();
  84. private GitDateFormatter dateFormatter;
  85. @Override
  86. @Before
  87. public void setUp() throws Exception {
  88. super.setUp();
  89. dateFormatter = new GitDateFormatter(Format.DEFAULT);
  90. }
  91. @Test
  92. public void testMergeInItself() throws Exception {
  93. try (Git git = new Git(db)) {
  94. git.commit().setMessage("initial commit").call();
  95. MergeResult result = git.merge().include(db.exactRef(Constants.HEAD)).call();
  96. assertEquals(MergeResult.MergeStatus.ALREADY_UP_TO_DATE, result.getMergeStatus());
  97. }
  98. // no reflog entry written by merge
  99. assertEquals("commit (initial): initial commit",
  100. db
  101. .getReflogReader(Constants.HEAD).getLastEntry().getComment());
  102. assertEquals("commit (initial): initial commit",
  103. db
  104. .getReflogReader(db.getBranch()).getLastEntry().getComment());
  105. }
  106. @Test
  107. public void testAlreadyUpToDate() throws Exception {
  108. try (Git git = new Git(db)) {
  109. RevCommit first = git.commit().setMessage("initial commit").call();
  110. createBranch(first, "refs/heads/branch1");
  111. RevCommit second = git.commit().setMessage("second commit").call();
  112. MergeResult result = git.merge().include(db.exactRef("refs/heads/branch1")).call();
  113. assertEquals(MergeResult.MergeStatus.ALREADY_UP_TO_DATE, result.getMergeStatus());
  114. assertEquals(second, result.getNewHead());
  115. }
  116. // no reflog entry written by merge
  117. assertEquals("commit: second commit", db
  118. .getReflogReader(Constants.HEAD).getLastEntry().getComment());
  119. assertEquals("commit: second commit", db
  120. .getReflogReader(db.getBranch()).getLastEntry().getComment());
  121. }
  122. @Test
  123. public void testFastForward() throws Exception {
  124. try (Git git = new Git(db)) {
  125. RevCommit first = git.commit().setMessage("initial commit").call();
  126. createBranch(first, "refs/heads/branch1");
  127. RevCommit second = git.commit().setMessage("second commit").call();
  128. checkoutBranch("refs/heads/branch1");
  129. MergeResult result = git.merge().include(db.exactRef(R_HEADS + MASTER)).call();
  130. assertEquals(MergeResult.MergeStatus.FAST_FORWARD, result.getMergeStatus());
  131. assertEquals(second, result.getNewHead());
  132. }
  133. assertEquals("merge refs/heads/master: Fast-forward",
  134. db.getReflogReader(Constants.HEAD).getLastEntry().getComment());
  135. assertEquals("merge refs/heads/master: Fast-forward",
  136. db.getReflogReader(db.getBranch()).getLastEntry().getComment());
  137. }
  138. @Test
  139. public void testFastForwardNoCommit() throws Exception {
  140. try (Git git = new Git(db)) {
  141. RevCommit first = git.commit().setMessage("initial commit").call();
  142. createBranch(first, "refs/heads/branch1");
  143. RevCommit second = git.commit().setMessage("second commit").call();
  144. checkoutBranch("refs/heads/branch1");
  145. MergeResult result = git.merge().include(db.exactRef(R_HEADS + MASTER))
  146. .setCommit(false).call();
  147. assertEquals(MergeResult.MergeStatus.FAST_FORWARD,
  148. result.getMergeStatus());
  149. assertEquals(second, result.getNewHead());
  150. }
  151. assertEquals("merge refs/heads/master: Fast-forward", db
  152. .getReflogReader(Constants.HEAD).getLastEntry().getComment());
  153. assertEquals("merge refs/heads/master: Fast-forward", db
  154. .getReflogReader(db.getBranch()).getLastEntry().getComment());
  155. }
  156. @Test
  157. public void testFastForwardWithFiles() throws Exception {
  158. try (Git git = new Git(db)) {
  159. writeTrashFile("file1", "file1");
  160. git.add().addFilepattern("file1").call();
  161. RevCommit first = git.commit().setMessage("initial commit").call();
  162. assertTrue(new File(db.getWorkTree(), "file1").exists());
  163. createBranch(first, "refs/heads/branch1");
  164. writeTrashFile("file2", "file2");
  165. git.add().addFilepattern("file2").call();
  166. RevCommit second = git.commit().setMessage("second commit").call();
  167. assertTrue(new File(db.getWorkTree(), "file2").exists());
  168. checkoutBranch("refs/heads/branch1");
  169. assertFalse(new File(db.getWorkTree(), "file2").exists());
  170. MergeResult result = git.merge().include(db.exactRef(R_HEADS + MASTER)).call();
  171. assertTrue(new File(db.getWorkTree(), "file1").exists());
  172. assertTrue(new File(db.getWorkTree(), "file2").exists());
  173. assertEquals(MergeResult.MergeStatus.FAST_FORWARD, result.getMergeStatus());
  174. assertEquals(second, result.getNewHead());
  175. }
  176. assertEquals("merge refs/heads/master: Fast-forward",
  177. db.getReflogReader(Constants.HEAD).getLastEntry().getComment());
  178. assertEquals("merge refs/heads/master: Fast-forward",
  179. db.getReflogReader(db.getBranch()).getLastEntry().getComment());
  180. }
  181. @Test
  182. public void testMultipleHeads() throws Exception {
  183. try (Git git = new Git(db)) {
  184. writeTrashFile("file1", "file1");
  185. git.add().addFilepattern("file1").call();
  186. RevCommit first = git.commit().setMessage("initial commit").call();
  187. createBranch(first, "refs/heads/branch1");
  188. writeTrashFile("file2", "file2");
  189. git.add().addFilepattern("file2").call();
  190. RevCommit second = git.commit().setMessage("second commit").call();
  191. writeTrashFile("file3", "file3");
  192. git.add().addFilepattern("file3").call();
  193. git.commit().setMessage("third commit").call();
  194. checkoutBranch("refs/heads/branch1");
  195. assertFalse(new File(db.getWorkTree(), "file2").exists());
  196. assertFalse(new File(db.getWorkTree(), "file3").exists());
  197. MergeCommand merge = git.merge();
  198. merge.include(second.getId());
  199. merge.include(db.exactRef(R_HEADS + MASTER));
  200. try {
  201. merge.call();
  202. fail("Expected exception not thrown when merging multiple heads");
  203. } catch (InvalidMergeHeadsException e) {
  204. // expected this exception
  205. }
  206. }
  207. }
  208. @Theory
  209. public void testMergeSuccessAllStrategies(MergeStrategy mergeStrategy)
  210. throws Exception {
  211. try (Git git = new Git(db)) {
  212. RevCommit first = git.commit().setMessage("first").call();
  213. createBranch(first, "refs/heads/side");
  214. writeTrashFile("a", "a");
  215. git.add().addFilepattern("a").call();
  216. git.commit().setMessage("second").call();
  217. checkoutBranch("refs/heads/side");
  218. writeTrashFile("b", "b");
  219. git.add().addFilepattern("b").call();
  220. git.commit().setMessage("third").call();
  221. MergeResult result = git.merge().setStrategy(mergeStrategy)
  222. .include(db.exactRef(R_HEADS + MASTER)).call();
  223. assertEquals(MergeStatus.MERGED, result.getMergeStatus());
  224. }
  225. assertEquals(
  226. "merge refs/heads/master: Merge made by "
  227. + mergeStrategy.getName() + ".",
  228. db.getReflogReader(Constants.HEAD).getLastEntry().getComment());
  229. assertEquals(
  230. "merge refs/heads/master: Merge made by "
  231. + mergeStrategy.getName() + ".",
  232. db.getReflogReader(db.getBranch()).getLastEntry().getComment());
  233. }
  234. @Theory
  235. public void testMergeSuccessAllStrategiesNoCommit(
  236. MergeStrategy mergeStrategy) throws Exception {
  237. try (Git git = new Git(db)) {
  238. RevCommit first = git.commit().setMessage("first").call();
  239. createBranch(first, "refs/heads/side");
  240. writeTrashFile("a", "a");
  241. git.add().addFilepattern("a").call();
  242. git.commit().setMessage("second").call();
  243. checkoutBranch("refs/heads/side");
  244. writeTrashFile("b", "b");
  245. git.add().addFilepattern("b").call();
  246. RevCommit thirdCommit = git.commit().setMessage("third").call();
  247. MergeResult result = git.merge().setStrategy(mergeStrategy)
  248. .setCommit(false)
  249. .include(db.exactRef(R_HEADS + MASTER)).call();
  250. assertEquals(MergeStatus.MERGED_NOT_COMMITTED, result.getMergeStatus());
  251. assertEquals(db.exactRef(Constants.HEAD).getTarget().getObjectId(),
  252. thirdCommit.getId());
  253. }
  254. }
  255. @Test
  256. public void testContentMerge() throws Exception {
  257. try (Git git = new Git(db)) {
  258. writeTrashFile("a", "1\na\n3\n");
  259. writeTrashFile("b", "1\nb\n3\n");
  260. writeTrashFile("c/c/c", "1\nc\n3\n");
  261. git.add().addFilepattern("a").addFilepattern("b")
  262. .addFilepattern("c/c/c").call();
  263. RevCommit initialCommit = git.commit().setMessage("initial").call();
  264. createBranch(initialCommit, "refs/heads/side");
  265. checkoutBranch("refs/heads/side");
  266. writeTrashFile("a", "1\na(side)\n3\n");
  267. writeTrashFile("b", "1\nb(side)\n3\n");
  268. git.add().addFilepattern("a").addFilepattern("b").call();
  269. RevCommit secondCommit = git.commit().setMessage("side").call();
  270. assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
  271. checkoutBranch("refs/heads/master");
  272. assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
  273. writeTrashFile("a", "1\na(main)\n3\n");
  274. writeTrashFile("c/c/c", "1\nc(main)\n3\n");
  275. git.add().addFilepattern("a").addFilepattern("c/c/c").call();
  276. git.commit().setMessage("main").call();
  277. MergeResult result = git.merge().include(secondCommit.getId())
  278. .setStrategy(MergeStrategy.RESOLVE).call();
  279. assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
  280. assertEquals(
  281. "1\n<<<<<<< HEAD\na(main)\n=======\na(side)\n>>>>>>> 86503e7e397465588cc267b65d778538bffccb83\n3\n",
  282. read(new File(db.getWorkTree(), "a")));
  283. assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
  284. assertEquals("1\nc(main)\n3\n",
  285. read(new File(db.getWorkTree(), "c/c/c")));
  286. assertEquals(1, result.getConflicts().size());
  287. assertEquals(3, result.getConflicts().get("a")[0].length);
  288. assertEquals(RepositoryState.MERGING, db.getRepositoryState());
  289. }
  290. }
  291. @Test
  292. public void testMergeTag() throws Exception {
  293. try (Git git = new Git(db)) {
  294. writeTrashFile("a", "a");
  295. git.add().addFilepattern("a").call();
  296. RevCommit initialCommit = git.commit().setMessage("initial").call();
  297. createBranch(initialCommit, "refs/heads/side");
  298. checkoutBranch("refs/heads/side");
  299. writeTrashFile("b", "b");
  300. git.add().addFilepattern("b").call();
  301. RevCommit secondCommit = git.commit().setMessage("side").call();
  302. Ref tag = git.tag().setAnnotated(true).setMessage("my tag 01")
  303. .setName("tag01").setObjectId(secondCommit).call();
  304. checkoutBranch("refs/heads/master");
  305. writeTrashFile("a", "a2");
  306. git.add().addFilepattern("a").call();
  307. git.commit().setMessage("main").call();
  308. MergeResult result = git.merge().include(tag).setStrategy(MergeStrategy.RESOLVE).call();
  309. assertEquals(MergeStatus.MERGED, result.getMergeStatus());
  310. }
  311. }
  312. @Test
  313. public void testMergeMessage() throws Exception {
  314. try (Git git = new Git(db)) {
  315. writeTrashFile("a", "1\na\n3\n");
  316. git.add().addFilepattern("a").call();
  317. RevCommit initialCommit = git.commit().setMessage("initial").call();
  318. createBranch(initialCommit, "refs/heads/side");
  319. checkoutBranch("refs/heads/side");
  320. writeTrashFile("a", "1\na(side)\n3\n");
  321. git.add().addFilepattern("a").call();
  322. git.commit().setMessage("side").call();
  323. checkoutBranch("refs/heads/master");
  324. writeTrashFile("a", "1\na(main)\n3\n");
  325. git.add().addFilepattern("a").call();
  326. git.commit().setMessage("main").call();
  327. Ref sideBranch = db.exactRef("refs/heads/side");
  328. git.merge().include(sideBranch)
  329. .setStrategy(MergeStrategy.RESOLVE).call();
  330. assertEquals("Merge branch 'side'\n\nConflicts:\n\ta\n",
  331. db.readMergeCommitMsg());
  332. }
  333. }
  334. @Test
  335. public void testMergeNonVersionedPaths() throws Exception {
  336. try (Git git = new Git(db)) {
  337. writeTrashFile("a", "1\na\n3\n");
  338. writeTrashFile("b", "1\nb\n3\n");
  339. writeTrashFile("c/c/c", "1\nc\n3\n");
  340. git.add().addFilepattern("a").addFilepattern("b")
  341. .addFilepattern("c/c/c").call();
  342. RevCommit initialCommit = git.commit().setMessage("initial").call();
  343. createBranch(initialCommit, "refs/heads/side");
  344. checkoutBranch("refs/heads/side");
  345. writeTrashFile("a", "1\na(side)\n3\n");
  346. writeTrashFile("b", "1\nb(side)\n3\n");
  347. git.add().addFilepattern("a").addFilepattern("b").call();
  348. RevCommit secondCommit = git.commit().setMessage("side").call();
  349. assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
  350. checkoutBranch("refs/heads/master");
  351. assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
  352. writeTrashFile("a", "1\na(main)\n3\n");
  353. writeTrashFile("c/c/c", "1\nc(main)\n3\n");
  354. git.add().addFilepattern("a").addFilepattern("c/c/c").call();
  355. git.commit().setMessage("main").call();
  356. writeTrashFile("d", "1\nd\n3\n");
  357. assertTrue(new File(db.getWorkTree(), "e").mkdir());
  358. MergeResult result = git.merge().include(secondCommit.getId())
  359. .setStrategy(MergeStrategy.RESOLVE).call();
  360. assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
  361. assertEquals(
  362. "1\n<<<<<<< HEAD\na(main)\n=======\na(side)\n>>>>>>> 86503e7e397465588cc267b65d778538bffccb83\n3\n",
  363. read(new File(db.getWorkTree(), "a")));
  364. assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
  365. assertEquals("1\nc(main)\n3\n",
  366. read(new File(db.getWorkTree(), "c/c/c")));
  367. assertEquals("1\nd\n3\n", read(new File(db.getWorkTree(), "d")));
  368. File dir = new File(db.getWorkTree(), "e");
  369. assertTrue(dir.isDirectory());
  370. assertEquals(1, result.getConflicts().size());
  371. assertEquals(3, result.getConflicts().get("a")[0].length);
  372. assertEquals(RepositoryState.MERGING, db.getRepositoryState());
  373. }
  374. }
  375. @Test
  376. public void testMultipleCreations() throws Exception {
  377. try (Git git = new Git(db)) {
  378. writeTrashFile("a", "1\na\n3\n");
  379. git.add().addFilepattern("a").call();
  380. RevCommit initialCommit = git.commit().setMessage("initial").call();
  381. createBranch(initialCommit, "refs/heads/side");
  382. checkoutBranch("refs/heads/side");
  383. writeTrashFile("b", "1\nb(side)\n3\n");
  384. git.add().addFilepattern("b").call();
  385. RevCommit secondCommit = git.commit().setMessage("side").call();
  386. checkoutBranch("refs/heads/master");
  387. writeTrashFile("b", "1\nb(main)\n3\n");
  388. git.add().addFilepattern("b").call();
  389. git.commit().setMessage("main").call();
  390. MergeResult result = git.merge().include(secondCommit.getId())
  391. .setStrategy(MergeStrategy.RESOLVE).call();
  392. assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
  393. }
  394. }
  395. @Test
  396. public void testMultipleCreationsSameContent() throws Exception {
  397. try (Git git = new Git(db)) {
  398. writeTrashFile("a", "1\na\n3\n");
  399. git.add().addFilepattern("a").call();
  400. RevCommit initialCommit = git.commit().setMessage("initial").call();
  401. createBranch(initialCommit, "refs/heads/side");
  402. checkoutBranch("refs/heads/side");
  403. writeTrashFile("b", "1\nb(1)\n3\n");
  404. git.add().addFilepattern("b").call();
  405. RevCommit secondCommit = git.commit().setMessage("side").call();
  406. checkoutBranch("refs/heads/master");
  407. writeTrashFile("b", "1\nb(1)\n3\n");
  408. git.add().addFilepattern("b").call();
  409. git.commit().setMessage("main").call();
  410. MergeResult result = git.merge().include(secondCommit.getId())
  411. .setStrategy(MergeStrategy.RESOLVE).call();
  412. assertEquals(MergeStatus.MERGED, result.getMergeStatus());
  413. assertEquals("1\nb(1)\n3\n", read(new File(db.getWorkTree(), "b")));
  414. assertEquals("merge " + secondCommit.getId().getName()
  415. + ": Merge made by resolve.", db
  416. .getReflogReader(Constants.HEAD)
  417. .getLastEntry().getComment());
  418. assertEquals("merge " + secondCommit.getId().getName()
  419. + ": Merge made by resolve.", db
  420. .getReflogReader(db.getBranch())
  421. .getLastEntry().getComment());
  422. }
  423. }
  424. @Test
  425. public void testSuccessfulContentMerge() throws Exception {
  426. try (Git git = new Git(db)) {
  427. writeTrashFile("a", "1\na\n3\n");
  428. writeTrashFile("b", "1\nb\n3\n");
  429. writeTrashFile("c/c/c", "1\nc\n3\n");
  430. git.add().addFilepattern("a").addFilepattern("b")
  431. .addFilepattern("c/c/c").call();
  432. RevCommit initialCommit = git.commit().setMessage("initial").call();
  433. createBranch(initialCommit, "refs/heads/side");
  434. checkoutBranch("refs/heads/side");
  435. writeTrashFile("a", "1(side)\na\n3\n");
  436. writeTrashFile("b", "1\nb(side)\n3\n");
  437. git.add().addFilepattern("a").addFilepattern("b").call();
  438. RevCommit secondCommit = git.commit().setMessage("side").call();
  439. assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
  440. checkoutBranch("refs/heads/master");
  441. assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
  442. writeTrashFile("a", "1\na\n3(main)\n");
  443. writeTrashFile("c/c/c", "1\nc(main)\n3\n");
  444. git.add().addFilepattern("a").addFilepattern("c/c/c").call();
  445. RevCommit thirdCommit = git.commit().setMessage("main").call();
  446. MergeResult result = git.merge().include(secondCommit.getId())
  447. .setStrategy(MergeStrategy.RESOLVE).call();
  448. assertEquals(MergeStatus.MERGED, result.getMergeStatus());
  449. assertEquals("1(side)\na\n3(main)\n", read(new File(db.getWorkTree(),
  450. "a")));
  451. assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
  452. assertEquals("1\nc(main)\n3\n", read(new File(db.getWorkTree(),
  453. "c/c/c")));
  454. assertEquals(null, result.getConflicts());
  455. assertEquals(2, result.getMergedCommits().length);
  456. assertEquals(thirdCommit, result.getMergedCommits()[0]);
  457. assertEquals(secondCommit, result.getMergedCommits()[1]);
  458. Iterator<RevCommit> it = git.log().call().iterator();
  459. RevCommit newHead = it.next();
  460. assertEquals(newHead, result.getNewHead());
  461. assertEquals(2, newHead.getParentCount());
  462. assertEquals(thirdCommit, newHead.getParent(0));
  463. assertEquals(secondCommit, newHead.getParent(1));
  464. assertEquals(
  465. "Merge commit '3fa334456d236a92db020289fe0bf481d91777b4'",
  466. newHead.getFullMessage());
  467. // @TODO fix me
  468. assertEquals(RepositoryState.SAFE, db.getRepositoryState());
  469. // test index state
  470. }
  471. }
  472. @Test
  473. public void testSuccessfulContentMergeNoCommit() throws Exception {
  474. try (Git git = new Git(db)) {
  475. writeTrashFile("a", "1\na\n3\n");
  476. writeTrashFile("b", "1\nb\n3\n");
  477. writeTrashFile("c/c/c", "1\nc\n3\n");
  478. git.add().addFilepattern("a").addFilepattern("b")
  479. .addFilepattern("c/c/c").call();
  480. RevCommit initialCommit = git.commit().setMessage("initial").call();
  481. createBranch(initialCommit, "refs/heads/side");
  482. checkoutBranch("refs/heads/side");
  483. writeTrashFile("a", "1(side)\na\n3\n");
  484. writeTrashFile("b", "1\nb(side)\n3\n");
  485. git.add().addFilepattern("a").addFilepattern("b").call();
  486. RevCommit secondCommit = git.commit().setMessage("side").call();
  487. assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
  488. checkoutBranch("refs/heads/master");
  489. assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
  490. writeTrashFile("a", "1\na\n3(main)\n");
  491. writeTrashFile("c/c/c", "1\nc(main)\n3\n");
  492. git.add().addFilepattern("a").addFilepattern("c/c/c").call();
  493. RevCommit thirdCommit = git.commit().setMessage("main").call();
  494. MergeResult result = git.merge().include(secondCommit.getId())
  495. .setCommit(false)
  496. .setStrategy(MergeStrategy.RESOLVE).call();
  497. assertEquals(MergeStatus.MERGED_NOT_COMMITTED, result.getMergeStatus());
  498. assertEquals(db.exactRef(Constants.HEAD).getTarget().getObjectId(),
  499. thirdCommit.getId());
  500. assertEquals("1(side)\na\n3(main)\n", read(new File(db.getWorkTree(),
  501. "a")));
  502. assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
  503. assertEquals("1\nc(main)\n3\n",
  504. read(new File(db.getWorkTree(), "c/c/c")));
  505. assertEquals(null, result.getConflicts());
  506. assertEquals(2, result.getMergedCommits().length);
  507. assertEquals(thirdCommit, result.getMergedCommits()[0]);
  508. assertEquals(secondCommit, result.getMergedCommits()[1]);
  509. assertNull(result.getNewHead());
  510. assertEquals(RepositoryState.MERGING_RESOLVED, db.getRepositoryState());
  511. }
  512. }
  513. @Test
  514. public void testSuccessfulContentMergeAndDirtyworkingTree()
  515. throws Exception {
  516. try (Git git = new Git(db)) {
  517. writeTrashFile("a", "1\na\n3\n");
  518. writeTrashFile("b", "1\nb\n3\n");
  519. writeTrashFile("d", "1\nd\n3\n");
  520. writeTrashFile("c/c/c", "1\nc\n3\n");
  521. git.add().addFilepattern("a").addFilepattern("b")
  522. .addFilepattern("c/c/c").addFilepattern("d").call();
  523. RevCommit initialCommit = git.commit().setMessage("initial").call();
  524. createBranch(initialCommit, "refs/heads/side");
  525. checkoutBranch("refs/heads/side");
  526. writeTrashFile("a", "1(side)\na\n3\n");
  527. writeTrashFile("b", "1\nb(side)\n3\n");
  528. git.add().addFilepattern("a").addFilepattern("b").call();
  529. RevCommit secondCommit = git.commit().setMessage("side").call();
  530. assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
  531. checkoutBranch("refs/heads/master");
  532. assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
  533. writeTrashFile("a", "1\na\n3(main)\n");
  534. writeTrashFile("c/c/c", "1\nc(main)\n3\n");
  535. git.add().addFilepattern("a").addFilepattern("c/c/c").call();
  536. RevCommit thirdCommit = git.commit().setMessage("main").call();
  537. writeTrashFile("d", "--- dirty ---");
  538. MergeResult result = git.merge().include(secondCommit.getId())
  539. .setStrategy(MergeStrategy.RESOLVE).call();
  540. assertEquals(MergeStatus.MERGED, result.getMergeStatus());
  541. assertEquals("1(side)\na\n3(main)\n", read(new File(db.getWorkTree(),
  542. "a")));
  543. assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
  544. assertEquals("1\nc(main)\n3\n", read(new File(db.getWorkTree(),
  545. "c/c/c")));
  546. assertEquals("--- dirty ---", read(new File(db.getWorkTree(), "d")));
  547. assertEquals(null, result.getConflicts());
  548. assertEquals(2, result.getMergedCommits().length);
  549. assertEquals(thirdCommit, result.getMergedCommits()[0]);
  550. assertEquals(secondCommit, result.getMergedCommits()[1]);
  551. Iterator<RevCommit> it = git.log().call().iterator();
  552. RevCommit newHead = it.next();
  553. assertEquals(newHead, result.getNewHead());
  554. assertEquals(2, newHead.getParentCount());
  555. assertEquals(thirdCommit, newHead.getParent(0));
  556. assertEquals(secondCommit, newHead.getParent(1));
  557. assertEquals(
  558. "Merge commit '064d54d98a4cdb0fed1802a21c656bfda67fe879'",
  559. newHead.getFullMessage());
  560. assertEquals(RepositoryState.SAFE, db.getRepositoryState());
  561. }
  562. }
  563. @Test
  564. public void testSingleDeletion() throws Exception {
  565. try (Git git = new Git(db)) {
  566. writeTrashFile("a", "1\na\n3\n");
  567. writeTrashFile("b", "1\nb\n3\n");
  568. writeTrashFile("d", "1\nd\n3\n");
  569. writeTrashFile("c/c/c", "1\nc\n3\n");
  570. git.add().addFilepattern("a").addFilepattern("b")
  571. .addFilepattern("c/c/c").addFilepattern("d").call();
  572. RevCommit initialCommit = git.commit().setMessage("initial").call();
  573. createBranch(initialCommit, "refs/heads/side");
  574. checkoutBranch("refs/heads/side");
  575. assertTrue(new File(db.getWorkTree(), "b").delete());
  576. git.add().addFilepattern("b").setUpdate(true).call();
  577. RevCommit secondCommit = git.commit().setMessage("side").call();
  578. assertFalse(new File(db.getWorkTree(), "b").exists());
  579. checkoutBranch("refs/heads/master");
  580. assertTrue(new File(db.getWorkTree(), "b").exists());
  581. writeTrashFile("a", "1\na\n3(main)\n");
  582. writeTrashFile("c/c/c", "1\nc(main)\n3\n");
  583. git.add().addFilepattern("a").addFilepattern("c/c/c").call();
  584. RevCommit thirdCommit = git.commit().setMessage("main").call();
  585. // We are merging a deletion into our branch
  586. MergeResult result = git.merge().include(secondCommit.getId())
  587. .setStrategy(MergeStrategy.RESOLVE).call();
  588. assertEquals(MergeStatus.MERGED, result.getMergeStatus());
  589. assertEquals("1\na\n3(main)\n", read(new File(db.getWorkTree(), "a")));
  590. assertFalse(new File(db.getWorkTree(), "b").exists());
  591. assertEquals("1\nc(main)\n3\n",
  592. read(new File(db.getWorkTree(), "c/c/c")));
  593. assertEquals("1\nd\n3\n", read(new File(db.getWorkTree(), "d")));
  594. // Do the opposite, be on a branch where we have deleted a file and
  595. // merge in a old commit where this file was not deleted
  596. checkoutBranch("refs/heads/side");
  597. assertFalse(new File(db.getWorkTree(), "b").exists());
  598. result = git.merge().include(thirdCommit.getId())
  599. .setStrategy(MergeStrategy.RESOLVE).call();
  600. assertEquals(MergeStatus.MERGED, result.getMergeStatus());
  601. assertEquals("1\na\n3(main)\n", read(new File(db.getWorkTree(), "a")));
  602. assertFalse(new File(db.getWorkTree(), "b").exists());
  603. assertEquals("1\nc(main)\n3\n",
  604. read(new File(db.getWorkTree(), "c/c/c")));
  605. assertEquals("1\nd\n3\n", read(new File(db.getWorkTree(), "d")));
  606. }
  607. }
  608. @Test
  609. public void testMultipleDeletions() throws Exception {
  610. try (Git git = new Git(db)) {
  611. writeTrashFile("a", "1\na\n3\n");
  612. git.add().addFilepattern("a").call();
  613. RevCommit initialCommit = git.commit().setMessage("initial").call();
  614. createBranch(initialCommit, "refs/heads/side");
  615. checkoutBranch("refs/heads/side");
  616. assertTrue(new File(db.getWorkTree(), "a").delete());
  617. git.add().addFilepattern("a").setUpdate(true).call();
  618. RevCommit secondCommit = git.commit().setMessage("side").call();
  619. assertFalse(new File(db.getWorkTree(), "a").exists());
  620. checkoutBranch("refs/heads/master");
  621. assertTrue(new File(db.getWorkTree(), "a").exists());
  622. assertTrue(new File(db.getWorkTree(), "a").delete());
  623. git.add().addFilepattern("a").setUpdate(true).call();
  624. git.commit().setMessage("main").call();
  625. // We are merging a deletion into our branch
  626. MergeResult result = git.merge().include(secondCommit.getId())
  627. .setStrategy(MergeStrategy.RESOLVE).call();
  628. assertEquals(MergeStatus.MERGED, result.getMergeStatus());
  629. }
  630. }
  631. @Test
  632. public void testDeletionAndConflict() throws Exception {
  633. try (Git git = new Git(db)) {
  634. writeTrashFile("a", "1\na\n3\n");
  635. writeTrashFile("b", "1\nb\n3\n");
  636. writeTrashFile("d", "1\nd\n3\n");
  637. writeTrashFile("c/c/c", "1\nc\n3\n");
  638. git.add().addFilepattern("a").addFilepattern("b")
  639. .addFilepattern("c/c/c").addFilepattern("d").call();
  640. RevCommit initialCommit = git.commit().setMessage("initial").call();
  641. createBranch(initialCommit, "refs/heads/side");
  642. checkoutBranch("refs/heads/side");
  643. assertTrue(new File(db.getWorkTree(), "b").delete());
  644. writeTrashFile("a", "1\na\n3(side)\n");
  645. git.add().addFilepattern("b").setUpdate(true).call();
  646. git.add().addFilepattern("a").setUpdate(true).call();
  647. RevCommit secondCommit = git.commit().setMessage("side").call();
  648. assertFalse(new File(db.getWorkTree(), "b").exists());
  649. checkoutBranch("refs/heads/master");
  650. assertTrue(new File(db.getWorkTree(), "b").exists());
  651. writeTrashFile("a", "1\na\n3(main)\n");
  652. writeTrashFile("c/c/c", "1\nc(main)\n3\n");
  653. git.add().addFilepattern("a").addFilepattern("c/c/c").call();
  654. git.commit().setMessage("main").call();
  655. // We are merging a deletion into our branch
  656. MergeResult result = git.merge().include(secondCommit.getId())
  657. .setStrategy(MergeStrategy.RESOLVE).call();
  658. assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
  659. assertEquals(
  660. "1\na\n<<<<<<< HEAD\n3(main)\n=======\n3(side)\n>>>>>>> 54ffed45d62d252715fc20e41da92d44c48fb0ff\n",
  661. read(new File(db.getWorkTree(), "a")));
  662. assertFalse(new File(db.getWorkTree(), "b").exists());
  663. assertEquals("1\nc(main)\n3\n",
  664. read(new File(db.getWorkTree(), "c/c/c")));
  665. assertEquals("1\nd\n3\n", read(new File(db.getWorkTree(), "d")));
  666. }
  667. }
  668. @Test
  669. public void testDeletionOnMasterConflict() throws Exception {
  670. try (Git git = new Git(db)) {
  671. writeTrashFile("a", "1\na\n3\n");
  672. writeTrashFile("b", "1\nb\n3\n");
  673. git.add().addFilepattern("a").addFilepattern("b").call();
  674. RevCommit initialCommit = git.commit().setMessage("initial").call();
  675. // create side branch and modify "a"
  676. createBranch(initialCommit, "refs/heads/side");
  677. checkoutBranch("refs/heads/side");
  678. writeTrashFile("a", "1\na(side)\n3\n");
  679. git.add().addFilepattern("a").call();
  680. RevCommit secondCommit = git.commit().setMessage("side").call();
  681. // delete a on master to generate conflict
  682. checkoutBranch("refs/heads/master");
  683. git.rm().addFilepattern("a").call();
  684. git.commit().setMessage("main").call();
  685. // merge side with master
  686. MergeResult result = git.merge().include(secondCommit.getId())
  687. .setStrategy(MergeStrategy.RESOLVE).call();
  688. assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
  689. // result should be 'a' conflicting with workspace content from side
  690. assertTrue(new File(db.getWorkTree(), "a").exists());
  691. assertEquals("1\na(side)\n3\n", read(new File(db.getWorkTree(), "a")));
  692. assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
  693. }
  694. }
  695. @Test
  696. public void testDeletionOnSideConflict() throws Exception {
  697. try (Git git = new Git(db)) {
  698. writeTrashFile("a", "1\na\n3\n");
  699. writeTrashFile("b", "1\nb\n3\n");
  700. git.add().addFilepattern("a").addFilepattern("b").call();
  701. RevCommit initialCommit = git.commit().setMessage("initial").call();
  702. // create side branch and delete "a"
  703. createBranch(initialCommit, "refs/heads/side");
  704. checkoutBranch("refs/heads/side");
  705. git.rm().addFilepattern("a").call();
  706. RevCommit secondCommit = git.commit().setMessage("side").call();
  707. // update a on master to generate conflict
  708. checkoutBranch("refs/heads/master");
  709. writeTrashFile("a", "1\na(main)\n3\n");
  710. git.add().addFilepattern("a").call();
  711. git.commit().setMessage("main").call();
  712. // merge side with master
  713. MergeResult result = git.merge().include(secondCommit.getId())
  714. .setStrategy(MergeStrategy.RESOLVE).call();
  715. assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
  716. assertTrue(new File(db.getWorkTree(), "a").exists());
  717. assertEquals("1\na(main)\n3\n", read(new File(db.getWorkTree(), "a")));
  718. assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
  719. assertEquals(1, result.getConflicts().size());
  720. assertEquals(3, result.getConflicts().get("a")[0].length);
  721. }
  722. }
  723. @Test
  724. public void testModifiedAndRenamed() throws Exception {
  725. // this test is essentially the same as testDeletionOnSideConflict,
  726. // however if once rename support is added this test should result in a
  727. // successful merge instead of a conflict
  728. try (Git git = new Git(db)) {
  729. writeTrashFile("x", "add x");
  730. git.add().addFilepattern("x").call();
  731. RevCommit initial = git.commit().setMessage("add x").call();
  732. createBranch(initial, "refs/heads/d1");
  733. createBranch(initial, "refs/heads/d2");
  734. // rename x to y on d1
  735. checkoutBranch("refs/heads/d1");
  736. new File(db.getWorkTree(), "x")
  737. .renameTo(new File(db.getWorkTree(), "y"));
  738. git.rm().addFilepattern("x").call();
  739. git.add().addFilepattern("y").call();
  740. RevCommit d1Commit = git.commit().setMessage("d1 rename x -> y").call();
  741. checkoutBranch("refs/heads/d2");
  742. writeTrashFile("x", "d2 change");
  743. git.add().addFilepattern("x").call();
  744. RevCommit d2Commit = git.commit().setMessage("d2 change in x").call();
  745. checkoutBranch("refs/heads/master");
  746. MergeResult d1Merge = git.merge().include(d1Commit).call();
  747. assertEquals(MergeResult.MergeStatus.FAST_FORWARD,
  748. d1Merge.getMergeStatus());
  749. MergeResult d2Merge = git.merge().include(d2Commit).call();
  750. assertEquals(MergeResult.MergeStatus.CONFLICTING,
  751. d2Merge.getMergeStatus());
  752. assertEquals(1, d2Merge.getConflicts().size());
  753. assertEquals(3, d2Merge.getConflicts().get("x")[0].length);
  754. }
  755. }
  756. @Test
  757. public void testMergeFailingWithDirtyWorkingTree() throws Exception {
  758. try (Git git = new Git(db)) {
  759. writeTrashFile("a", "1\na\n3\n");
  760. writeTrashFile("b", "1\nb\n3\n");
  761. git.add().addFilepattern("a").addFilepattern("b").call();
  762. RevCommit initialCommit = git.commit().setMessage("initial").call();
  763. createBranch(initialCommit, "refs/heads/side");
  764. checkoutBranch("refs/heads/side");
  765. writeTrashFile("a", "1(side)\na\n3\n");
  766. writeTrashFile("b", "1\nb(side)\n3\n");
  767. git.add().addFilepattern("a").addFilepattern("b").call();
  768. RevCommit secondCommit = git.commit().setMessage("side").call();
  769. assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
  770. checkoutBranch("refs/heads/master");
  771. assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
  772. writeTrashFile("a", "1\na\n3(main)\n");
  773. git.add().addFilepattern("a").call();
  774. git.commit().setMessage("main").call();
  775. writeTrashFile("a", "--- dirty ---");
  776. MergeResult result = git.merge().include(secondCommit.getId())
  777. .setStrategy(MergeStrategy.RESOLVE).call();
  778. assertEquals(MergeStatus.FAILED, result.getMergeStatus());
  779. assertEquals("--- dirty ---", read(new File(db.getWorkTree(), "a")));
  780. assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
  781. assertEquals(null, result.getConflicts());
  782. assertEquals(RepositoryState.SAFE, db.getRepositoryState());
  783. }
  784. }
  785. @Test
  786. public void testMergeConflictFileFolder() throws Exception {
  787. try (Git git = new Git(db)) {
  788. writeTrashFile("a", "1\na\n3\n");
  789. writeTrashFile("b", "1\nb\n3\n");
  790. git.add().addFilepattern("a").addFilepattern("b").call();
  791. RevCommit initialCommit = git.commit().setMessage("initial").call();
  792. createBranch(initialCommit, "refs/heads/side");
  793. checkoutBranch("refs/heads/side");
  794. writeTrashFile("c/c/c", "1\nc(side)\n3\n");
  795. writeTrashFile("d", "1\nd(side)\n3\n");
  796. git.add().addFilepattern("c/c/c").addFilepattern("d").call();
  797. RevCommit secondCommit = git.commit().setMessage("side").call();
  798. checkoutBranch("refs/heads/master");
  799. writeTrashFile("c", "1\nc(main)\n3\n");
  800. writeTrashFile("d/d/d", "1\nd(main)\n3\n");
  801. git.add().addFilepattern("c").addFilepattern("d/d/d").call();
  802. git.commit().setMessage("main").call();
  803. MergeResult result = git.merge().include(secondCommit.getId())
  804. .setStrategy(MergeStrategy.RESOLVE).call();
  805. assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
  806. assertEquals("1\na\n3\n", read(new File(db.getWorkTree(), "a")));
  807. assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
  808. assertEquals("1\nc(main)\n3\n", read(new File(db.getWorkTree(), "c")));
  809. assertEquals("1\nd(main)\n3\n", read(new File(db.getWorkTree(), "d/d/d")));
  810. assertEquals(null, result.getConflicts());
  811. assertEquals(RepositoryState.MERGING, db.getRepositoryState());
  812. }
  813. }
  814. @Test
  815. public void testSuccessfulMergeFailsDueToDirtyIndex() throws Exception {
  816. try (Git git = new Git(db)) {
  817. File fileA = writeTrashFile("a", "a");
  818. RevCommit initialCommit = addAllAndCommit(git);
  819. // switch branch
  820. createBranch(initialCommit, "refs/heads/side");
  821. checkoutBranch("refs/heads/side");
  822. // modify file a
  823. write(fileA, "a(side)");
  824. writeTrashFile("b", "b");
  825. RevCommit sideCommit = addAllAndCommit(git);
  826. // switch branch
  827. checkoutBranch("refs/heads/master");
  828. writeTrashFile("c", "c");
  829. addAllAndCommit(git);
  830. // modify and add file a
  831. write(fileA, "a(modified)");
  832. git.add().addFilepattern("a").call();
  833. // do not commit
  834. // get current index state
  835. String indexState = indexState(CONTENT);
  836. // merge
  837. MergeResult result = git.merge().include(sideCommit.getId())
  838. .setStrategy(MergeStrategy.RESOLVE).call();
  839. checkMergeFailedResult(result, MergeFailureReason.DIRTY_INDEX,
  840. indexState, fileA);
  841. }
  842. }
  843. @Test
  844. public void testConflictingMergeFailsDueToDirtyIndex() throws Exception {
  845. try (Git git = new Git(db)) {
  846. File fileA = writeTrashFile("a", "a");
  847. RevCommit initialCommit = addAllAndCommit(git);
  848. // switch branch
  849. createBranch(initialCommit, "refs/heads/side");
  850. checkoutBranch("refs/heads/side");
  851. // modify file a
  852. write(fileA, "a(side)");
  853. writeTrashFile("b", "b");
  854. RevCommit sideCommit = addAllAndCommit(git);
  855. // switch branch
  856. checkoutBranch("refs/heads/master");
  857. // modify file a - this will cause a conflict during merge
  858. write(fileA, "a(master)");
  859. writeTrashFile("c", "c");
  860. addAllAndCommit(git);
  861. // modify and add file a
  862. write(fileA, "a(modified)");
  863. git.add().addFilepattern("a").call();
  864. // do not commit
  865. // get current index state
  866. String indexState = indexState(CONTENT);
  867. // merge
  868. MergeResult result = git.merge().include(sideCommit.getId())
  869. .setStrategy(MergeStrategy.RESOLVE).call();
  870. checkMergeFailedResult(result, MergeFailureReason.DIRTY_INDEX,
  871. indexState, fileA);
  872. }
  873. }
  874. @Test
  875. public void testSuccessfulMergeFailsDueToDirtyWorktree() throws Exception {
  876. try (Git git = new Git(db)) {
  877. File fileA = writeTrashFile("a", "a");
  878. RevCommit initialCommit = addAllAndCommit(git);
  879. // switch branch
  880. createBranch(initialCommit, "refs/heads/side");
  881. checkoutBranch("refs/heads/side");
  882. // modify file a
  883. write(fileA, "a(side)");
  884. writeTrashFile("b", "b");
  885. RevCommit sideCommit = addAllAndCommit(git);
  886. // switch branch
  887. checkoutBranch("refs/heads/master");
  888. writeTrashFile("c", "c");
  889. addAllAndCommit(git);
  890. // modify file a
  891. write(fileA, "a(modified)");
  892. // do not add and commit
  893. // get current index state
  894. String indexState = indexState(CONTENT);
  895. // merge
  896. MergeResult result = git.merge().include(sideCommit.getId())
  897. .setStrategy(MergeStrategy.RESOLVE).call();
  898. checkMergeFailedResult(result, MergeFailureReason.DIRTY_WORKTREE,
  899. indexState, fileA);
  900. }
  901. }
  902. @Test
  903. public void testConflictingMergeFailsDueToDirtyWorktree() throws Exception {
  904. try (Git git = new Git(db)) {
  905. File fileA = writeTrashFile("a", "a");
  906. RevCommit initialCommit = addAllAndCommit(git);
  907. // switch branch
  908. createBranch(initialCommit, "refs/heads/side");
  909. checkoutBranch("refs/heads/side");
  910. // modify file a
  911. write(fileA, "a(side)");
  912. writeTrashFile("b", "b");
  913. RevCommit sideCommit = addAllAndCommit(git);
  914. // switch branch
  915. checkoutBranch("refs/heads/master");
  916. // modify file a - this will cause a conflict during merge
  917. write(fileA, "a(master)");
  918. writeTrashFile("c", "c");
  919. addAllAndCommit(git);
  920. // modify file a
  921. write(fileA, "a(modified)");
  922. // do not add and commit
  923. // get current index state
  924. String indexState = indexState(CONTENT);
  925. // merge
  926. MergeResult result = git.merge().include(sideCommit.getId())
  927. .setStrategy(MergeStrategy.RESOLVE).call();
  928. checkMergeFailedResult(result, MergeFailureReason.DIRTY_WORKTREE,
  929. indexState, fileA);
  930. }
  931. }
  932. @Test
  933. public void testMergeRemovingFolders() throws Exception {
  934. File folder1 = new File(db.getWorkTree(), "folder1");
  935. File folder2 = new File(db.getWorkTree(), "folder2");
  936. FileUtils.mkdir(folder1);
  937. FileUtils.mkdir(folder2);
  938. File file = new File(folder1, "file1.txt");
  939. write(file, "folder1--file1.txt");
  940. file = new File(folder1, "file2.txt");
  941. write(file, "folder1--file2.txt");
  942. file = new File(folder2, "file1.txt");
  943. write(file, "folder--file1.txt");
  944. file = new File(folder2, "file2.txt");
  945. write(file, "folder2--file2.txt");
  946. try (Git git = new Git(db)) {
  947. git.add().addFilepattern(folder1.getName())
  948. .addFilepattern(folder2.getName()).call();
  949. RevCommit commit1 = git.commit().setMessage("adding folders").call();
  950. recursiveDelete(folder1);
  951. recursiveDelete(folder2);
  952. git.rm().addFilepattern("folder1/file1.txt")
  953. .addFilepattern("folder1/file2.txt")
  954. .addFilepattern("folder2/file1.txt")
  955. .addFilepattern("folder2/file2.txt").call();
  956. RevCommit commit2 = git.commit()
  957. .setMessage("removing folders on 'branch'").call();
  958. git.checkout().setName(commit1.name()).call();
  959. MergeResult result = git.merge().include(commit2.getId())
  960. .setStrategy(MergeStrategy.RESOLVE).call();
  961. assertEquals(MergeResult.MergeStatus.FAST_FORWARD,
  962. result.getMergeStatus());
  963. assertEquals(commit2, result.getNewHead());
  964. assertFalse(folder1.exists());
  965. assertFalse(folder2.exists());
  966. }
  967. }
  968. @Test
  969. public void testMergeRemovingFoldersWithoutFastForward() throws Exception {
  970. File folder1 = new File(db.getWorkTree(), "folder1");
  971. File folder2 = new File(db.getWorkTree(), "folder2");
  972. FileUtils.mkdir(folder1);
  973. FileUtils.mkdir(folder2);
  974. File file = new File(folder1, "file1.txt");
  975. write(file, "folder1--file1.txt");
  976. file = new File(folder1, "file2.txt");
  977. write(file, "folder1--file2.txt");
  978. file = new File(folder2, "file1.txt");
  979. write(file, "folder--file1.txt");
  980. file = new File(folder2, "file2.txt");
  981. write(file, "folder2--file2.txt");
  982. try (Git git = new Git(db)) {
  983. git.add().addFilepattern(folder1.getName())
  984. .addFilepattern(folder2.getName()).call();
  985. RevCommit base = git.commit().setMessage("adding folders").call();
  986. recursiveDelete(folder1);
  987. recursiveDelete(folder2);
  988. git.rm().addFilepattern("folder1/file1.txt")
  989. .addFilepattern("folder1/file2.txt")
  990. .addFilepattern("folder2/file1.txt")
  991. .addFilepattern("folder2/file2.txt").call();
  992. RevCommit other = git.commit()
  993. .setMessage("removing folders on 'branch'").call();
  994. git.checkout().setName(base.name()).call();
  995. file = new File(folder2, "file3.txt");
  996. write(file, "folder2--file3.txt");
  997. git.add().addFilepattern(folder2.getName()).call();
  998. git.commit().setMessage("adding another file").call();
  999. MergeResult result = git.merge().include(other.getId())
  1000. .setStrategy(MergeStrategy.RESOLVE).call();
  1001. assertEquals(MergeResult.MergeStatus.MERGED,
  1002. result.getMergeStatus());
  1003. assertFalse(folder1.exists());
  1004. }
  1005. }
  1006. @Test
  1007. public void testFileModeMerge() throws Exception {
  1008. // Only Java6
  1009. assumeTrue(FS.DETECTED.supportsExecute());
  1010. try (Git git = new Git(db)) {
  1011. writeTrashFile("mergeableMode", "a");
  1012. setExecutable(git, "mergeableMode", false);
  1013. writeTrashFile("conflictingModeWithBase", "a");
  1014. setExecutable(git, "conflictingModeWithBase", false);
  1015. RevCommit initialCommit = addAllAndCommit(git);
  1016. // switch branch
  1017. createBranch(initialCommit, "refs/heads/side");
  1018. checkoutBranch("refs/heads/side");
  1019. setExecutable(git, "mergeableMode", true);
  1020. writeTrashFile("conflictingModeNoBase", "b");
  1021. setExecutable(git, "conflictingModeNoBase", true);
  1022. RevCommit sideCommit = addAllAndCommit(git);
  1023. // switch branch
  1024. createBranch(initialCommit, "refs/heads/side2");
  1025. checkoutBranch("refs/heads/side2");
  1026. setExecutable(git, "mergeableMode", false);
  1027. assertFalse(new File(git.getRepository().getWorkTree(),
  1028. "conflictingModeNoBase").exists());
  1029. writeTrashFile("conflictingModeNoBase", "b");
  1030. setExecutable(git, "conflictingModeNoBase", false);
  1031. addAllAndCommit(git);
  1032. // merge
  1033. MergeResult result = git.merge().include(sideCommit.getId())
  1034. .setStrategy(MergeStrategy.RESOLVE).call();
  1035. assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
  1036. assertTrue(canExecute(git, "mergeableMode"));
  1037. assertFalse(canExecute(git, "conflictingModeNoBase"));
  1038. }
  1039. }
  1040. @Test
  1041. public void testFileModeMergeWithDirtyWorkTree() throws Exception {
  1042. // Only Java6 (or set x bit in index)
  1043. assumeTrue(FS.DETECTED.supportsExecute());
  1044. try (Git git = new Git(db)) {
  1045. writeTrashFile("mergeableButDirty", "a");
  1046. setExecutable(git, "mergeableButDirty", false);
  1047. RevCommit initialCommit = addAllAndCommit(git);
  1048. // switch branch
  1049. createBranch(initialCommit, "refs/heads/side");
  1050. checkoutBranch("refs/heads/side");
  1051. setExecutable(git, "mergeableButDirty", true);
  1052. RevCommit sideCommit = addAllAndCommit(git);
  1053. // switch branch
  1054. createBranch(initialCommit, "refs/heads/side2");
  1055. checkoutBranch("refs/heads/side2");
  1056. setExecutable(git, "mergeableButDirty", false);
  1057. addAllAndCommit(git);
  1058. writeTrashFile("mergeableButDirty", "b");
  1059. // merge
  1060. MergeResult result = git.merge().include(sideCommit.getId())
  1061. .setStrategy(MergeStrategy.RESOLVE).call();
  1062. assertEquals(MergeStatus.FAILED, result.getMergeStatus());
  1063. assertFalse(canExecute(git, "mergeableButDirty"));
  1064. }
  1065. }
  1066. @Test
  1067. public void testSquashFastForward() throws Exception {
  1068. try (Git git = new Git(db)) {
  1069. writeTrashFile("file1", "file1");
  1070. git.add().addFilepattern("file1").call();
  1071. RevCommit first = git.commit().setMessage("initial commit").call();
  1072. assertTrue(new File(db.getWorkTree(), "file1").exists());
  1073. createBranch(first, "refs/heads/branch1");
  1074. checkoutBranch("refs/heads/branch1");
  1075. writeTrashFile("file2", "file2");
  1076. git.add().addFilepattern("file2").call();
  1077. RevCommit second = git.commit().setMessage("second commit").call();
  1078. assertTrue(new File(db.getWorkTree(), "file2").exists());
  1079. writeTrashFile("file3", "file3");
  1080. git.add().addFilepattern("file3").call();
  1081. RevCommit third = git.commit().setMessage("third commit").call();
  1082. assertTrue(new File(db.getWorkTree(), "file3").exists());
  1083. checkoutBranch("refs/heads/master");
  1084. assertTrue(new File(db.getWorkTree(), "file1").exists());
  1085. assertFalse(new File(db.getWorkTree(), "file2").exists());
  1086. assertFalse(new File(db.getWorkTree(), "file3").exists());
  1087. MergeResult result = git.merge()
  1088. .include(db.exactRef("refs/heads/branch1"))
  1089. .setSquash(true)
  1090. .call();
  1091. assertTrue(new File(db.getWorkTree(), "file1").exists());
  1092. assertTrue(new File(db.getWorkTree(), "file2").exists());
  1093. assertTrue(new File(db.getWorkTree(), "file3").exists());
  1094. assertEquals(MergeResult.MergeStatus.FAST_FORWARD_SQUASHED,
  1095. result.getMergeStatus());
  1096. assertEquals(first, result.getNewHead()); // HEAD didn't move
  1097. assertEquals(first, db.resolve(Constants.HEAD + "^{commit}"));
  1098. assertEquals(
  1099. "Squashed commit of the following:\n\ncommit "
  1100. + third.getName()
  1101. + "\nAuthor: "
  1102. + third.getAuthorIdent().getName()
  1103. + " <"
  1104. + third.getAuthorIdent().getEmailAddress()
  1105. + ">\nDate: "
  1106. + dateFormatter.formatDate(third
  1107. .getAuthorIdent())
  1108. + "\n\n\tthird commit\n\ncommit "
  1109. + second.getName()
  1110. + "\nAuthor: "
  1111. + second.getAuthorIdent().getName()
  1112. + " <"
  1113. + second.getAuthorIdent().getEmailAddress()
  1114. + ">\nDate: "
  1115. + dateFormatter.formatDate(second
  1116. .getAuthorIdent()) + "\n\n\tsecond commit\n",
  1117. db.readSquashCommitMsg());
  1118. assertNull(db.readMergeCommitMsg());
  1119. Status stat = git.status().call();
  1120. assertEquals(Sets.of("file2", "file3"), stat.getAdded());
  1121. }
  1122. }
  1123. @Test
  1124. public void testSquashMerge() throws Exception {
  1125. try (Git git = new Git(db)) {
  1126. writeTrashFile("file1", "file1");
  1127. git.add().addFilepattern("file1").call();
  1128. RevCommit first = git.commit().setMessage("initial commit").call();
  1129. assertTrue(new File(db.getWorkTree(), "file1").exists());
  1130. createBranch(first, "refs/heads/branch1");
  1131. writeTrashFile("file2", "file2");
  1132. git.add().addFilepattern("file2").call();
  1133. RevCommit second = git.commit().setMessage("second commit").call();
  1134. assertTrue(new File(db.getWorkTree(), "file2").exists());
  1135. checkoutBranch("refs/heads/branch1");
  1136. writeTrashFile("file3", "file3");
  1137. git.add().addFilepattern("file3").call();
  1138. RevCommit third = git.commit().setMessage("third commit").call();
  1139. assertTrue(new File(db.getWorkTree(), "file3").exists());
  1140. checkoutBranch("refs/heads/master");
  1141. assertTrue(new File(db.getWorkTree(), "file1").exists());
  1142. assertTrue(new File(db.getWorkTree(), "file2").exists());
  1143. assertFalse(new File(db.getWorkTree(), "file3").exists());
  1144. MergeResult result = git.merge()
  1145. .include(db.exactRef("refs/heads/branch1"))
  1146. .setSquash(true)
  1147. .call();
  1148. assertTrue(new File(db.getWorkTree(), "file1").exists());
  1149. assertTrue(new File(db.getWorkTree(), "file2").exists());
  1150. assertTrue(new File(db.getWorkTree(), "file3").exists());
  1151. assertEquals(MergeResult.MergeStatus.MERGED_SQUASHED,
  1152. result.getMergeStatus());
  1153. assertEquals(second, result.getNewHead()); // HEAD didn't move
  1154. assertEquals(second, db.resolve(Constants.HEAD + "^{commit}"));
  1155. assertEquals(
  1156. "Squashed commit of the following:\n\ncommit "
  1157. + third.getName()
  1158. + "\nAuthor: "
  1159. + third.getAuthorIdent().getName()
  1160. + " <"
  1161. + third.getAuthorIdent().getEmailAddress()
  1162. + ">\nDate: "
  1163. + dateFormatter.formatDate(third
  1164. .getAuthorIdent()) + "\n\n\tthird commit\n",
  1165. db.readSquashCommitMsg());
  1166. assertNull(db.readMergeCommitMsg());
  1167. Status stat = git.status().call();
  1168. assertEquals(Sets.of("file3"), stat.getAdded());
  1169. }
  1170. }
  1171. @Test
  1172. public void testSquashMergeConflict() throws Exception {
  1173. try (Git git = new Git(db)) {
  1174. writeTrashFile("file1", "file1");
  1175. git.add().addFilepattern("file1").call();
  1176. RevCommit first = git.commit().setMessage("initial commit").call();
  1177. assertTrue(new File(db.getWorkTree(), "file1").exists());
  1178. createBranch(first, "refs/heads/branch1");
  1179. writeTrashFile("file2", "master");
  1180. git.add().addFilepattern("file2").call();
  1181. RevCommit second = git.commit().setMessage("second commit").call();
  1182. assertTrue(new File(db.getWorkTree(), "file2").exists());
  1183. checkoutBranch("refs/heads/branch1");
  1184. writeTrashFile("file2", "branch");
  1185. git.add().addFilepattern("file2").call();
  1186. RevCommit third = git.commit().setMessage("third commit").call();
  1187. assertTrue(new File(db.getWorkTree(), "file2").exists());
  1188. checkoutBranch("refs/heads/master");
  1189. assertTrue(new File(db.getWorkTree(), "file1").exists());
  1190. assertTrue(new File(db.getWorkTree(), "file2").exists());
  1191. MergeResult result = git.merge()
  1192. .include(db.exactRef("refs/heads/branch1"))
  1193. .setSquash(true)
  1194. .call();
  1195. assertTrue(new File(db.getWorkTree(), "file1").exists());
  1196. assertTrue(new File(db.getWorkTree(), "file2").exists());
  1197. assertEquals(MergeResult.MergeStatus.CONFLICTING,
  1198. result.getMergeStatus());
  1199. assertNull(result.getNewHead());
  1200. assertEquals(second, db.resolve(Constants.HEAD + "^{commit}"));
  1201. assertEquals(
  1202. "Squashed commit of the following:\n\ncommit "
  1203. + third.getName()
  1204. + "\nAuthor: "
  1205. + third.getAuthorIdent().getName()
  1206. + " <"
  1207. + third.getAuthorIdent().getEmailAddress()
  1208. + ">\nDate: "
  1209. + dateFormatter.formatDate(third
  1210. .getAuthorIdent()) + "\n\n\tthird commit\n",
  1211. db.readSquashCommitMsg());
  1212. assertEquals("\nConflicts:\n\tfile2\n", db.readMergeCommitMsg());
  1213. Status stat = git.status().call();
  1214. assertEquals(Sets.of("file2"), stat.getConflicting());
  1215. }
  1216. }
  1217. @Test
  1218. public void testFastForwardOnly() throws Exception {
  1219. try (Git git = new Git(db)) {
  1220. RevCommit initialCommit = git.commit().setMessage("initial commit")
  1221. .call();
  1222. createBranch(initialCommit, "refs/heads/branch1");
  1223. git.commit().setMessage("second commit").call();
  1224. checkoutBranch("refs/heads/branch1");
  1225. MergeCommand merge = git.merge();
  1226. merge.setFastForward(FastForwardMode.FF_ONLY);
  1227. merge.include(db.exactRef(R_HEADS + MASTER));
  1228. MergeResult result = merge.call();
  1229. assertEquals(MergeStatus.FAST_FORWARD, result.getMergeStatus());
  1230. }
  1231. }
  1232. @Test
  1233. public void testNoFastForward() throws Exception {
  1234. try (Git git = new Git(db)) {
  1235. RevCommit initialCommit = git.commit().setMessage("initial commit")
  1236. .call();
  1237. createBranch(initialCommit, "refs/heads/branch1");
  1238. git.commit().setMessage("second commit").call();
  1239. checkoutBranch("refs/heads/branch1");
  1240. MergeCommand merge = git.merge();
  1241. merge.setFastForward(FastForwardMode.NO_FF);
  1242. merge.include(db.exactRef(R_HEADS + MASTER));
  1243. MergeResult result = merge.call();
  1244. assertEquals(MergeStatus.MERGED, result.getMergeStatus());
  1245. }
  1246. }
  1247. @Test
  1248. public void testNoFastForwardNoCommit() throws Exception {
  1249. // given
  1250. try (Git git = new Git(db)) {
  1251. RevCommit initialCommit = git.commit().setMessage("initial commit")
  1252. .call();
  1253. createBranch(initialCommit, "refs/heads/branch1");
  1254. RevCommit secondCommit = git.commit().setMessage("second commit")
  1255. .call();
  1256. checkoutBranch("refs/heads/branch1");
  1257. // when
  1258. MergeCommand merge = git.merge();
  1259. merge.setFastForward(FastForwardMode.NO_FF);
  1260. merge.include(db.exactRef(R_HEADS + MASTER));
  1261. merge.setCommit(false);
  1262. MergeResult result = merge.call();
  1263. // then
  1264. assertEquals(MergeStatus.MERGED_NOT_COMMITTED, result.getMergeStatus());
  1265. assertEquals(2, result.getMergedCommits().length);
  1266. assertEquals(initialCommit, result.getMergedCommits()[0]);
  1267. assertEquals(secondCommit, result.getMergedCommits()[1]);
  1268. assertNull(result.getNewHead());
  1269. assertEquals(RepositoryState.MERGING_RESOLVED, db.getRepositoryState());
  1270. }
  1271. }
  1272. @Test
  1273. public void testFastForwardOnlyNotPossible() throws Exception {
  1274. try (Git git = new Git(db)) {
  1275. RevCommit initialCommit = git.commit().setMessage("initial commit")
  1276. .call();
  1277. createBranch(initialCommit, "refs/heads/branch1");
  1278. git.commit().setMessage("second commit").call();
  1279. checkoutBranch("refs/heads/branch1");
  1280. writeTrashFile("file1", "branch1");
  1281. git.add().addFilepattern("file").call();
  1282. git.commit().setMessage("second commit on branch1").call();
  1283. MergeCommand merge = git.merge();
  1284. merge.setFastForward(FastForwardMode.FF_ONLY);
  1285. merge.include(db.exactRef(R_HEADS + MASTER));
  1286. MergeResult result = merge.call();
  1287. assertEquals(MergeStatus.ABORTED, result.getMergeStatus());
  1288. }
  1289. }
  1290. @Test
  1291. public void testRecursiveMergeWithConflict() throws Exception {
  1292. TestRepository<Repository> db_t = new TestRepository<>(db);
  1293. BranchBuilder master = db_t.branch("master");
  1294. RevCommit m0 = master.commit().add("f", "1\n2\n3\n4\n5\n6\n7\n8\n9\n")
  1295. .message("m0").create();
  1296. RevCommit m1 = master.commit()
  1297. .add("f", "1-master\n2\n3\n4\n5\n6\n7\n8\n9\n").message("m1")
  1298. .create();
  1299. db_t.getRevWalk().parseCommit(m1);
  1300. BranchBuilder side = db_t.branch("side");
  1301. RevCommit s1 = side.commit().parent(m0)
  1302. .add("f", "1\n2\n3\n4\n5\n6\n7\n8\n9-side\n").message("s1")
  1303. .create();
  1304. RevCommit s2 = side.commit().parent(m1)
  1305. .add("f", "1-master\n2\n3\n4\n5\n6\n7-res(side)\n8\n9-side\n")
  1306. .message("s2(merge)").create();
  1307. master.commit().parent(s1)
  1308. .add("f", "1-master\n2\n3\n4\n5\n6\n7-conflict\n8\n9-side\n")
  1309. .message("m2(merge)").create();
  1310. Git git = Git.wrap(db);
  1311. git.checkout().setName("master").call();
  1312. MergeResult result = git.merge().setStrategy(MergeStrategy.RECURSIVE)
  1313. .include("side", s2).call();
  1314. assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
  1315. }
  1316. private Ref prepareSuccessfulMerge(Git git) throws Exception {
  1317. writeTrashFile("a", "1\na\n3\n");
  1318. git.add().addFilepattern("a").call();
  1319. RevCommit initialCommit = git.commit().setMessage("initial").call();
  1320. createBranch(initialCommit, "refs/heads/side");
  1321. checkoutBranch("refs/heads/side");
  1322. writeTrashFile("b", "1\nb\n3\n");
  1323. git.add().addFilepattern("b").call();
  1324. git.commit().setMessage("side").call();
  1325. checkoutBranch("refs/heads/master");
  1326. writeTrashFile("c", "1\nc\n3\n");
  1327. git.add().addFilepattern("c").call();
  1328. git.commit().setMessage("main").call();
  1329. return db.exactRef("refs/heads/side");
  1330. }
  1331. @Test
  1332. public void testMergeWithMessageOption() throws Exception {
  1333. try (Git git = new Git(db)) {
  1334. Ref sideBranch = prepareSuccessfulMerge(git);
  1335. git.merge().include(sideBranch).setStrategy(MergeStrategy.RESOLVE)
  1336. .setMessage("user message").call();
  1337. assertNull(db.readMergeCommitMsg());
  1338. Iterator<RevCommit> it = git.log().call().iterator();
  1339. RevCommit newHead = it.next();
  1340. assertEquals("user message", newHead.getFullMessage());
  1341. }
  1342. }
  1343. @Test
  1344. public void testMergeWithChangeId() throws Exception {
  1345. try (Git git = new Git(db)) {
  1346. Ref sideBranch = prepareSuccessfulMerge(git);
  1347. git.merge().include(sideBranch).setStrategy(MergeStrategy.RESOLVE)
  1348. .setInsertChangeId(true).call();
  1349. assertNull(db.readMergeCommitMsg());
  1350. Iterator<RevCommit> it = git.log().call().iterator();
  1351. RevCommit newHead = it.next();
  1352. String commitMessage = newHead.getFullMessage();
  1353. assertTrue(Pattern.compile("\nChange-Id: I[0-9a-fA-F]{40}\n")
  1354. .matcher(commitMessage).find());
  1355. }
  1356. }
  1357. @Test
  1358. public void testMergeWithMessageAndChangeId() throws Exception {
  1359. try (Git git = new Git(db)) {
  1360. Ref sideBranch = prepareSuccessfulMerge(git);
  1361. git.merge().include(sideBranch).setStrategy(MergeStrategy.RESOLVE)
  1362. .setMessage("user message").setInsertChangeId(true).call();
  1363. assertNull(db.readMergeCommitMsg());
  1364. Iterator<RevCommit> it = git.log().call().iterator();
  1365. RevCommit newHead = it.next();
  1366. String commitMessage = newHead.getFullMessage();
  1367. assertTrue(commitMessage.startsWith("user message\n\n"));
  1368. assertTrue(Pattern.compile("\nChange-Id: I[0-9a-fA-F]{40}\n")
  1369. .matcher(commitMessage).find());
  1370. }
  1371. }
  1372. @Test
  1373. public void testMergeConflictWithMessageOption() throws Exception {
  1374. try (Git git = new Git(db)) {
  1375. writeTrashFile("a", "1\na\n3\n");
  1376. git.add().addFilepattern("a").call();
  1377. RevCommit initialCommit = git.commit().setMessage("initial").call();
  1378. createBranch(initialCommit, "refs/heads/side");
  1379. checkoutBranch("refs/heads/side");
  1380. writeTrashFile("a", "1\na(side)\n3\n");
  1381. git.add().addFilepattern("a").call();
  1382. git.commit().setMessage("side").call();
  1383. checkoutBranch("refs/heads/master");
  1384. writeTrashFile("a", "1\na(main)\n3\n");
  1385. git.add().addFilepattern("a").call();
  1386. git.commit().setMessage("main").call();
  1387. Ref sideBranch = db.exactRef("refs/heads/side");
  1388. git.merge().include(sideBranch).setStrategy(MergeStrategy.RESOLVE)
  1389. .setMessage("user message").call();
  1390. assertEquals("user message\n\nConflicts:\n\ta\n",
  1391. db.readMergeCommitMsg());
  1392. }
  1393. }
  1394. private static void setExecutable(Git git, String path, boolean executable) {
  1395. FS.DETECTED.setExecute(
  1396. new File(git.getRepository().getWorkTree(), path), executable);
  1397. }
  1398. private static boolean canExecute(Git git, String path) {
  1399. return FS.DETECTED.canExecute(new File(git.getRepository()
  1400. .getWorkTree(), path));
  1401. }
  1402. private static RevCommit addAllAndCommit(Git git) throws Exception {
  1403. git.add().addFilepattern(".").call();
  1404. return git.commit().setMessage("message").call();
  1405. }
  1406. private void checkMergeFailedResult(final MergeResult result,
  1407. final MergeFailureReason reason,
  1408. final String indexState, final File fileA) throws Exception {
  1409. assertEquals(MergeStatus.FAILED, result.getMergeStatus());
  1410. assertEquals(reason, result.getFailingPaths().get("a"));
  1411. assertEquals("a(modified)", read(fileA));
  1412. assertFalse(new File(db.getWorkTree(), "b").exists());
  1413. assertEquals("c", read(new File(db.getWorkTree(), "c")));
  1414. assertEquals(indexState, indexState(CONTENT));
  1415. assertEquals(null, result.getConflicts());
  1416. assertEquals(RepositoryState.SAFE, db.getRepositoryState());
  1417. }
  1418. }