summaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit
diff options
context:
space:
mode:
authorThomas Wolf <thomas.wolf@paranor.ch>2020-11-15 18:45:12 +0100
committerThomas Wolf <thomas.wolf@paranor.ch>2020-11-17 14:27:28 +0100
commite84881ea6b67c6c3239df4e42cf73ffdadc13d56 (patch)
tree766ef29d89535fe4e91b2d8582b6d70c60c9f76e /org.eclipse.jgit
parentff6a827f4fa97815eac3b1a1ec53da8dfea41dd0 (diff)
downloadjgit-e84881ea6b67c6c3239df4e42cf73ffdadc13d56.tar.gz
jgit-e84881ea6b67c6c3239df4e42cf73ffdadc13d56.zip
Allow to resolve a conflict by checking out a file
DirCacheEditor unconditionally applied a PathEdit to all stages in the index. This gives wrong results if one wants to check out a file from some commit to resolve a conflict: JGit would update the working tree file multiple times (once per stage), and set all stages to point to the checked-out blob. C git replaces the stages by the entry for the checked-out file. To support this, add a DirCacheEntry.setStage() method so that CheckoutCommand can force the stage to zero. In DirCacheEditor, keep only the zero stage if the PathEdit re-set the stage. Bug: 568038 Change-Id: Ic7c635bb5aaa06ffaaeed50bc5e45702c56fc6d1 Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
Diffstat (limited to 'org.eclipse.jgit')
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java7
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEditor.java32
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java18
3 files changed, 50 insertions, 7 deletions
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
index 0dc5d5e7f7..847ab0a9a8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2010, Chris Aniszczyk <caniszczyk@gmail.com>
- * Copyright (C) 2011, Matthias Sohn <matthias.sohn@sap.com> and others
+ * Copyright (C) 2011, 2020 Matthias Sohn <matthias.sohn@sap.com> and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -503,6 +503,11 @@ public class CheckoutCommand extends GitCommand<Ref> {
editor.add(new PathEdit(path) {
@Override
public void apply(DirCacheEntry ent) {
+ if (ent.getStage() != DirCacheEntry.STAGE_0) {
+ // A checkout on a conflicting file stages the checked
+ // out file and resolves the conflict.
+ ent.setStage(DirCacheEntry.STAGE_0);
+ }
ent.setObjectId(blobId);
ent.setFileMode(mode);
checkoutPath(ent, r,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEditor.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEditor.java
index 73d2807eaf..8c342e267d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEditor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEditor.java
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2008-2009, Google Inc.
- * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others
+ * Copyright (C) 2008, 2009, Google Inc.
+ * Copyright (C) 2008, 2020 Shawn O. Pearce <spearce@spearce.org> and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -139,10 +139,28 @@ public class DirCacheEditor extends BaseDirCacheEditor {
: eIdx;
fastAdd(ent);
} else {
- // Apply to all entries of the current path (different stages)
lastIdx = cache.nextEntry(eIdx);
- for (int i = eIdx; i < lastIdx; i++) {
- final DirCacheEntry ent = cache.getEntry(i);
+ if (lastIdx > eIdx + 1) {
+ // Apply to all entries of the current path (different
+ // stages). If any apply() resets the stage to STAGE_0, take
+ // only that entry and omit all others.
+ DirCacheEntry[] tmp = new DirCacheEntry[lastIdx - eIdx];
+ int n = 0;
+ for (int i = eIdx; i < lastIdx; i++) {
+ DirCacheEntry ent = cache.getEntry(i);
+ e.apply(ent);
+ if (ent.getStage() == DirCacheEntry.STAGE_0) {
+ fastAdd(ent);
+ n = 0;
+ break;
+ }
+ tmp[n++] = ent;
+ }
+ for (int i = 0; i < n; i++) {
+ fastAdd(tmp[i]);
+ }
+ } else {
+ DirCacheEntry ent = cache.getEntry(eIdx);
e.apply(ent);
fastAdd(ent);
}
@@ -257,7 +275,9 @@ public class DirCacheEditor extends BaseDirCacheEditor {
* {@link #apply(DirCacheEntry)} method. The editor will invoke apply once
* for each record in the index which matches the path name. If there are
* multiple records (for example in stages 1, 2 and 3), the edit instance
- * will be called multiple times, once for each stage.
+ * will be called multiple times, once for each stage. If any of these calls
+ * resets the stage to 0, only this entry will be taken and entries for
+ * other stages are discarded.
*/
public abstract static class PathEdit {
final byte[] path;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java
index dcb84825fe..67edf50f44 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java
@@ -542,6 +542,24 @@ public class DirCacheEntry {
}
/**
+ * Sets the stage of an entry.
+ *
+ * @param stage
+ * to set, in the range [0..3]
+ * @throws IllegalArgumentException
+ * if the stage is outside the range [0..3]
+ * @since 5.10
+ */
+ public void setStage(int stage) {
+ if ((stage & ~0x3) != 0) {
+ throw new IllegalArgumentException(
+ "Invalid stage, must be in range [0..3]"); //$NON-NLS-1$
+ }
+ byte flags = info[infoOffset + P_FLAGS];
+ info[infoOffset + P_FLAGS] = (byte) ((flags & 0xCF) | (stage << 4));
+ }
+
+ /**
* Returns whether this entry should be skipped from the working tree.
*
* @return true if this entry should be skipepd.