summaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit
diff options
context:
space:
mode:
authorChristian Halstrick <christian.halstrick@sap.com>2018-02-12 15:44:04 +0100
committerChristian Halstrick <christian.halstrick@sap.com>2019-01-08 10:01:09 +0100
commite406d500de01b9ae7155e296baebf3ec8024869d (patch)
tree3873d4a07a3c46d662d7ed5d66cd234c2f07188c /org.eclipse.jgit
parent6c8240a75126013b7f4588d78e66baa54e89cbfc (diff)
downloadjgit-e406d500de01b9ae7155e296baebf3ec8024869d.tar.gz
jgit-e406d500de01b9ae7155e296baebf3ec8024869d.zip
Fix "jgit checkout -f" to overwrite dirty worktree files
CheckoutCommand had a setForce() method. But this didn't correspond to native git's 'git checkout -f' option. Deprecate the old setForce() method and move its implementation to a new method setForceRefUpdate() and use it to implement the -B option in the CLI class Checkout. Add a setForced() method and use it to fix the associated '-f' option of the CLI Checkout class to behave like native git's 'git checkout -f' which overwrites dirty worktree files during checkout. This is still not fully matching native git's behavior: updating additionally dirty index entries is not done yet. Bug: 530771 Change-Id: I776b78eb623b6ea0aca42f681788f2e4b1667f15 Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
Diffstat (limited to 'org.eclipse.jgit')
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java58
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java42
2 files changed, 86 insertions, 14 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 455a2e665f..e05f6f1bd6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
@@ -162,7 +162,9 @@ public class CheckoutCommand extends GitCommand<Ref> {
private String name;
- private boolean force = false;
+ private boolean forceRefUpdate = false;
+
+ private boolean forced = false;
private boolean createBranch = false;
@@ -269,7 +271,11 @@ public class CheckoutCommand extends GitCommand<Ref> {
try {
dco = new DirCacheCheckout(repo, headTree, dc,
newCommit.getTree());
- dco.setFailOnConflict(!force);
+ dco.setFailOnConflict(true);
+ dco.setForce(forced);
+ if (forced) {
+ dco.setFailOnConflict(false);
+ }
dco.setProgressMonitor(monitor);
try {
dco.checkout();
@@ -286,7 +292,7 @@ public class CheckoutCommand extends GitCommand<Ref> {
ref = null;
String toName = Repository.shortenRefName(name);
RefUpdate refUpdate = repo.updateRef(Constants.HEAD, ref == null);
- refUpdate.setForceUpdate(force);
+ refUpdate.setForceUpdate(forceRefUpdate);
refUpdate.setRefLogMessage(refLogMessage + " to " + toName, false); //$NON-NLS-1$
Result updateResult;
if (ref != null)
@@ -666,10 +672,54 @@ public class CheckoutCommand extends GitCommand<Ref> {
* set to a new start-point; if false, the existing branch will
* not be changed
* @return this instance
+ * @deprecated this method was badly named comparing its semantics to native
+ * git's checkout --force option, use
+ * {@link #setForceRefUpdate(boolean)} instead
*/
+ @Deprecated
public CheckoutCommand setForce(boolean force) {
+ return setForceRefUpdate(force);
+ }
+
+ /**
+ * Specify to force the ref update in case of a branch switch.
+ *
+ * In releases prior to 5.2 this method was called setForce() but this name
+ * was misunderstood to implement native git's --force option, which is not
+ * true.
+ *
+ * @param forceRefUpdate
+ * if <code>true</code> and the branch with the given name
+ * already exists, the start-point of an existing branch will be
+ * set to a new start-point; if false, the existing branch will
+ * not be changed
+ * @return this instance
+ * @since 5.3
+ */
+ public CheckoutCommand setForceRefUpdate(boolean forceRefUpdate) {
+ checkCallable();
+ this.forceRefUpdate = forceRefUpdate;
+ return this;
+ }
+
+ /**
+ * Allow a checkout even if the workingtree or index differs from HEAD. This
+ * matches native git's '--force' option.
+ *
+ * JGit releases before 5.2 had a method <code>setForce()</code> offering
+ * semantics different from this new <code>setForced()</code>. This old
+ * semantic can now be found in {@link #setForceRefUpdate(boolean)}
+ *
+ * @param forced
+ * if set to <code>true</code> then allow the checkout even if
+ * workingtree or index doesn't match HEAD. Overwrite workingtree
+ * files and index content with the new content in this case.
+ * @return this instance
+ * @since 5.3
+ */
+ public CheckoutCommand setForced(boolean forced) {
checkCallable();
- this.force = force;
+ this.forced = forced;
return this;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
index ce7485bf1f..307fd3f310 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
@@ -155,6 +155,8 @@ public class DirCacheCheckout {
private boolean failOnConflict = true;
+ private boolean force = false;
+
private ArrayList<String> toBeDeleted = new ArrayList<>();
private boolean initialCheckout;
@@ -427,11 +429,11 @@ public class DirCacheCheckout {
DirCacheEntry entry = i.getDirCacheEntry();
if (entry.getLastModified() == 0)
entry.setLastModified(f.getEntryLastModified());
- keep(entry);
+ keep(entry, f);
}
} else
// The index contains a folder
- keep(i.getDirCacheEntry());
+ keep(i.getDirCacheEntry(), f);
} else {
// There is no entry in the merge commit. Means: we want to delete
// what's currently in the index and working tree
@@ -821,14 +823,14 @@ public class DirCacheCheckout {
break;
case 0xDFD: // 3 4
- keep(dce);
+ keep(dce, f);
break;
case 0xF0D: // 18
remove(name);
break;
case 0xDFF: // 5 5b 6 6b
if (equalIdAndMode(iId, iMode, mId, mMode))
- keep(dce); // 5 6
+ keep(dce, f); // 5 6
else
conflict(name, dce, h, m); // 5b 6b
break;
@@ -858,7 +860,7 @@ public class DirCacheCheckout {
conflict(name, dce, h, m); // 9
break;
case 0xFD0: // keep without a rule
- keep(dce);
+ keep(dce, f);
break;
case 0xFFD: // 12 13 14
if (equalIdAndMode(hId, hMode, iId, iMode))
@@ -878,7 +880,7 @@ public class DirCacheCheckout {
conflict(name, dce, h, m);
break;
default:
- keep(dce);
+ keep(dce, f);
}
return;
}
@@ -964,7 +966,7 @@ public class DirCacheCheckout {
if (initialCheckout)
update(name, mId, mMode);
else
- keep(dce);
+ keep(dce, f);
} else
conflict(name, dce, h, m);
}
@@ -1027,7 +1029,7 @@ public class DirCacheCheckout {
// Nothing in Head
// Something in Index
// -> Merge contains nothing new. Keep the index.
- keep(dce);
+ keep(dce, f);
} else
// Merge contains something and it is not the same as Index
// Nothing in Head
@@ -1176,7 +1178,7 @@ public class DirCacheCheckout {
// to the other one.
// -> In all three cases we don't touch index and file.
- keep(dce);
+ keep(dce, f);
}
}
}
@@ -1225,9 +1227,15 @@ public class DirCacheCheckout {
}
}
- private void keep(DirCacheEntry e) {
+ private void keep(DirCacheEntry e, WorkingTreeIterator f)
+ throws IOException {
if (e != null && !FileMode.TREE.equals(e.getFileMode()))
builder.add(e);
+ if (force) {
+ if (f.isModified(e, true, this.walk.getObjectReader())) {
+ checkoutEntry(repo, e, this.walk.getObjectReader());
+ }
+ }
}
private void remove(String path) {
@@ -1262,6 +1270,20 @@ public class DirCacheCheckout {
}
/**
+ * If <code>true</code>, dirty worktree files may be overridden. If
+ * <code>false</code> dirty worktree files will not be overridden in order
+ * not to delete unsaved content. This corresponds to native git's 'git
+ * checkout -f' option. By default this option is set to false.
+ *
+ * @param force
+ * a boolean.
+ * @since 5.3
+ */
+ public void setForce(boolean force) {
+ this.force = force;
+ }
+
+ /**
* This method implements how to handle conflicts when
* {@link #failOnConflict} is false
*