Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

MergeCommandTest.java 47KB

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