Merge changes Ib6689f54,I3b5c22ee
* changes:
Remove unused API problem filters
Add missing @since tag for RevCommit#parents introduced in 61b4d105e4
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java
index 5dfdfcf..57661a7 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java
@@ -15,13 +15,16 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
+import java.nio.file.Files;
import java.util.Set;
+import org.eclipse.jgit.api.ResetCommand.ResetType;
import org.eclipse.jgit.api.errors.FilterFailedException;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.NoFilepatternException;
@@ -34,6 +37,7 @@
import org.eclipse.jgit.lfs.BuiltinLFS;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.CoreConfig.SymLinks;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
@@ -100,6 +104,43 @@
}
@Test
+ public void testAddLink() throws IOException, GitAPIException {
+ assumeTrue(db.getFS().supportsSymlinks());
+ try (Git git = new Git(db)) {
+ writeTrashFile("a.txt", "a");
+ File link = new File(db.getWorkTree(), "link");
+ db.getFS().createSymLink(link, "a.txt");
+ git.add().addFilepattern(".").call();
+ assertEquals(
+ "[a.txt, mode:100644, content:a][link, mode:120000, content:a.txt]",
+ indexState(CONTENT));
+ git.commit().setMessage("link").call();
+ StoredConfig config = db.getConfig();
+ config.setEnum(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_SYMLINKS, SymLinks.FALSE);
+ config.save();
+ Files.delete(link.toPath());
+ git.reset().setMode(ResetType.HARD).call();
+ assertTrue(Files.isRegularFile(link.toPath()));
+ assertEquals(
+ "[a.txt, mode:100644, content:a][link, mode:120000, content:a.txt]",
+ indexState(CONTENT));
+ writeTrashFile("link", "b.txt");
+ git.add().addFilepattern("link").call();
+ assertEquals(
+ "[a.txt, mode:100644, content:a][link, mode:120000, content:b.txt]",
+ indexState(CONTENT));
+ config.setEnum(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_SYMLINKS, SymLinks.TRUE);
+ config.save();
+ git.add().addFilepattern("link").call();
+ assertEquals(
+ "[a.txt, mode:100644, content:a][link, mode:100644, content:b.txt]",
+ indexState(CONTENT));
+ }
+ }
+
+ @Test
public void testCleanFilter() throws IOException, GitAPIException {
writeTrashFile(".gitattributes", "*.txt filter=tstFilter");
writeTrashFile("src/a.tmp", "foo");
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java
index 0d49cd3..e463e90 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java
@@ -303,12 +303,16 @@
DirCacheEntry dce = db.readDirCache().getEntry("symlink");
dce.setFileMode(FileMode.SYMLINK);
try (ObjectReader objectReader = db.newObjectReader()) {
- DirCacheCheckout.checkoutEntry(db, dce, objectReader, false, null);
+ WorkingTreeOptions options = db.getConfig()
+ .get(WorkingTreeOptions.KEY);
+ DirCacheCheckout.checkoutEntry(db, dce, objectReader, false, null,
+ options);
FileTreeIterator fti = new FileTreeIterator(trash, db.getFS(),
- db.getConfig().get(WorkingTreeOptions.KEY));
- while (!fti.getEntryPathString().equals("symlink"))
+ options);
+ while (!fti.getEntryPathString().equals("symlink")) {
fti.next(1);
+ }
assertFalse(fti.isModified(dce, false, objectReader));
}
}
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 847ab0a..7319ff4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
@@ -55,6 +55,7 @@
import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.treewalk.WorkingTreeOptions;
import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
/**
@@ -411,6 +412,8 @@
protected CheckoutCommand checkoutPaths() throws IOException,
RefNotFoundException {
actuallyModifiedPaths = new HashSet<>();
+ WorkingTreeOptions options = repo.getConfig()
+ .get(WorkingTreeOptions.KEY);
DirCache dc = repo.lockDirCache();
try (RevWalk revWalk = new RevWalk(repo);
TreeWalk treeWalk = new TreeWalk(repo,
@@ -419,10 +422,10 @@
if (!checkoutAllPaths)
treeWalk.setFilter(PathFilterGroup.createFromStrings(paths));
if (isCheckoutIndex())
- checkoutPathsFromIndex(treeWalk, dc);
+ checkoutPathsFromIndex(treeWalk, dc, options);
else {
RevCommit commit = revWalk.parseCommit(getStartPointObjectId());
- checkoutPathsFromCommit(treeWalk, dc, commit);
+ checkoutPathsFromCommit(treeWalk, dc, commit, options);
}
} finally {
try {
@@ -439,7 +442,8 @@
return this;
}
- private void checkoutPathsFromIndex(TreeWalk treeWalk, DirCache dc)
+ private void checkoutPathsFromIndex(TreeWalk treeWalk, DirCache dc,
+ WorkingTreeOptions options)
throws IOException {
DirCacheIterator dci = new DirCacheIterator(dc);
treeWalk.addTree(dci);
@@ -465,8 +469,9 @@
if (stage > DirCacheEntry.STAGE_0) {
if (checkoutStage != null) {
if (stage == checkoutStage.number) {
- checkoutPath(ent, r, new CheckoutMetadata(
- eolStreamType, filterCommand));
+ checkoutPath(ent, r, options,
+ new CheckoutMetadata(eolStreamType,
+ filterCommand));
actuallyModifiedPaths.add(path);
}
} else {
@@ -475,8 +480,9 @@
throw new JGitInternalException(e.getMessage(), e);
}
} else {
- checkoutPath(ent, r, new CheckoutMetadata(eolStreamType,
- filterCommand));
+ checkoutPath(ent, r, options,
+ new CheckoutMetadata(eolStreamType,
+ filterCommand));
actuallyModifiedPaths.add(path);
}
}
@@ -488,7 +494,7 @@
}
private void checkoutPathsFromCommit(TreeWalk treeWalk, DirCache dc,
- RevCommit commit) throws IOException {
+ RevCommit commit, WorkingTreeOptions options) throws IOException {
treeWalk.addTree(commit.getTree());
final ObjectReader r = treeWalk.getObjectReader();
DirCacheEditor editor = dc.editor();
@@ -510,7 +516,7 @@
}
ent.setObjectId(blobId);
ent.setFileMode(mode);
- checkoutPath(ent, r,
+ checkoutPath(ent, r, options,
new CheckoutMetadata(eolStreamType, filterCommand));
actuallyModifiedPaths.add(path);
}
@@ -520,10 +526,10 @@
}
private void checkoutPath(DirCacheEntry entry, ObjectReader reader,
- CheckoutMetadata checkoutMetadata) {
+ WorkingTreeOptions options, CheckoutMetadata checkoutMetadata) {
try {
DirCacheCheckout.checkoutEntry(repo, entry, reader, true,
- checkoutMetadata);
+ checkoutMetadata, options);
} catch (IOException e) {
throw new JGitInternalException(MessageFormat.format(
JGitText.get().checkoutConflictWithFile,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java
index 1004d3e..17036a9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java
@@ -48,6 +48,7 @@
import org.eclipse.jgit.treewalk.AbstractTreeIterator;
import org.eclipse.jgit.treewalk.FileTreeIterator;
import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.treewalk.WorkingTreeOptions;
/**
* Command class to apply a stashed commit.
@@ -382,6 +383,8 @@
private void resetUntracked(RevTree tree) throws CheckoutConflictException,
IOException {
Set<String> actuallyModifiedPaths = new HashSet<>();
+ WorkingTreeOptions options = repo.getConfig()
+ .get(WorkingTreeOptions.KEY);
// TODO maybe NameConflictTreeWalk ?
try (TreeWalk walk = new TreeWalk(repo)) {
walk.addTree(tree);
@@ -413,7 +416,7 @@
}
}
- checkoutPath(entry, reader,
+ checkoutPath(entry, reader, options,
new CheckoutMetadata(eolStreamType, null));
actuallyModifiedPaths.add(entry.getPathString());
}
@@ -426,10 +429,10 @@
}
private void checkoutPath(DirCacheEntry entry, ObjectReader reader,
- CheckoutMetadata checkoutMetadata) {
+ WorkingTreeOptions options, CheckoutMetadata checkoutMetadata) {
try {
DirCacheCheckout.checkoutEntry(repo, entry, reader, true,
- checkoutMetadata);
+ checkoutMetadata, options);
} catch (IOException e) {
throw new JGitInternalException(MessageFormat.format(
JGitText.get().checkoutConflictWithFile,
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 f6fc393..2365c90 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
@@ -143,6 +143,8 @@
private boolean performingCheckout;
+ private WorkingTreeOptions options;
+
private ProgressMonitor monitor = NullProgressMonitor.INSTANCE;
/**
@@ -362,9 +364,12 @@
* Processing an entry in the context of {@link #prescanOneTree()} when only
* one tree is given
*
- * @param m the tree to merge
- * @param i the index
- * @param f the working tree
+ * @param m
+ * the tree to merge
+ * @param i
+ * the index
+ * @param f
+ * the working tree
* @throws IOException
*/
void processEntry(CanonicalTreeParser m, DirCacheBuildIterator i,
@@ -489,6 +494,8 @@
MissingObjectException, IncorrectObjectTypeException,
CheckoutConflictException, IndexWriteException, CanceledException {
toBeDeleted.clear();
+ options = repo.getConfig()
+ .get(WorkingTreeOptions.KEY);
try (ObjectReader objectReader = repo.getObjectDatabase().newReader()) {
if (headCommitTree != null)
preScanTwoTrees();
@@ -558,7 +565,8 @@
if (FileMode.GITLINK.equals(entry.getRawMode())) {
checkoutGitlink(path, entry);
} else {
- checkoutEntry(repo, entry, objectReader, false, meta);
+ checkoutEntry(repo, entry, objectReader, false, meta,
+ options);
}
e = null;
@@ -594,7 +602,7 @@
}
if (entry.getStage() == DirCacheEntry.STAGE_3) {
checkoutEntry(repo, entry, objectReader, false,
- null);
+ null, options);
break;
}
++entryIdx;
@@ -1226,7 +1234,7 @@
checkoutEntry(repo, e, walk.getObjectReader(), false,
new CheckoutMetadata(walk.getEolStreamType(CHECKOUT_OP),
walk.getFilterCommand(
- Constants.ATTR_FILTER_TYPE_SMUDGE)));
+ Constants.ATTR_FILTER_TYPE_SMUDGE)), options);
}
}
}
@@ -1392,12 +1400,6 @@
* cannot be renamed to file or link without deleting it recursively.
* </p>
*
- * <p>
- * TODO: this method works directly on File IO, we may need another
- * abstraction (like WorkingTreeIterator). This way we could tell e.g.
- * Eclipse that Files in the workspace got changed
- * </p>
- *
* @param repo
* repository managing the destination work tree.
* @param entry
@@ -1407,15 +1409,16 @@
* @throws java.io.IOException
* @since 3.6
* @deprecated since 5.1, use
- * {@link #checkoutEntry(Repository, DirCacheEntry, ObjectReader, boolean, CheckoutMetadata)}
+ * {@link #checkoutEntry(Repository, DirCacheEntry, ObjectReader, boolean, CheckoutMetadata, WorkingTreeOptions)}
* instead
*/
@Deprecated
public static void checkoutEntry(Repository repo, DirCacheEntry entry,
ObjectReader or) throws IOException {
- checkoutEntry(repo, entry, or, false, null);
+ checkoutEntry(repo, entry, or, false, null, null);
}
+
/**
* Updates the file in the working tree with content and mode from an entry
* in the index. The new content is first written to a new temporary file in
@@ -1428,12 +1431,6 @@
* recursively, independently if has any content.
* </p>
*
- * <p>
- * TODO: this method works directly on File IO, we may need another
- * abstraction (like WorkingTreeIterator). This way we could tell e.g.
- * Eclipse that Files in the workspace got changed
- * </p>
- *
* @param repo
* repository managing the destination work tree.
* @param entry
@@ -1452,12 +1449,58 @@
* </ul>
* @throws java.io.IOException
* @since 4.2
+ * @deprecated since 6.3, use
+ * {@link #checkoutEntry(Repository, DirCacheEntry, ObjectReader, boolean, CheckoutMetadata, WorkingTreeOptions)}
+ * instead
*/
+ @Deprecated
public static void checkoutEntry(Repository repo, DirCacheEntry entry,
ObjectReader or, boolean deleteRecursive,
CheckoutMetadata checkoutMetadata) throws IOException {
- if (checkoutMetadata == null)
+ checkoutEntry(repo, entry, or, deleteRecursive, checkoutMetadata, null);
+ }
+
+ /**
+ * Updates the file in the working tree with content and mode from an entry
+ * in the index. The new content is first written to a new temporary file in
+ * the same directory as the real file. Then that new file is renamed to the
+ * final filename.
+ *
+ * <p>
+ * <b>Note:</b> if the entry path on local file system exists as a file, it
+ * will be deleted and if it exists as a directory, it will be deleted
+ * recursively, independently if has any content.
+ * </p>
+ *
+ * @param repo
+ * repository managing the destination work tree.
+ * @param entry
+ * the entry containing new mode and content
+ * @param or
+ * object reader to use for checkout
+ * @param deleteRecursive
+ * true to recursively delete final path if it exists on the file
+ * system
+ * @param checkoutMetadata
+ * containing
+ * <ul>
+ * <li>smudgeFilterCommand to be run for smudging the entry to be
+ * checked out</li>
+ * <li>eolStreamType used for stream conversion</li>
+ * </ul>
+ * @param options
+ * {@link WorkingTreeOptions} that are effective; if {@code null}
+ * they are loaded from the repository config
+ * @throws java.io.IOException
+ * @since 6.3
+ */
+ public static void checkoutEntry(Repository repo, DirCacheEntry entry,
+ ObjectReader or, boolean deleteRecursive,
+ CheckoutMetadata checkoutMetadata, WorkingTreeOptions options)
+ throws IOException {
+ if (checkoutMetadata == null) {
checkoutMetadata = CheckoutMetadata.EMPTY;
+ }
ObjectLoader ol = or.open(entry.getObjectId());
File f = new File(repo.getWorkTree(), entry.getPathString());
File parentDir = f.getParentFile();
@@ -1466,7 +1509,8 @@
}
FileUtils.mkdirs(parentDir, true);
FS fs = repo.getFS();
- WorkingTreeOptions opt = repo.getConfig().get(WorkingTreeOptions.KEY);
+ WorkingTreeOptions opt = options != null ? options
+ : repo.getConfig().get(WorkingTreeOptions.KEY);
if (entry.getFileMode() == FileMode.SYMLINK
&& opt.getSymLinks() == SymLinks.TRUE) {
byte[] bytes = ol.getBytes();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
index b108b0a..d8a61ec 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
@@ -1004,6 +1004,12 @@
return wtMode;
}
final FileMode iMode = indexIter.getEntryFileMode();
+ if (iMode == FileMode.SYMLINK
+ && getOptions().getSymLinks() == SymLinks.FALSE
+ && (wtMode == FileMode.REGULAR_FILE
+ || wtMode == FileMode.EXECUTABLE_FILE)) {
+ return iMode;
+ }
if (getOptions().isFileMode() && iMode != FileMode.GITLINK && iMode != FileMode.TREE) {
return wtMode;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/WorkTreeUpdater.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/WorkTreeUpdater.java
index fb0b33a..88529ba 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/WorkTreeUpdater.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/WorkTreeUpdater.java
@@ -495,7 +495,9 @@
new File(nonNullNonBareRepo().getWorkTree(), entry.getKey()).mkdirs();
} else {
DirCacheCheckout.checkoutEntry(
- repo, dirCacheEntry, reader, false, checkoutMetadata.get(entry.getKey()));
+ repo, dirCacheEntry, reader, false,
+ checkoutMetadata.get(entry.getKey()),
+ workingTreeOptions);
result.modifiedFiles.add(entry.getKey());
}
}
@@ -520,7 +522,8 @@
DirCacheEntry entry = dirCache.getEntry(path);
if (entry != null) {
DirCacheCheckout.checkoutEntry(
- repo, entry, reader, false, cleanupMetadata.get(path));
+ repo, entry, reader, false, cleanupMetadata.get(path),
+ workingTreeOptions);
}
}
}
@@ -554,22 +557,30 @@
if (inCore) {
return;
}
- CheckoutMetadata checkoutMetadata = new CheckoutMetadata(streamType, smudgeCommand);
+ CheckoutMetadata metadata = new CheckoutMetadata(streamType,
+ smudgeCommand);
if (safeWrite) {
- try (org.eclipse.jgit.util.TemporaryBuffer buffer =
- new org.eclipse.jgit.util.TemporaryBuffer.LocalFile(null)) {
- // Write to a buffer and copy to the file only if everything was fine.
- DirCacheCheckout.getContent(
- repo, path, checkoutMetadata, resultStreamLoader, null, buffer);
- InputStream bufIn = buffer.openInputStream();
- Files.copy(bufIn, file.toPath(), StandardCopyOption.REPLACE_EXISTING);
+ // Write to a buffer and copy to the file only if everything was
+ // fine.
+ TemporaryBuffer buffer = new TemporaryBuffer.LocalFile(null);
+ try {
+ try (TemporaryBuffer buf = buffer) {
+ DirCacheCheckout.getContent(repo, path, metadata,
+ resultStreamLoader, workingTreeOptions, buf);
+ }
+ try (InputStream bufIn = buffer.openInputStream()) {
+ Files.copy(bufIn, file.toPath(),
+ StandardCopyOption.REPLACE_EXISTING);
+ }
+ } finally {
+ buffer.destroy();
}
return;
}
- OutputStream outputStream = new FileOutputStream(file);
- DirCacheCheckout.getContent(
- repo, path, checkoutMetadata, resultStreamLoader, null, outputStream);
-
+ try (OutputStream outputStream = new FileOutputStream(file)) {
+ DirCacheCheckout.getContent(repo, path, metadata,
+ resultStreamLoader, workingTreeOptions, outputStream);
+ }
}
/**