diff options
author | Christian Halstrick <christian.halstrick@sap.com> | 2018-02-12 15:44:04 +0100 |
---|---|---|
committer | Christian Halstrick <christian.halstrick@sap.com> | 2019-01-08 10:01:09 +0100 |
commit | e406d500de01b9ae7155e296baebf3ec8024869d (patch) | |
tree | 3873d4a07a3c46d662d7ed5d66cd234c2f07188c /org.eclipse.jgit | |
parent | 6c8240a75126013b7f4588d78e66baa54e89cbfc (diff) | |
download | jgit-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.java | 58 | ||||
-rw-r--r-- | org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java | 42 |
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 * |