aboutsummaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit/src/org/eclipse/jgit/merge
diff options
context:
space:
mode:
authorChristian Halstrick <christian.halstrick@sap.com>2012-07-26 16:20:38 +0200
committerChristian Halstrick <christian.halstrick@sap.com>2012-07-26 16:20:38 +0200
commit778fdfaec1d1f5b16775264ebf728ee882000154 (patch)
treefdc5b632557b206b1e0ecdafd70a29b46145be3c /org.eclipse.jgit/src/org/eclipse/jgit/merge
parentd87e56adddb03c9eb731ee835fdb7f2a59824f46 (diff)
downloadjgit-778fdfaec1d1f5b16775264ebf728ee882000154.tar.gz
jgit-778fdfaec1d1f5b16775264ebf728ee882000154.zip
Again teach ResolveMerger to create more correct DirCacheEntry's
Currently, after a merge/cherry-pick/rebase, all index entries are smudged as the ResolveMerger never sets entry lengths and/or modification times. This change teaches it to re-set them at least for things it did not touch. The other entries are then repaired when the index is persisted, or entries are checked out. The first attempt to get this in was commit 3ea694c2523d909190b5350e13254a62e94ec5d5 which has been reverted. Since then some fixes to ResolveMerger and a few more tests have been added which check situations where the index is not matching HEAD before we merge. Change-Id: I648fda30846615b3bf688c34274c6cf4bc857832 Signed-off-by: Christian Halstrick <christian.halstrick@sap.com> Also-by: Markus Duft <markus.duft@salomon.at>
Diffstat (limited to 'org.eclipse.jgit/src/org/eclipse/jgit/merge')
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java116
1 files changed, 81 insertions, 35 deletions
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
index 2410d6fe04..212938efe8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
@@ -204,6 +204,11 @@ public class ResolveMerger extends ThreeWayMerger {
}
if (!inCore) {
+ // No problem found. The only thing left to be done is to
+ // checkout all files from "theirs" which have been selected to
+ // go into the new index.
+ checkout();
+
// All content-merges are successfully done. If we can now write the
// new index we are on quite safe ground. Even if the checkout of
// files coming from "theirs" fails the user can work around such
@@ -214,10 +219,6 @@ public class ResolveMerger extends ThreeWayMerger {
}
builder = null;
- // No problem found. The only thing left to be done is to checkout
- // all files from "theirs" which have been selected to go into the
- // new index.
- checkout();
} else {
builder.finish();
builder = null;
@@ -313,13 +314,18 @@ public class ResolveMerger extends ThreeWayMerger {
* @param path
* @param p
* @param stage
+ * @param lastMod
+ * @param len
* @return the entry which was added to the index
*/
- private DirCacheEntry add(byte[] path, CanonicalTreeParser p, int stage) {
+ private DirCacheEntry add(byte[] path, CanonicalTreeParser p, int stage,
+ long lastMod, long len) {
if (p != null && !p.getEntryFileMode().equals(FileMode.TREE)) {
DirCacheEntry e = new DirCacheEntry(path, stage);
e.setFileMode(p.getEntryFileMode());
e.setObjectId(p.getEntryObjectId());
+ e.setLastModified(lastMod);
+ e.setLength(len);
builder.add(e);
return e;
}
@@ -327,6 +333,26 @@ public class ResolveMerger extends ThreeWayMerger {
}
/**
+ * adds a entry to the index builder which is a copy of the specified
+ * DirCacheEntry
+ *
+ * @param e
+ * the entry which should be copied
+ *
+ * @return the entry which was added to the index
+ */
+ private DirCacheEntry keep(DirCacheEntry e) {
+ DirCacheEntry newEntry = new DirCacheEntry(e.getPathString(),
+ e.getStage());
+ newEntry.setFileMode(e.getFileMode());
+ newEntry.setObjectId(e.getObjectId());
+ newEntry.setLastModified(e.getLastModified());
+ newEntry.setLength(e.getLength());
+ builder.add(newEntry);
+ return newEntry;
+ }
+
+ /**
* Processes one path and tries to merge. This method will do all do all
* trivial (not content) merges and will also detect if a merge will fail.
* The merge will fail when one of the following is true
@@ -382,12 +408,27 @@ public class ResolveMerger extends ThreeWayMerger {
if (isIndexDirty())
return false;
+ DirCacheEntry ourDce = null;
+
+ if (index == null || index.getDirCacheEntry() == null) {
+ // create a fake DCE, but only if ours is valid. ours is kept only
+ // in case it is valid, so a null ourDce is ok in all other cases.
+ if (nonTree(modeO)) {
+ ourDce = new DirCacheEntry(tw.getRawPath());
+ ourDce.setObjectId(tw.getObjectId(T_OURS));
+ ourDce.setFileMode(tw.getFileMode(T_OURS));
+ }
+ } else {
+ ourDce = index.getDirCacheEntry();
+ }
+
if (nonTree(modeO) && nonTree(modeT) && tw.idEqual(T_OURS, T_THEIRS)) {
// OURS and THEIRS have equal content. Check the file mode
if (modeO == modeT) {
// content and mode of OURS and THEIRS are equal: it doesn't
- // matter which one we choose. OURS is chosen.
- add(tw.getRawPath(), ours, DirCacheEntry.STAGE_0);
+ // matter which one we choose. OURS is chosen. Since the index
+ // is clean (the index matches already OURS) we can keep the existing one
+ keep(ourDce);
// no checkout needed!
return true;
} else {
@@ -398,22 +439,25 @@ public class ResolveMerger extends ThreeWayMerger {
if (newMode != FileMode.MISSING.getBits()) {
if (newMode == modeO)
// ours version is preferred
- add(tw.getRawPath(), ours, DirCacheEntry.STAGE_0);
+ keep(ourDce);
else {
// the preferred version THEIRS has a different mode
// than ours. Check it out!
if (isWorktreeDirty(work))
return false;
+ // we know about length and lastMod only after we have written the new content.
+ // This will happen later. Set these values to 0 for know.
DirCacheEntry e = add(tw.getRawPath(), theirs,
- DirCacheEntry.STAGE_0);
+ DirCacheEntry.STAGE_0, 0, 0);
toBeCheckedOut.put(tw.getPathString(), e);
}
return true;
} else {
- // FileModes are not mergeable. We found a conflict on modes
- add(tw.getRawPath(), base, DirCacheEntry.STAGE_1);
- add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2);
- add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3);
+ // FileModes are not mergeable. We found a conflict on modes.
+ // For conflicting entries we don't know lastModified and length.
+ add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, 0, 0);
+ add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, 0, 0);
+ add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, 0, 0);
unmergedPaths.add(tw.getPathString());
mergeResults.put(
tw.getPathString(),
@@ -426,8 +470,8 @@ public class ResolveMerger extends ThreeWayMerger {
if (nonTree(modeO) && modeB == modeT && tw.idEqual(T_BASE, T_THEIRS)) {
// THEIRS was not changed compared to BASE. All changes must be in
- // OURS. OURS is chosen.
- add(tw.getRawPath(), ours, DirCacheEntry.STAGE_0);
+ // OURS. OURS is chosen. We can keep the existing entry.
+ keep(ourDce);
// no checkout needed!
return true;
}
@@ -440,8 +484,11 @@ public class ResolveMerger extends ThreeWayMerger {
if (isWorktreeDirty(work))
return false;
if (nonTree(modeT)) {
+ // we know about length and lastMod only after we have written
+ // the new content.
+ // This will happen later. Set these values to 0 for know.
DirCacheEntry e = add(tw.getRawPath(), theirs,
- DirCacheEntry.STAGE_0);
+ DirCacheEntry.STAGE_0, 0, 0);
if (e != null)
toBeCheckedOut.put(tw.getPathString(), e);
return true;
@@ -460,16 +507,16 @@ public class ResolveMerger extends ThreeWayMerger {
// detected later
if (nonTree(modeO) && !nonTree(modeT)) {
if (nonTree(modeB))
- add(tw.getRawPath(), base, DirCacheEntry.STAGE_1);
- add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2);
+ add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, 0, 0);
+ add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, 0, 0);
unmergedPaths.add(tw.getPathString());
enterSubtree = false;
return true;
}
if (nonTree(modeT) && !nonTree(modeO)) {
if (nonTree(modeB))
- add(tw.getRawPath(), base, DirCacheEntry.STAGE_1);
- add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3);
+ add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, 0, 0);
+ add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, 0, 0);
unmergedPaths.add(tw.getPathString());
enterSubtree = false;
return true;
@@ -502,10 +549,10 @@ public class ResolveMerger extends ThreeWayMerger {
if (((modeO != 0 && !tw.idEqual(T_BASE, T_OURS)) || (modeT != 0 && !tw
.idEqual(T_BASE, T_THEIRS)))) {
- add(tw.getRawPath(), base, DirCacheEntry.STAGE_1);
- add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2);
+ add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, 0, 0);
+ add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, 0, 0);
DirCacheEntry e = add(tw.getRawPath(), theirs,
- DirCacheEntry.STAGE_3);
+ DirCacheEntry.STAGE_3, 0, 0);
// OURS was deleted checkout THEIRS
if (modeO == 0) {
@@ -567,19 +614,16 @@ public class ResolveMerger extends ThreeWayMerger {
}
private boolean isWorktreeDirty(WorkingTreeIterator work) {
- if (inCore)
+ if (inCore || work == null)
return false;
final int modeF = tw.getRawMode(T_FILE);
final int modeO = tw.getRawMode(T_OURS);
// Worktree entry has to match ours to be considered clean
- final boolean isDirty;
- if (nonTree(modeF))
- isDirty = work.isModeDifferent(modeO)
- || !tw.idEqual(T_FILE, T_OURS);
- else
- isDirty = false;
+ boolean isDirty = work.isModeDifferent(modeO);
+ if (!isDirty && nonTree(modeF))
+ isDirty = !tw.idEqual(T_FILE, T_OURS);
if (isDirty)
failingPaths.put(tw.getPathString(),
@@ -609,9 +653,9 @@ public class ResolveMerger extends ThreeWayMerger {
// a conflict occurred, the file will contain conflict markers
// the index will be populated with the three stages and only the
// workdir (if used) contains the halfways merged content
- add(tw.getRawPath(), base, DirCacheEntry.STAGE_1);
- add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2);
- add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3);
+ add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, 0, 0);
+ add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, 0, 0);
+ add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, 0, 0);
mergeResults.put(tw.getPathString(), result);
} else {
// no conflict occurred, the file will contain fully merged content.
@@ -662,6 +706,9 @@ public class ResolveMerger extends ThreeWayMerger {
throw new UnsupportedOperationException();
of = new File(workTree, tw.getPathString());
+ File parentFolder = of.getParentFile();
+ if (!parentFolder.exists())
+ parentFolder.mkdirs();
fos = new FileOutputStream(of);
try {
fmt.formatMerge(fos, result, Arrays.asList(commitNames),
@@ -669,8 +716,7 @@ public class ResolveMerger extends ThreeWayMerger {
} finally {
fos.close();
}
- }
- else if (!result.containsConflicts()) {
+ } else if (!result.containsConflicts()) {
// When working inCore, only trivial merges can be handled,
// so we generate objects only in conflict free cases
of = File.createTempFile("merge_", "_temp", null);