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

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