Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

ResolveMerger.java 35KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085
  1. /*
  2. * Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com>,
  3. * Copyright (C) 2010-2012, Matthias Sohn <matthias.sohn@sap.com>
  4. * Copyright (C) 2012, Research In Motion Limited
  5. * and other copyright owners as documented in the project's IP log.
  6. *
  7. * This program and the accompanying materials are made available
  8. * under the terms of the Eclipse Distribution License v1.0 which
  9. * accompanies this distribution, is reproduced below, and is
  10. * available at http://www.eclipse.org/org/documents/edl-v10.php
  11. *
  12. * All rights reserved.
  13. *
  14. * Redistribution and use in source and binary forms, with or
  15. * without modification, are permitted provided that the following
  16. * conditions are met:
  17. *
  18. * - Redistributions of source code must retain the above copyright
  19. * notice, this list of conditions and the following disclaimer.
  20. *
  21. * - Redistributions in binary form must reproduce the above
  22. * copyright notice, this list of conditions and the following
  23. * disclaimer in the documentation and/or other materials provided
  24. * with the distribution.
  25. *
  26. * - Neither the name of the Eclipse Foundation, Inc. nor the
  27. * names of its contributors may be used to endorse or promote
  28. * products derived from this software without specific prior
  29. * written permission.
  30. *
  31. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  32. * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  33. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  34. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  35. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  36. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  37. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  38. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  39. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  40. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  41. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  42. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  43. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  44. */
  45. package org.eclipse.jgit.merge;
  46. import static org.eclipse.jgit.lib.Constants.CHARACTER_ENCODING;
  47. import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
  48. import java.io.BufferedOutputStream;
  49. import java.io.File;
  50. import java.io.FileInputStream;
  51. import java.io.FileNotFoundException;
  52. import java.io.FileOutputStream;
  53. import java.io.IOException;
  54. import java.io.InputStream;
  55. import java.io.OutputStream;
  56. import java.util.ArrayList;
  57. import java.util.Arrays;
  58. import java.util.Collections;
  59. import java.util.HashMap;
  60. import java.util.Iterator;
  61. import java.util.LinkedList;
  62. import java.util.List;
  63. import java.util.Map;
  64. import org.eclipse.jgit.diff.DiffAlgorithm;
  65. import org.eclipse.jgit.diff.DiffAlgorithm.SupportedAlgorithm;
  66. import org.eclipse.jgit.diff.RawText;
  67. import org.eclipse.jgit.diff.RawTextComparator;
  68. import org.eclipse.jgit.diff.Sequence;
  69. import org.eclipse.jgit.dircache.DirCache;
  70. import org.eclipse.jgit.dircache.DirCacheBuildIterator;
  71. import org.eclipse.jgit.dircache.DirCacheBuilder;
  72. import org.eclipse.jgit.dircache.DirCacheCheckout;
  73. import org.eclipse.jgit.dircache.DirCacheEntry;
  74. import org.eclipse.jgit.errors.CorruptObjectException;
  75. import org.eclipse.jgit.errors.IncorrectObjectTypeException;
  76. import org.eclipse.jgit.errors.IndexWriteException;
  77. import org.eclipse.jgit.errors.MissingObjectException;
  78. import org.eclipse.jgit.errors.NoWorkTreeException;
  79. import org.eclipse.jgit.lib.ConfigConstants;
  80. import org.eclipse.jgit.lib.FileMode;
  81. import org.eclipse.jgit.lib.ObjectId;
  82. import org.eclipse.jgit.lib.ObjectReader;
  83. import org.eclipse.jgit.lib.Repository;
  84. import org.eclipse.jgit.revwalk.RevTree;
  85. import org.eclipse.jgit.treewalk.AbstractTreeIterator;
  86. import org.eclipse.jgit.treewalk.CanonicalTreeParser;
  87. import org.eclipse.jgit.treewalk.NameConflictTreeWalk;
  88. import org.eclipse.jgit.treewalk.TreeWalk;
  89. import org.eclipse.jgit.treewalk.WorkingTreeIterator;
  90. import org.eclipse.jgit.treewalk.filter.TreeFilter;
  91. import org.eclipse.jgit.util.FS;
  92. import org.eclipse.jgit.util.TemporaryBuffer;
  93. /**
  94. * A three-way merger performing a content-merge if necessary
  95. */
  96. public class ResolveMerger extends ThreeWayMerger {
  97. /**
  98. * If the merge fails (means: not stopped because of unresolved conflicts)
  99. * this enum is used to explain why it failed
  100. */
  101. public enum MergeFailureReason {
  102. /** the merge failed because of a dirty index */
  103. DIRTY_INDEX,
  104. /** the merge failed because of a dirty workingtree */
  105. DIRTY_WORKTREE,
  106. /** the merge failed because of a file could not be deleted */
  107. COULD_NOT_DELETE
  108. }
  109. /**
  110. * The tree walk which we'll iterate over to merge entries.
  111. *
  112. * @since 3.4
  113. */
  114. protected NameConflictTreeWalk tw;
  115. /**
  116. * string versions of a list of commit SHA1s
  117. *
  118. * @since 3.0
  119. */
  120. protected String commitNames[];
  121. /**
  122. * Index of the base tree within the {@link #tw tree walk}.
  123. *
  124. * @since 3.4
  125. */
  126. protected static final int T_BASE = 0;
  127. /**
  128. * Index of our tree in withthe {@link #tw tree walk}.
  129. *
  130. * @since 3.4
  131. */
  132. protected static final int T_OURS = 1;
  133. /**
  134. * Index of their tree within the {@link #tw tree walk}.
  135. *
  136. * @since 3.4
  137. */
  138. protected static final int T_THEIRS = 2;
  139. /**
  140. * Index of the index tree within the {@link #tw tree walk}.
  141. *
  142. * @since 3.4
  143. */
  144. protected static final int T_INDEX = 3;
  145. /**
  146. * Index of the working directory tree within the {@link #tw tree walk}.
  147. *
  148. * @since 3.4
  149. */
  150. protected static final int T_FILE = 4;
  151. /**
  152. * Builder to update the cache during this merge.
  153. *
  154. * @since 3.4
  155. */
  156. protected DirCacheBuilder builder;
  157. /**
  158. * merge result as tree
  159. *
  160. * @since 3.0
  161. */
  162. protected ObjectId resultTree;
  163. /**
  164. * Paths that could not be merged by this merger because of an unsolvable
  165. * conflict.
  166. *
  167. * @since 3.4
  168. */
  169. protected List<String> unmergedPaths = new ArrayList<String>();
  170. /**
  171. * Files modified during this merge operation.
  172. *
  173. * @since 3.4
  174. */
  175. protected List<String> modifiedFiles = new LinkedList<String>();
  176. /**
  177. * If the merger has nothing to do for a file but check it out at the end of
  178. * the operation, it can be added here.
  179. *
  180. * @since 3.4
  181. */
  182. protected Map<String, DirCacheEntry> toBeCheckedOut = new HashMap<String, DirCacheEntry>();
  183. /**
  184. * Paths in this list will be deleted from the local copy at the end of the
  185. * operation.
  186. *
  187. * @since 3.4
  188. */
  189. protected List<String> toBeDeleted = new ArrayList<String>();
  190. /**
  191. * Low-level textual merge results. Will be passed on to the callers in case
  192. * of conflicts.
  193. *
  194. * @since 3.4
  195. */
  196. protected Map<String, MergeResult<? extends Sequence>> mergeResults = new HashMap<String, MergeResult<? extends Sequence>>();
  197. /**
  198. * Paths for which the merge failed altogether.
  199. *
  200. * @since 3.4
  201. */
  202. protected Map<String, MergeFailureReason> failingPaths = new HashMap<String, MergeFailureReason>();
  203. /**
  204. * Updated as we merge entries of the tree walk. Tells us whether we should
  205. * recurse into the entry if it is a subtree.
  206. *
  207. * @since 3.4
  208. */
  209. protected boolean enterSubtree;
  210. /**
  211. * Set to true if this merge should work in-memory. The repos dircache and
  212. * workingtree are not touched by this method. Eventually needed files are
  213. * created as temporary files and a new empty, in-memory dircache will be
  214. * used instead the repo's one. Often used for bare repos where the repo
  215. * doesn't even have a workingtree and dircache.
  216. * @since 3.0
  217. */
  218. protected boolean inCore;
  219. /**
  220. * Set to true if this merger should use the default dircache of the
  221. * repository and should handle locking and unlocking of the dircache. If
  222. * this merger should work in-core or if an explicit dircache was specified
  223. * during construction then this field is set to false.
  224. * @since 3.0
  225. */
  226. protected boolean implicitDirCache;
  227. /**
  228. * Directory cache
  229. * @since 3.0
  230. */
  231. protected DirCache dircache;
  232. /**
  233. * The iterator to access the working tree. If set to <code>null</code> this
  234. * merger will not touch the working tree.
  235. * @since 3.0
  236. */
  237. protected WorkingTreeIterator workingTreeIterator;
  238. /**
  239. * our merge algorithm
  240. * @since 3.0
  241. */
  242. protected MergeAlgorithm mergeAlgorithm;
  243. /**
  244. * @param local
  245. * @param inCore
  246. */
  247. protected ResolveMerger(Repository local, boolean inCore) {
  248. super(local);
  249. SupportedAlgorithm diffAlg = local.getConfig().getEnum(
  250. ConfigConstants.CONFIG_DIFF_SECTION, null,
  251. ConfigConstants.CONFIG_KEY_ALGORITHM,
  252. SupportedAlgorithm.HISTOGRAM);
  253. mergeAlgorithm = new MergeAlgorithm(DiffAlgorithm.getAlgorithm(diffAlg));
  254. commitNames = new String[] { "BASE", "OURS", "THEIRS" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
  255. this.inCore = inCore;
  256. if (inCore) {
  257. implicitDirCache = false;
  258. dircache = DirCache.newInCore();
  259. } else {
  260. implicitDirCache = true;
  261. }
  262. }
  263. /**
  264. * @param local
  265. */
  266. protected ResolveMerger(Repository local) {
  267. this(local, false);
  268. }
  269. @Override
  270. protected boolean mergeImpl() throws IOException {
  271. if (implicitDirCache)
  272. dircache = getRepository().lockDirCache();
  273. try {
  274. return mergeTrees(mergeBase(), sourceTrees[0], sourceTrees[1],
  275. false);
  276. } finally {
  277. if (implicitDirCache)
  278. dircache.unlock();
  279. }
  280. }
  281. private void checkout() throws NoWorkTreeException, IOException {
  282. // Iterate in reverse so that "folder/file" is deleted before
  283. // "folder". Otherwise this could result in a failing path because
  284. // of a non-empty directory, for which delete() would fail.
  285. for (int i = toBeDeleted.size() - 1; i >= 0; i--) {
  286. String fileName = toBeDeleted.get(i);
  287. File f = new File(db.getWorkTree(), fileName);
  288. if (!f.delete())
  289. if (!f.isDirectory())
  290. failingPaths.put(fileName,
  291. MergeFailureReason.COULD_NOT_DELETE);
  292. modifiedFiles.add(fileName);
  293. }
  294. for (Map.Entry<String, DirCacheEntry> entry : toBeCheckedOut
  295. .entrySet()) {
  296. DirCacheCheckout.checkoutEntry(db, entry.getValue(), reader);
  297. modifiedFiles.add(entry.getKey());
  298. }
  299. }
  300. /**
  301. * Reverts the worktree after an unsuccessful merge. We know that for all
  302. * modified files the old content was in the old index and the index
  303. * contained only stage 0. In case if inCore operation just clear the
  304. * history of modified files.
  305. *
  306. * @throws IOException
  307. * @throws CorruptObjectException
  308. * @throws NoWorkTreeException
  309. * @since 3.4
  310. */
  311. protected void cleanUp() throws NoWorkTreeException,
  312. CorruptObjectException,
  313. IOException {
  314. if (inCore) {
  315. modifiedFiles.clear();
  316. return;
  317. }
  318. DirCache dc = db.readDirCache();
  319. Iterator<String> mpathsIt=modifiedFiles.iterator();
  320. while(mpathsIt.hasNext()) {
  321. String mpath=mpathsIt.next();
  322. DirCacheEntry entry = dc.getEntry(mpath);
  323. if (entry != null)
  324. DirCacheCheckout.checkoutEntry(db, entry, reader);
  325. mpathsIt.remove();
  326. }
  327. }
  328. /**
  329. * adds a new path with the specified stage to the index builder
  330. *
  331. * @param path
  332. * @param p
  333. * @param stage
  334. * @param lastMod
  335. * @param len
  336. * @return the entry which was added to the index
  337. */
  338. private DirCacheEntry add(byte[] path, CanonicalTreeParser p, int stage,
  339. long lastMod, long len) {
  340. if (p != null && !p.getEntryFileMode().equals(FileMode.TREE)) {
  341. DirCacheEntry e = new DirCacheEntry(path, stage);
  342. e.setFileMode(p.getEntryFileMode());
  343. e.setObjectId(p.getEntryObjectId());
  344. e.setLastModified(lastMod);
  345. e.setLength(len);
  346. builder.add(e);
  347. return e;
  348. }
  349. return null;
  350. }
  351. /**
  352. * adds a entry to the index builder which is a copy of the specified
  353. * DirCacheEntry
  354. *
  355. * @param e
  356. * the entry which should be copied
  357. *
  358. * @return the entry which was added to the index
  359. */
  360. private DirCacheEntry keep(DirCacheEntry e) {
  361. DirCacheEntry newEntry = new DirCacheEntry(e.getPathString(),
  362. e.getStage());
  363. newEntry.setFileMode(e.getFileMode());
  364. newEntry.setObjectId(e.getObjectId());
  365. newEntry.setLastModified(e.getLastModified());
  366. newEntry.setLength(e.getLength());
  367. builder.add(newEntry);
  368. return newEntry;
  369. }
  370. /**
  371. * Processes one path and tries to merge. This method will do all do all
  372. * trivial (not content) merges and will also detect if a merge will fail.
  373. * The merge will fail when one of the following is true
  374. * <ul>
  375. * <li>the index entry does not match the entry in ours. When merging one
  376. * branch into the current HEAD, ours will point to HEAD and theirs will
  377. * point to the other branch. It is assumed that the index matches the HEAD
  378. * because it will only not match HEAD if it was populated before the merge
  379. * operation. But the merge commit should not accidentally contain
  380. * modifications done before the merge. Check the <a href=
  381. * "http://www.kernel.org/pub/software/scm/git/docs/git-read-tree.html#_3_way_merge"
  382. * >git read-tree</a> documentation for further explanations.</li>
  383. * <li>A conflict was detected and the working-tree file is dirty. When a
  384. * conflict is detected the content-merge algorithm will try to write a
  385. * merged version into the working-tree. If the file is dirty we would
  386. * override unsaved data.</li>
  387. * </ul>
  388. *
  389. * @param base
  390. * the common base for ours and theirs
  391. * @param ours
  392. * the ours side of the merge. When merging a branch into the
  393. * HEAD ours will point to HEAD
  394. * @param theirs
  395. * the theirs side of the merge. When merging a branch into the
  396. * current HEAD theirs will point to the branch which is merged
  397. * into HEAD.
  398. * @param index
  399. * the index entry
  400. * @param work
  401. * the file in the working tree
  402. * @param ignoreConflicts
  403. * see
  404. * {@link ResolveMerger#mergeTrees(AbstractTreeIterator, RevTree, RevTree, boolean)}
  405. * @return <code>false</code> if the merge will fail because the index entry
  406. * didn't match ours or the working-dir file was dirty and a
  407. * conflict occurred
  408. * @throws MissingObjectException
  409. * @throws IncorrectObjectTypeException
  410. * @throws CorruptObjectException
  411. * @throws IOException
  412. * @since 3.5
  413. */
  414. protected boolean processEntry(CanonicalTreeParser base,
  415. CanonicalTreeParser ours, CanonicalTreeParser theirs,
  416. DirCacheBuildIterator index, WorkingTreeIterator work,
  417. boolean ignoreConflicts)
  418. throws MissingObjectException, IncorrectObjectTypeException,
  419. CorruptObjectException, IOException {
  420. enterSubtree = true;
  421. final int modeO = tw.getRawMode(T_OURS);
  422. final int modeT = tw.getRawMode(T_THEIRS);
  423. final int modeB = tw.getRawMode(T_BASE);
  424. if (modeO == 0 && modeT == 0 && modeB == 0)
  425. // File is either untracked or new, staged but uncommitted
  426. return true;
  427. if (isIndexDirty())
  428. return false;
  429. DirCacheEntry ourDce = null;
  430. if (index == null || index.getDirCacheEntry() == null) {
  431. // create a fake DCE, but only if ours is valid. ours is kept only
  432. // in case it is valid, so a null ourDce is ok in all other cases.
  433. if (nonTree(modeO)) {
  434. ourDce = new DirCacheEntry(tw.getRawPath());
  435. ourDce.setObjectId(tw.getObjectId(T_OURS));
  436. ourDce.setFileMode(tw.getFileMode(T_OURS));
  437. }
  438. } else {
  439. ourDce = index.getDirCacheEntry();
  440. }
  441. if (nonTree(modeO) && nonTree(modeT) && tw.idEqual(T_OURS, T_THEIRS)) {
  442. // OURS and THEIRS have equal content. Check the file mode
  443. if (modeO == modeT) {
  444. // content and mode of OURS and THEIRS are equal: it doesn't
  445. // matter which one we choose. OURS is chosen. Since the index
  446. // is clean (the index matches already OURS) we can keep the existing one
  447. keep(ourDce);
  448. // no checkout needed!
  449. return true;
  450. } else {
  451. // same content but different mode on OURS and THEIRS.
  452. // Try to merge the mode and report an error if this is
  453. // not possible.
  454. int newMode = mergeFileModes(modeB, modeO, modeT);
  455. if (newMode != FileMode.MISSING.getBits()) {
  456. if (newMode == modeO)
  457. // ours version is preferred
  458. keep(ourDce);
  459. else {
  460. // the preferred version THEIRS has a different mode
  461. // than ours. Check it out!
  462. if (isWorktreeDirty(work, ourDce))
  463. return false;
  464. // we know about length and lastMod only after we have written the new content.
  465. // This will happen later. Set these values to 0 for know.
  466. DirCacheEntry e = add(tw.getRawPath(), theirs,
  467. DirCacheEntry.STAGE_0, 0, 0);
  468. toBeCheckedOut.put(tw.getPathString(), e);
  469. }
  470. return true;
  471. } else {
  472. // FileModes are not mergeable. We found a conflict on modes.
  473. // For conflicting entries we don't know lastModified and length.
  474. add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, 0, 0);
  475. add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, 0, 0);
  476. add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, 0, 0);
  477. unmergedPaths.add(tw.getPathString());
  478. mergeResults.put(
  479. tw.getPathString(),
  480. new MergeResult<RawText>(Collections
  481. .<RawText> emptyList()));
  482. }
  483. return true;
  484. }
  485. }
  486. if (modeB == modeT && tw.idEqual(T_BASE, T_THEIRS)) {
  487. // THEIRS was not changed compared to BASE. All changes must be in
  488. // OURS. OURS is chosen. We can keep the existing entry.
  489. if (ourDce != null)
  490. keep(ourDce);
  491. // no checkout needed!
  492. return true;
  493. }
  494. if (modeB == modeO && tw.idEqual(T_BASE, T_OURS)) {
  495. // OURS was not changed compared to BASE. All changes must be in
  496. // THEIRS. THEIRS is chosen.
  497. // Check worktree before checking out THEIRS
  498. if (isWorktreeDirty(work, ourDce))
  499. return false;
  500. if (nonTree(modeT)) {
  501. // we know about length and lastMod only after we have written
  502. // the new content.
  503. // This will happen later. Set these values to 0 for know.
  504. DirCacheEntry e = add(tw.getRawPath(), theirs,
  505. DirCacheEntry.STAGE_0, 0, 0);
  506. if (e != null)
  507. toBeCheckedOut.put(tw.getPathString(), e);
  508. return true;
  509. } else {
  510. // we want THEIRS ... but THEIRS contains a folder or the
  511. // deletion of the path. Delete what's in the workingtree (the
  512. // workingtree is clean) but do not complain if the file is
  513. // already deleted locally. This complements the test in
  514. // isWorktreeDirty() for the same case.
  515. if (tw.getTreeCount() > T_FILE && tw.getRawMode(T_FILE) == 0)
  516. return true;
  517. toBeDeleted.add(tw.getPathString());
  518. return true;
  519. }
  520. }
  521. if (tw.isSubtree()) {
  522. // file/folder conflicts: here I want to detect only file/folder
  523. // conflict between ours and theirs. file/folder conflicts between
  524. // base/index/workingTree and something else are not relevant or
  525. // detected later
  526. if (nonTree(modeO) && !nonTree(modeT)) {
  527. if (nonTree(modeB))
  528. add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, 0, 0);
  529. add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, 0, 0);
  530. unmergedPaths.add(tw.getPathString());
  531. enterSubtree = false;
  532. return true;
  533. }
  534. if (nonTree(modeT) && !nonTree(modeO)) {
  535. if (nonTree(modeB))
  536. add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, 0, 0);
  537. add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, 0, 0);
  538. unmergedPaths.add(tw.getPathString());
  539. enterSubtree = false;
  540. return true;
  541. }
  542. // ours and theirs are both folders or both files (and treewalk
  543. // tells us we are in a subtree because of index or working-dir).
  544. // If they are both folders no content-merge is required - we can
  545. // return here.
  546. if (!nonTree(modeO))
  547. return true;
  548. // ours and theirs are both files, just fall out of the if block
  549. // and do the content merge
  550. }
  551. if (nonTree(modeO) && nonTree(modeT)) {
  552. // Check worktree before modifying files
  553. if (isWorktreeDirty(work, ourDce))
  554. return false;
  555. // Don't attempt to resolve submodule link conflicts
  556. if (isGitLink(modeO) || isGitLink(modeT)) {
  557. add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, 0, 0);
  558. add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, 0, 0);
  559. add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, 0, 0);
  560. unmergedPaths.add(tw.getPathString());
  561. return true;
  562. }
  563. MergeResult<RawText> result = contentMerge(base, ours, theirs);
  564. if (ignoreConflicts)
  565. result.setContainsConflicts(false);
  566. updateIndex(base, ours, theirs, result);
  567. if (result.containsConflicts() && !ignoreConflicts)
  568. unmergedPaths.add(tw.getPathString());
  569. modifiedFiles.add(tw.getPathString());
  570. } else if (modeO != modeT) {
  571. // OURS or THEIRS has been deleted
  572. if (((modeO != 0 && !tw.idEqual(T_BASE, T_OURS)) || (modeT != 0 && !tw
  573. .idEqual(T_BASE, T_THEIRS)))) {
  574. add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, 0, 0);
  575. add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, 0, 0);
  576. DirCacheEntry e = add(tw.getRawPath(), theirs,
  577. DirCacheEntry.STAGE_3, 0, 0);
  578. // OURS was deleted checkout THEIRS
  579. if (modeO == 0) {
  580. // Check worktree before checking out THEIRS
  581. if (isWorktreeDirty(work, ourDce))
  582. return false;
  583. if (nonTree(modeT)) {
  584. if (e != null)
  585. toBeCheckedOut.put(tw.getPathString(), e);
  586. }
  587. }
  588. unmergedPaths.add(tw.getPathString());
  589. // generate a MergeResult for the deleted file
  590. mergeResults.put(tw.getPathString(),
  591. contentMerge(base, ours, theirs));
  592. }
  593. }
  594. return true;
  595. }
  596. /**
  597. * Does the content merge. The three texts base, ours and theirs are
  598. * specified with {@link CanonicalTreeParser}. If any of the parsers is
  599. * specified as <code>null</code> then an empty text will be used instead.
  600. *
  601. * @param base
  602. * @param ours
  603. * @param theirs
  604. *
  605. * @return the result of the content merge
  606. * @throws IOException
  607. */
  608. private MergeResult<RawText> contentMerge(CanonicalTreeParser base,
  609. CanonicalTreeParser ours, CanonicalTreeParser theirs)
  610. throws IOException {
  611. RawText baseText = base == null ? RawText.EMPTY_TEXT : getRawText(
  612. base.getEntryObjectId(), reader);
  613. RawText ourText = ours == null ? RawText.EMPTY_TEXT : getRawText(
  614. ours.getEntryObjectId(), reader);
  615. RawText theirsText = theirs == null ? RawText.EMPTY_TEXT : getRawText(
  616. theirs.getEntryObjectId(), reader);
  617. return (mergeAlgorithm.merge(RawTextComparator.DEFAULT, baseText,
  618. ourText, theirsText));
  619. }
  620. private boolean isIndexDirty() {
  621. if (inCore)
  622. return false;
  623. final int modeI = tw.getRawMode(T_INDEX);
  624. final int modeO = tw.getRawMode(T_OURS);
  625. // Index entry has to match ours to be considered clean
  626. final boolean isDirty = nonTree(modeI)
  627. && !(modeO == modeI && tw.idEqual(T_INDEX, T_OURS));
  628. if (isDirty)
  629. failingPaths
  630. .put(tw.getPathString(), MergeFailureReason.DIRTY_INDEX);
  631. return isDirty;
  632. }
  633. private boolean isWorktreeDirty(WorkingTreeIterator work,
  634. DirCacheEntry ourDce) throws IOException {
  635. if (work == null)
  636. return false;
  637. final int modeF = tw.getRawMode(T_FILE);
  638. final int modeO = tw.getRawMode(T_OURS);
  639. // Worktree entry has to match ours to be considered clean
  640. boolean isDirty;
  641. if (ourDce != null)
  642. isDirty = work.isModified(ourDce, true, reader);
  643. else {
  644. isDirty = work.isModeDifferent(modeO);
  645. if (!isDirty && nonTree(modeF))
  646. isDirty = !tw.idEqual(T_FILE, T_OURS);
  647. }
  648. // Ignore existing empty directories
  649. if (isDirty && modeF == FileMode.TYPE_TREE
  650. && modeO == FileMode.TYPE_MISSING)
  651. isDirty = false;
  652. if (isDirty)
  653. failingPaths.put(tw.getPathString(),
  654. MergeFailureReason.DIRTY_WORKTREE);
  655. return isDirty;
  656. }
  657. /**
  658. * Updates the index after a content merge has happened. If no conflict has
  659. * occurred this includes persisting the merged content to the object
  660. * database. In case of conflicts this method takes care to write the
  661. * correct stages to the index.
  662. *
  663. * @param base
  664. * @param ours
  665. * @param theirs
  666. * @param result
  667. * @throws FileNotFoundException
  668. * @throws IOException
  669. */
  670. private void updateIndex(CanonicalTreeParser base,
  671. CanonicalTreeParser ours, CanonicalTreeParser theirs,
  672. MergeResult<RawText> result) throws FileNotFoundException,
  673. IOException {
  674. File mergedFile = !inCore ? writeMergedFile(result) : null;
  675. if (result.containsConflicts()) {
  676. // A conflict occurred, the file will contain conflict markers
  677. // the index will be populated with the three stages and the
  678. // workdir (if used) contains the halfway merged content.
  679. add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, 0, 0);
  680. add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, 0, 0);
  681. add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, 0, 0);
  682. mergeResults.put(tw.getPathString(), result);
  683. return;
  684. }
  685. // No conflict occurred, the file will contain fully merged content.
  686. // The index will be populated with the new merged version.
  687. DirCacheEntry dce = new DirCacheEntry(tw.getPathString());
  688. // Set the mode for the new content. Fall back to REGULAR_FILE if
  689. // we can't merge modes of OURS and THEIRS.
  690. int newMode = mergeFileModes(
  691. tw.getRawMode(0),
  692. tw.getRawMode(1),
  693. tw.getRawMode(2));
  694. dce.setFileMode(newMode == FileMode.MISSING.getBits()
  695. ? FileMode.REGULAR_FILE
  696. : FileMode.fromBits(newMode));
  697. if (mergedFile != null) {
  698. long len = mergedFile.length();
  699. dce.setLastModified(mergedFile.lastModified());
  700. dce.setLength((int) len);
  701. InputStream is = new FileInputStream(mergedFile);
  702. try {
  703. dce.setObjectId(getObjectInserter().insert(OBJ_BLOB, len, is));
  704. } finally {
  705. is.close();
  706. }
  707. } else
  708. dce.setObjectId(insertMergeResult(result));
  709. builder.add(dce);
  710. }
  711. /**
  712. * Writes merged file content to the working tree.
  713. *
  714. * @param result
  715. * the result of the content merge
  716. * @return the working tree file to which the merged content was written.
  717. * @throws FileNotFoundException
  718. * @throws IOException
  719. */
  720. private File writeMergedFile(MergeResult<RawText> result)
  721. throws FileNotFoundException, IOException {
  722. File workTree = db.getWorkTree();
  723. FS fs = db.getFS();
  724. File of = new File(workTree, tw.getPathString());
  725. File parentFolder = of.getParentFile();
  726. if (!fs.exists(parentFolder))
  727. parentFolder.mkdirs();
  728. try (OutputStream os = new BufferedOutputStream(
  729. new FileOutputStream(of))) {
  730. new MergeFormatter().formatMerge(os, result,
  731. Arrays.asList(commitNames), CHARACTER_ENCODING);
  732. }
  733. return of;
  734. }
  735. private ObjectId insertMergeResult(MergeResult<RawText> result)
  736. throws IOException {
  737. TemporaryBuffer.LocalFile buf = new TemporaryBuffer.LocalFile(
  738. db.getDirectory(), 10 << 20);
  739. try {
  740. new MergeFormatter().formatMerge(buf, result,
  741. Arrays.asList(commitNames), CHARACTER_ENCODING);
  742. buf.close();
  743. try (InputStream in = buf.openInputStream()) {
  744. return getObjectInserter().insert(OBJ_BLOB, buf.length(), in);
  745. }
  746. } finally {
  747. buf.destroy();
  748. }
  749. }
  750. /**
  751. * Try to merge filemodes. If only ours or theirs have changed the mode
  752. * (compared to base) we choose that one. If ours and theirs have equal
  753. * modes return that one. If also that is not the case the modes are not
  754. * mergeable. Return {@link FileMode#MISSING} int that case.
  755. *
  756. * @param modeB
  757. * filemode found in BASE
  758. * @param modeO
  759. * filemode found in OURS
  760. * @param modeT
  761. * filemode found in THEIRS
  762. *
  763. * @return the merged filemode or {@link FileMode#MISSING} in case of a
  764. * conflict
  765. */
  766. private int mergeFileModes(int modeB, int modeO, int modeT) {
  767. if (modeO == modeT)
  768. return modeO;
  769. if (modeB == modeO)
  770. // Base equal to Ours -> chooses Theirs if that is not missing
  771. return (modeT == FileMode.MISSING.getBits()) ? modeO : modeT;
  772. if (modeB == modeT)
  773. // Base equal to Theirs -> chooses Ours if that is not missing
  774. return (modeO == FileMode.MISSING.getBits()) ? modeT : modeO;
  775. return FileMode.MISSING.getBits();
  776. }
  777. private static RawText getRawText(ObjectId id, ObjectReader reader)
  778. throws IOException {
  779. if (id.equals(ObjectId.zeroId()))
  780. return new RawText(new byte[] {});
  781. return new RawText(reader.open(id, OBJ_BLOB).getCachedBytes());
  782. }
  783. private static boolean nonTree(final int mode) {
  784. return mode != 0 && !FileMode.TREE.equals(mode);
  785. }
  786. private static boolean isGitLink(final int mode) {
  787. return FileMode.GITLINK.equals(mode);
  788. }
  789. @Override
  790. public ObjectId getResultTreeId() {
  791. return (resultTree == null) ? null : resultTree.toObjectId();
  792. }
  793. /**
  794. * @param commitNames
  795. * the names of the commits as they would appear in conflict
  796. * markers
  797. */
  798. public void setCommitNames(String[] commitNames) {
  799. this.commitNames = commitNames;
  800. }
  801. /**
  802. * @return the names of the commits as they would appear in conflict
  803. * markers.
  804. */
  805. public String[] getCommitNames() {
  806. return commitNames;
  807. }
  808. /**
  809. * @return the paths with conflicts. This is a subset of the files listed
  810. * by {@link #getModifiedFiles()}
  811. */
  812. public List<String> getUnmergedPaths() {
  813. return unmergedPaths;
  814. }
  815. /**
  816. * @return the paths of files which have been modified by this merge. A
  817. * file will be modified if a content-merge works on this path or if
  818. * the merge algorithm decides to take the theirs-version. This is a
  819. * superset of the files listed by {@link #getUnmergedPaths()}.
  820. */
  821. public List<String> getModifiedFiles() {
  822. return modifiedFiles;
  823. }
  824. /**
  825. * @return a map which maps the paths of files which have to be checked out
  826. * because the merge created new fully-merged content for this file
  827. * into the index. This means: the merge wrote a new stage 0 entry
  828. * for this path.
  829. */
  830. public Map<String, DirCacheEntry> getToBeCheckedOut() {
  831. return toBeCheckedOut;
  832. }
  833. /**
  834. * @return the mergeResults
  835. */
  836. public Map<String, MergeResult<? extends Sequence>> getMergeResults() {
  837. return mergeResults;
  838. }
  839. /**
  840. * @return lists paths causing this merge to fail (not stopped because of a
  841. * conflict). <code>null</code> is returned if this merge didn't
  842. * fail.
  843. */
  844. public Map<String, MergeFailureReason> getFailingPaths() {
  845. return (failingPaths.size() == 0) ? null : failingPaths;
  846. }
  847. /**
  848. * Returns whether this merge failed (i.e. not stopped because of a
  849. * conflict)
  850. *
  851. * @return <code>true</code> if a failure occurred, <code>false</code>
  852. * otherwise
  853. */
  854. public boolean failed() {
  855. return failingPaths.size() > 0;
  856. }
  857. /**
  858. * Sets the DirCache which shall be used by this merger. If the DirCache is
  859. * not set explicitly and if this merger doesn't work in-core, this merger
  860. * will implicitly get and lock a default DirCache. If the DirCache is
  861. * explicitly set the caller is responsible to lock it in advance. Finally
  862. * the merger will call {@link DirCache#commit()} which requires that the
  863. * DirCache is locked. If the {@link #mergeImpl()} returns without throwing
  864. * an exception the lock will be released. In case of exceptions the caller
  865. * is responsible to release the lock.
  866. *
  867. * @param dc
  868. * the DirCache to set
  869. */
  870. public void setDirCache(DirCache dc) {
  871. this.dircache = dc;
  872. implicitDirCache = false;
  873. }
  874. /**
  875. * Sets the WorkingTreeIterator to be used by this merger. If no
  876. * WorkingTreeIterator is set this merger will ignore the working tree and
  877. * fail if a content merge is necessary.
  878. * <p>
  879. * TODO: enhance WorkingTreeIterator to support write operations. Then this
  880. * merger will be able to merge with a different working tree abstraction.
  881. *
  882. * @param workingTreeIterator
  883. * the workingTreeIt to set
  884. */
  885. public void setWorkingTreeIterator(WorkingTreeIterator workingTreeIterator) {
  886. this.workingTreeIterator = workingTreeIterator;
  887. }
  888. /**
  889. * The resolve conflict way of three way merging
  890. *
  891. * @param baseTree
  892. * @param headTree
  893. * @param mergeTree
  894. * @param ignoreConflicts
  895. * Controls what to do in case a content-merge is done and a
  896. * conflict is detected. The default setting for this should be
  897. * <code>false</code>. In this case the working tree file is
  898. * filled with new content (containing conflict markers) and the
  899. * index is filled with multiple stages containing BASE, OURS and
  900. * THEIRS content. Having such non-0 stages is the sign to git
  901. * tools that there are still conflicts for that path.
  902. * <p>
  903. * If <code>true</code> is specified the behavior is different.
  904. * In case a conflict is detected the working tree file is again
  905. * filled with new content (containing conflict markers). But
  906. * also stage 0 of the index is filled with that content. No
  907. * other stages are filled. Means: there is no conflict on that
  908. * path but the new content (including conflict markers) is
  909. * stored as successful merge result. This is needed in the
  910. * context of {@link RecursiveMerger} where when determining
  911. * merge bases we don't want to deal with content-merge
  912. * conflicts.
  913. * @return whether the trees merged cleanly
  914. * @throws IOException
  915. * @since 3.5
  916. */
  917. protected boolean mergeTrees(AbstractTreeIterator baseTree,
  918. RevTree headTree, RevTree mergeTree, boolean ignoreConflicts)
  919. throws IOException {
  920. builder = dircache.builder();
  921. DirCacheBuildIterator buildIt = new DirCacheBuildIterator(builder);
  922. tw = new NameConflictTreeWalk(db, reader);
  923. tw.addTree(baseTree);
  924. tw.addTree(headTree);
  925. tw.addTree(mergeTree);
  926. int dciPos = tw.addTree(buildIt);
  927. if (workingTreeIterator != null) {
  928. tw.addTree(workingTreeIterator);
  929. workingTreeIterator.setDirCacheIterator(tw, dciPos);
  930. } else {
  931. tw.setFilter(TreeFilter.ANY_DIFF);
  932. }
  933. if (!mergeTreeWalk(tw, ignoreConflicts)) {
  934. return false;
  935. }
  936. if (!inCore) {
  937. // No problem found. The only thing left to be done is to
  938. // checkout all files from "theirs" which have been selected to
  939. // go into the new index.
  940. checkout();
  941. // All content-merges are successfully done. If we can now write the
  942. // new index we are on quite safe ground. Even if the checkout of
  943. // files coming from "theirs" fails the user can work around such
  944. // failures by checking out the index again.
  945. if (!builder.commit()) {
  946. cleanUp();
  947. throw new IndexWriteException();
  948. }
  949. builder = null;
  950. } else {
  951. builder.finish();
  952. builder = null;
  953. }
  954. if (getUnmergedPaths().isEmpty() && !failed()) {
  955. resultTree = dircache.writeTree(getObjectInserter());
  956. return true;
  957. } else {
  958. resultTree = null;
  959. return false;
  960. }
  961. }
  962. /**
  963. * Process the given TreeWalk's entries.
  964. *
  965. * @param treeWalk
  966. * The walk to iterate over.
  967. * @param ignoreConflicts
  968. * see
  969. * {@link ResolveMerger#mergeTrees(AbstractTreeIterator, RevTree, RevTree, boolean)}
  970. * @return Whether the trees merged cleanly.
  971. * @throws IOException
  972. * @since 3.5
  973. */
  974. protected boolean mergeTreeWalk(TreeWalk treeWalk, boolean ignoreConflicts)
  975. throws IOException {
  976. boolean hasWorkingTreeIterator = tw.getTreeCount() > T_FILE;
  977. while (treeWalk.next()) {
  978. if (!processEntry(
  979. treeWalk.getTree(T_BASE, CanonicalTreeParser.class),
  980. treeWalk.getTree(T_OURS, CanonicalTreeParser.class),
  981. treeWalk.getTree(T_THEIRS, CanonicalTreeParser.class),
  982. treeWalk.getTree(T_INDEX, DirCacheBuildIterator.class),
  983. hasWorkingTreeIterator ? treeWalk.getTree(T_FILE,
  984. WorkingTreeIterator.class) : null, ignoreConflicts)) {
  985. cleanUp();
  986. return false;
  987. }
  988. if (treeWalk.isSubtree() && enterSubtree)
  989. treeWalk.enterSubtree();
  990. }
  991. return true;
  992. }
  993. }