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.

RecursiveMergerTest.java 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  1. /*
  2. * Copyright (C) 2012, Christian Halstrick <christian.halstrick@sap.com>
  3. * and other copyright owners as documented in the project's IP log.
  4. *
  5. * This program and the accompanying materials are made available
  6. * under the terms of the Eclipse Distribution License v1.0 which
  7. * accompanies this distribution, is reproduced below, and is
  8. * available at http://www.eclipse.org/org/documents/edl-v10.php
  9. *
  10. * All rights reserved.
  11. *
  12. * Redistribution and use in source and binary forms, with or
  13. * without modification, are permitted provided that the following
  14. * conditions are met:
  15. *
  16. * - Redistributions of source code must retain the above copyright
  17. * notice, this list of conditions and the following disclaimer.
  18. *
  19. * - Redistributions in binary form must reproduce the above
  20. * copyright notice, this list of conditions and the following
  21. * disclaimer in the documentation and/or other materials provided
  22. * with the distribution.
  23. *
  24. * - Neither the name of the Eclipse Foundation, Inc. nor the
  25. * names of its contributors may be used to endorse or promote
  26. * products derived from this software without specific prior
  27. * written permission.
  28. *
  29. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  30. * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  31. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  32. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  33. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  34. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  35. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  36. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  37. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  38. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  39. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  40. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  41. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  42. */
  43. package org.eclipse.jgit.merge;
  44. import static org.junit.Assert.assertEquals;
  45. import static org.junit.Assert.assertFalse;
  46. import java.io.BufferedReader;
  47. import java.io.File;
  48. import java.io.FileOutputStream;
  49. import java.io.IOException;
  50. import java.io.InputStreamReader;
  51. import org.eclipse.jgit.api.Git;
  52. import org.eclipse.jgit.dircache.DirCache;
  53. import org.eclipse.jgit.dircache.DirCacheEditor;
  54. import org.eclipse.jgit.dircache.DirCacheEntry;
  55. import org.eclipse.jgit.errors.MissingObjectException;
  56. import org.eclipse.jgit.errors.NoMergeBaseException;
  57. import org.eclipse.jgit.errors.NoMergeBaseException.MergeBaseFailureReason;
  58. import org.eclipse.jgit.junit.RepositoryTestCase;
  59. import org.eclipse.jgit.junit.TestRepository;
  60. import org.eclipse.jgit.junit.TestRepository.BranchBuilder;
  61. import org.eclipse.jgit.lib.AnyObjectId;
  62. import org.eclipse.jgit.lib.Constants;
  63. import org.eclipse.jgit.lib.FileMode;
  64. import org.eclipse.jgit.lib.ObjectId;
  65. import org.eclipse.jgit.lib.ObjectLoader;
  66. import org.eclipse.jgit.lib.ObjectReader;
  67. import org.eclipse.jgit.lib.Repository;
  68. import org.eclipse.jgit.revwalk.RevBlob;
  69. import org.eclipse.jgit.revwalk.RevCommit;
  70. import org.eclipse.jgit.storage.file.FileRepository;
  71. import org.eclipse.jgit.treewalk.FileTreeIterator;
  72. import org.eclipse.jgit.treewalk.TreeWalk;
  73. import org.eclipse.jgit.treewalk.filter.PathFilter;
  74. import org.junit.Before;
  75. import org.junit.experimental.theories.DataPoints;
  76. import org.junit.experimental.theories.Theories;
  77. import org.junit.experimental.theories.Theory;
  78. import org.junit.runner.RunWith;
  79. @RunWith(Theories.class)
  80. public class RecursiveMergerTest extends RepositoryTestCase {
  81. static int counter = 0;
  82. @DataPoints
  83. public static MergeStrategy[] strategiesUnderTest = new MergeStrategy[] {
  84. MergeStrategy.RECURSIVE, MergeStrategy.RESOLVE };
  85. public enum IndexState {
  86. Bare, Missing, SameAsHead, SameAsOther, SameAsWorkTree, DifferentFromHeadAndOtherAndWorktree
  87. }
  88. @DataPoints
  89. public static IndexState[] indexStates = IndexState.values();
  90. public enum WorktreeState {
  91. Bare, Missing, SameAsHead, DifferentFromHeadAndOther, SameAsOther;
  92. }
  93. @DataPoints
  94. public static WorktreeState[] worktreeStates = WorktreeState.values();
  95. private TestRepository<FileRepository> db_t;
  96. @Override
  97. @Before
  98. public void setUp() throws Exception {
  99. super.setUp();
  100. db_t = new TestRepository<FileRepository>(db);
  101. }
  102. @Theory
  103. /**
  104. * Merging m2,s2 from the following topology. In master and side different
  105. * files are touched. No need to do a real content merge.
  106. *
  107. * <pre>
  108. * m0--m1--m2
  109. * \ \/
  110. * \ /\
  111. * s1--s2
  112. * </pre>
  113. */
  114. public void crissCrossMerge(MergeStrategy strategy, IndexState indexState,
  115. WorktreeState worktreeState) throws Exception {
  116. if (!validateStates(indexState, worktreeState))
  117. return;
  118. // fill the repo
  119. BranchBuilder master = db_t.branch("master");
  120. RevCommit m0 = master.commit().add("m", ",m0").message("m0").create();
  121. RevCommit m1 = master.commit().add("m", "m1").message("m1").create();
  122. db_t.getRevWalk().parseCommit(m1);
  123. BranchBuilder side = db_t.branch("side");
  124. RevCommit s1 = side.commit().parent(m0).add("s", "s1").message("s1")
  125. .create();
  126. RevCommit s2 = side.commit().parent(m1).add("m", "m1")
  127. .message("s2(merge)").create();
  128. RevCommit m2 = master.commit().parent(s1).add("s", "s1")
  129. .message("m2(merge)").create();
  130. Git git = Git.wrap(db);
  131. git.checkout().setName("master").call();
  132. modifyWorktree(worktreeState, "m", "side");
  133. modifyWorktree(worktreeState, "s", "side");
  134. modifyIndex(indexState, "m", "side");
  135. modifyIndex(indexState, "s", "side");
  136. ResolveMerger merger = (ResolveMerger) strategy.newMerger(db,
  137. worktreeState == WorktreeState.Bare);
  138. if (worktreeState != WorktreeState.Bare)
  139. merger.setWorkingTreeIterator(new FileTreeIterator(db));
  140. try {
  141. boolean expectSuccess = true;
  142. if (!(indexState == IndexState.Bare
  143. || indexState == IndexState.Missing
  144. || indexState == IndexState.SameAsHead || indexState == IndexState.SameAsOther))
  145. // index is dirty
  146. expectSuccess = false;
  147. assertEquals(Boolean.valueOf(expectSuccess),
  148. Boolean.valueOf(merger.merge(new RevCommit[] { m2, s2 })));
  149. assertEquals(MergeStrategy.RECURSIVE, strategy);
  150. assertEquals("m1",
  151. contentAsString(db, merger.getResultTreeId(), "m"));
  152. assertEquals("s1",
  153. contentAsString(db, merger.getResultTreeId(), "s"));
  154. } catch (NoMergeBaseException e) {
  155. assertEquals(MergeStrategy.RESOLVE, strategy);
  156. assertEquals(e.getReason(),
  157. MergeBaseFailureReason.MULTIPLE_MERGE_BASES_NOT_SUPPORTED);
  158. }
  159. }
  160. @Theory
  161. /**
  162. * Merging m2,s2 from the following topology. The same file is modified
  163. * in both branches. The modifications should be mergeable. m2 and s2
  164. * contain branch specific conflict resolutions. Therefore m2 and don't contain the same content.
  165. *
  166. * <pre>
  167. * m0--m1--m2
  168. * \ \/
  169. * \ /\
  170. * s1--s2
  171. * </pre>
  172. */
  173. public void crissCrossMerge_mergeable(MergeStrategy strategy,
  174. IndexState indexState, WorktreeState worktreeState)
  175. throws Exception {
  176. if (!validateStates(indexState, worktreeState))
  177. return;
  178. BranchBuilder master = db_t.branch("master");
  179. RevCommit m0 = master.commit().add("f", "1\n2\n3\n4\n5\n6\n7\n8\n9\n")
  180. .message("m0").create();
  181. RevCommit m1 = master.commit()
  182. .add("f", "1-master\n2\n3\n4\n5\n6\n7\n8\n9\n").message("m1")
  183. .create();
  184. db_t.getRevWalk().parseCommit(m1);
  185. BranchBuilder side = db_t.branch("side");
  186. RevCommit s1 = side.commit().parent(m0)
  187. .add("f", "1\n2\n3\n4\n5\n6\n7\n8\n9-side\n").message("s1")
  188. .create();
  189. RevCommit s2 = side.commit().parent(m1)
  190. .add("f", "1-master\n2\n3\n4\n5\n6\n7-res(side)\n8\n9-side\n")
  191. .message("s2(merge)").create();
  192. RevCommit m2 = master
  193. .commit()
  194. .parent(s1)
  195. .add("f", "1-master\n2\n3-res(master)\n4\n5\n6\n7\n8\n9-side\n")
  196. .message("m2(merge)").create();
  197. Git git = Git.wrap(db);
  198. git.checkout().setName("master").call();
  199. modifyWorktree(worktreeState, "f", "side");
  200. modifyIndex(indexState, "f", "side");
  201. ResolveMerger merger = (ResolveMerger) strategy.newMerger(db,
  202. worktreeState == WorktreeState.Bare);
  203. if (worktreeState != WorktreeState.Bare)
  204. merger.setWorkingTreeIterator(new FileTreeIterator(db));
  205. try {
  206. boolean expectSuccess = true;
  207. if (!(indexState == IndexState.Bare
  208. || indexState == IndexState.Missing || indexState == IndexState.SameAsHead))
  209. // index is dirty
  210. expectSuccess = false;
  211. else if (worktreeState == WorktreeState.DifferentFromHeadAndOther
  212. || worktreeState == WorktreeState.SameAsOther)
  213. expectSuccess = false;
  214. assertEquals(Boolean.valueOf(expectSuccess),
  215. Boolean.valueOf(merger.merge(new RevCommit[] { m2, s2 })));
  216. assertEquals(MergeStrategy.RECURSIVE, strategy);
  217. if (!expectSuccess)
  218. // if the merge was not successful skip testing the state of index and workingtree
  219. return;
  220. assertEquals(
  221. "1-master\n2\n3-res(master)\n4\n5\n6\n7-res(side)\n8\n9-side",
  222. contentAsString(db, merger.getResultTreeId(), "f"));
  223. if (indexState != IndexState.Bare)
  224. assertEquals(
  225. "[f, mode:100644, content:1-master\n2\n3-res(master)\n4\n5\n6\n7-res(side)\n8\n9-side\n]",
  226. indexState(RepositoryTestCase.CONTENT));
  227. if (worktreeState != WorktreeState.Bare
  228. && worktreeState != WorktreeState.Missing)
  229. assertEquals(
  230. "1-master\n2\n3-res(master)\n4\n5\n6\n7-res(side)\n8\n9-side\n",
  231. read("f"));
  232. } catch (NoMergeBaseException e) {
  233. assertEquals(MergeStrategy.RESOLVE, strategy);
  234. assertEquals(e.getReason(),
  235. MergeBaseFailureReason.MULTIPLE_MERGE_BASES_NOT_SUPPORTED);
  236. }
  237. }
  238. @Theory
  239. /**
  240. * Merging m2,s2 from the following topology. The same file is modified
  241. * in both branches. The modifications are not automatically
  242. * mergeable. m2 and s2 contain branch specific conflict resolutions.
  243. * Therefore m2 and s2 don't contain the same content.
  244. *
  245. * <pre>
  246. * m0--m1--m2
  247. * \ \/
  248. * \ /\
  249. * s1--s2
  250. * </pre>
  251. */
  252. public void crissCrossMerge_nonmergeable(MergeStrategy strategy,
  253. IndexState indexState, WorktreeState worktreeState)
  254. throws Exception {
  255. if (!validateStates(indexState, worktreeState))
  256. return;
  257. BranchBuilder master = db_t.branch("master");
  258. RevCommit m0 = master.commit().add("f", "1\n2\n3\n4\n5\n6\n7\n8\n9\n")
  259. .message("m0").create();
  260. RevCommit m1 = master.commit()
  261. .add("f", "1-master\n2\n3\n4\n5\n6\n7\n8\n9\n").message("m1")
  262. .create();
  263. db_t.getRevWalk().parseCommit(m1);
  264. BranchBuilder side = db_t.branch("side");
  265. RevCommit s1 = side.commit().parent(m0)
  266. .add("f", "1\n2\n3\n4\n5\n6\n7\n8\n9-side\n").message("s1")
  267. .create();
  268. RevCommit s2 = side.commit().parent(m1)
  269. .add("f", "1-master\n2\n3\n4\n5\n6\n7-res(side)\n8\n9-side\n")
  270. .message("s2(merge)").create();
  271. RevCommit m2 = master.commit().parent(s1)
  272. .add("f", "1-master\n2\n3\n4\n5\n6\n7-conflict\n8\n9-side\n")
  273. .message("m2(merge)").create();
  274. Git git = Git.wrap(db);
  275. git.checkout().setName("master").call();
  276. modifyWorktree(worktreeState, "f", "side");
  277. modifyIndex(indexState, "f", "side");
  278. ResolveMerger merger = (ResolveMerger) strategy.newMerger(db,
  279. worktreeState == WorktreeState.Bare);
  280. if (worktreeState != WorktreeState.Bare)
  281. merger.setWorkingTreeIterator(new FileTreeIterator(db));
  282. try {
  283. assertFalse(merger.merge(new RevCommit[] { m2, s2 }));
  284. assertEquals(MergeStrategy.RECURSIVE, strategy);
  285. if (indexState == IndexState.SameAsHead
  286. && worktreeState == WorktreeState.SameAsHead) {
  287. assertEquals(
  288. "[f, mode:100644, stage:1, content:1-master\n2\n3\n4\n5\n6\n7\n8\n9-side\n]"
  289. + "[f, mode:100644, stage:2, content:1-master\n2\n3\n4\n5\n6\n7-conflict\n8\n9-side\n]"
  290. + "[f, mode:100644, stage:3, content:1-master\n2\n3\n4\n5\n6\n7-res(side)\n8\n9-side\n]",
  291. indexState(RepositoryTestCase.CONTENT));
  292. assertEquals(
  293. "1-master\n2\n3\n4\n5\n6\n<<<<<<< OURS\n7-conflict\n=======\n7-res(side)\n>>>>>>> THEIRS\n8\n9-side\n",
  294. read("f"));
  295. }
  296. } catch (NoMergeBaseException e) {
  297. assertEquals(MergeStrategy.RESOLVE, strategy);
  298. assertEquals(e.getReason(),
  299. MergeBaseFailureReason.MULTIPLE_MERGE_BASES_NOT_SUPPORTED);
  300. }
  301. }
  302. @Theory
  303. /**
  304. * Merging m2,s2 which have three common predecessors.The same file is modified
  305. * in all branches. The modifications should be mergeable. m2 and s2
  306. * contain branch specific conflict resolutions. Therefore m2 and s2
  307. * don't contain the same content.
  308. *
  309. * <pre>
  310. * m1-----m2
  311. * / \/ /
  312. * / /\ /
  313. * m0--o1 x
  314. * \ \/ \
  315. * \ /\ \
  316. * s1-----s2
  317. * </pre>
  318. */
  319. public void crissCrossMerge_ThreeCommonPredecessors(MergeStrategy strategy,
  320. IndexState indexState, WorktreeState worktreeState)
  321. throws Exception {
  322. if (!validateStates(indexState, worktreeState))
  323. return;
  324. BranchBuilder master = db_t.branch("master");
  325. RevCommit m0 = master.commit().add("f", "1\n2\n3\n4\n5\n6\n7\n8\n9\n")
  326. .message("m0").create();
  327. RevCommit m1 = master.commit()
  328. .add("f", "1-master\n2\n3\n4\n5\n6\n7\n8\n9\n").message("m1")
  329. .create();
  330. BranchBuilder side = db_t.branch("side");
  331. RevCommit s1 = side.commit().parent(m0)
  332. .add("f", "1\n2\n3\n4\n5\n6\n7\n8\n9-side\n").message("s1")
  333. .create();
  334. BranchBuilder other = db_t.branch("other");
  335. RevCommit o1 = other.commit().parent(m0)
  336. .add("f", "1\n2\n3\n4\n5-other\n6\n7\n8\n9\n").message("o1")
  337. .create();
  338. RevCommit m2 = master
  339. .commit()
  340. .parent(s1)
  341. .parent(o1)
  342. .add("f",
  343. "1-master\n2\n3-res(master)\n4\n5-other\n6\n7\n8\n9-side\n")
  344. .message("m2(merge)").create();
  345. RevCommit s2 = side
  346. .commit()
  347. .parent(m1)
  348. .parent(o1)
  349. .add("f",
  350. "1-master\n2\n3\n4\n5-other\n6\n7-res(side)\n8\n9-side\n")
  351. .message("s2(merge)").create();
  352. Git git = Git.wrap(db);
  353. git.checkout().setName("master").call();
  354. modifyWorktree(worktreeState, "f", "side");
  355. modifyIndex(indexState, "f", "side");
  356. ResolveMerger merger = (ResolveMerger) strategy.newMerger(db,
  357. worktreeState == WorktreeState.Bare);
  358. if (worktreeState != WorktreeState.Bare)
  359. merger.setWorkingTreeIterator(new FileTreeIterator(db));
  360. try {
  361. boolean expectSuccess = true;
  362. if (!(indexState == IndexState.Bare
  363. || indexState == IndexState.Missing || indexState == IndexState.SameAsHead))
  364. // index is dirty
  365. expectSuccess = false;
  366. else if (worktreeState == WorktreeState.DifferentFromHeadAndOther
  367. || worktreeState == WorktreeState.SameAsOther)
  368. // workingtree is dirty
  369. expectSuccess = false;
  370. assertEquals(Boolean.valueOf(expectSuccess),
  371. Boolean.valueOf(merger.merge(new RevCommit[] { m2, s2 })));
  372. assertEquals(MergeStrategy.RECURSIVE, strategy);
  373. if (!expectSuccess)
  374. // if the merge was not successful skip testing the state of index and workingtree
  375. return;
  376. assertEquals(
  377. "1-master\n2\n3-res(master)\n4\n5-other\n6\n7-res(side)\n8\n9-side",
  378. contentAsString(db, merger.getResultTreeId(), "f"));
  379. if (indexState != IndexState.Bare)
  380. assertEquals(
  381. "[f, mode:100644, content:1-master\n2\n3-res(master)\n4\n5-other\n6\n7-res(side)\n8\n9-side\n]",
  382. indexState(RepositoryTestCase.CONTENT));
  383. if (worktreeState != WorktreeState.Bare
  384. && worktreeState != WorktreeState.Missing)
  385. assertEquals(
  386. "1-master\n2\n3-res(master)\n4\n5-other\n6\n7-res(side)\n8\n9-side\n",
  387. read("f"));
  388. } catch (NoMergeBaseException e) {
  389. assertEquals(MergeStrategy.RESOLVE, strategy);
  390. assertEquals(e.getReason(),
  391. MergeBaseFailureReason.MULTIPLE_MERGE_BASES_NOT_SUPPORTED);
  392. }
  393. }
  394. void modifyIndex(IndexState indexState, String path, String other)
  395. throws Exception {
  396. RevBlob blob;
  397. switch (indexState) {
  398. case Missing:
  399. setIndex(null, path);
  400. break;
  401. case SameAsHead:
  402. setIndex(contentId(Constants.HEAD, path), path);
  403. break;
  404. case SameAsOther:
  405. setIndex(contentId(other, path), path);
  406. break;
  407. case SameAsWorkTree:
  408. blob = db_t.blob(read(path));
  409. setIndex(blob, path);
  410. break;
  411. case DifferentFromHeadAndOtherAndWorktree:
  412. blob = db_t.blob(Integer.toString(counter++));
  413. setIndex(blob, path);
  414. break;
  415. case Bare:
  416. File file = new File(db.getDirectory(), "index");
  417. if (!file.exists())
  418. return;
  419. db.close();
  420. file.delete();
  421. db = new FileRepository(db.getDirectory());
  422. db_t = new TestRepository<FileRepository>(db);
  423. break;
  424. }
  425. }
  426. private void setIndex(final ObjectId id, String path)
  427. throws MissingObjectException, IOException {
  428. DirCache lockedDircache;
  429. DirCacheEditor dcedit;
  430. lockedDircache = db.lockDirCache();
  431. dcedit = lockedDircache.editor();
  432. try {
  433. if (id != null) {
  434. final ObjectLoader contLoader = db.newObjectReader().open(id);
  435. dcedit.add(new DirCacheEditor.PathEdit(path) {
  436. @Override
  437. public void apply(DirCacheEntry ent) {
  438. ent.setFileMode(FileMode.REGULAR_FILE);
  439. ent.setLength(contLoader.getSize());
  440. ent.setObjectId(id);
  441. }
  442. });
  443. } else
  444. dcedit.add(new DirCacheEditor.DeletePath(path));
  445. } finally {
  446. dcedit.commit();
  447. }
  448. }
  449. private ObjectId contentId(String revName, String path) throws Exception {
  450. RevCommit headCommit = db_t.getRevWalk().parseCommit(
  451. db.resolve(revName));
  452. db_t.parseBody(headCommit);
  453. return db_t.get(headCommit.getTree(), path).getId();
  454. }
  455. void modifyWorktree(WorktreeState worktreeState, String path, String other)
  456. throws Exception {
  457. FileOutputStream fos = null;
  458. ObjectId bloblId;
  459. try {
  460. switch (worktreeState) {
  461. case Missing:
  462. new File(db.getWorkTree(), path).delete();
  463. break;
  464. case DifferentFromHeadAndOther:
  465. write(new File(db.getWorkTree(), path),
  466. Integer.toString(counter++));
  467. break;
  468. case SameAsHead:
  469. bloblId = contentId(Constants.HEAD, path);
  470. fos = new FileOutputStream(new File(db.getWorkTree(), path));
  471. db.newObjectReader().open(bloblId).copyTo(fos);
  472. break;
  473. case SameAsOther:
  474. bloblId = contentId(other, path);
  475. fos = new FileOutputStream(new File(db.getWorkTree(), path));
  476. db.newObjectReader().open(bloblId).copyTo(fos);
  477. break;
  478. case Bare:
  479. if (db.isBare())
  480. return;
  481. File workTreeFile = db.getWorkTree();
  482. db.getConfig().setBoolean("core", null, "bare", true);
  483. db.getDirectory().renameTo(new File(workTreeFile, "test.git"));
  484. db = new FileRepository(new File(workTreeFile, "test.git"));
  485. db_t = new TestRepository<FileRepository>(db);
  486. }
  487. } finally {
  488. if (fos != null)
  489. fos.close();
  490. }
  491. }
  492. private boolean validateStates(IndexState indexState,
  493. WorktreeState worktreeState) {
  494. if (worktreeState == WorktreeState.Bare
  495. && indexState != IndexState.Bare)
  496. return false;
  497. if (worktreeState != WorktreeState.Bare
  498. && indexState == IndexState.Bare)
  499. return false;
  500. if (worktreeState != WorktreeState.DifferentFromHeadAndOther
  501. && indexState == IndexState.SameAsWorkTree)
  502. // would be a duplicate: the combination WorktreeState.X and
  503. // IndexState.X already covered this
  504. return false;
  505. return true;
  506. }
  507. private String contentAsString(Repository r, ObjectId treeId, String path)
  508. throws MissingObjectException, IOException {
  509. TreeWalk tw = new TreeWalk(r);
  510. tw.addTree(treeId);
  511. tw.setFilter(PathFilter.create(path));
  512. tw.setRecursive(true);
  513. if (!tw.next())
  514. return null;
  515. AnyObjectId blobId = tw.getObjectId(0);
  516. StringBuilder result = new StringBuilder();
  517. BufferedReader br = null;
  518. ObjectReader or = r.newObjectReader();
  519. try {
  520. br = new BufferedReader(new InputStreamReader(or.open(blobId)
  521. .openStream()));
  522. String line;
  523. boolean first = true;
  524. while ((line = br.readLine()) != null) {
  525. if (!first)
  526. result.append('\n');
  527. result.append(line);
  528. first = false;
  529. }
  530. return result.toString();
  531. } finally {
  532. if (br != null)
  533. br.close();
  534. }
  535. }
  536. }