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

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