Delete non empty directories before checkout a path
If the checkout path is currently a non-empty directory (and was a link or a regular file before), this directory will be removed before performing checkout, but only if the checkout path is specified. Bug: 474973 Change-Id: Ifc6c61592d9b54d26c66367163acdebea369145c Signed-off-by: Andrey Loskutov <loskutov@gmx.de>
This commit is contained in:
parent
227b78f087
commit
a406ebf401
|
@ -55,6 +55,7 @@
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
import org.eclipse.jgit.lib.Repository;
|
import org.eclipse.jgit.lib.Repository;
|
||||||
import org.eclipse.jgit.util.FileUtils;
|
import org.eclipse.jgit.util.FileUtils;
|
||||||
|
@ -240,4 +241,10 @@ public static void deleteTrashFile(final Repository db,
|
||||||
FileUtils.delete(path);
|
FileUtils.delete(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Path writeLink(Repository db, String link,
|
||||||
|
String target) throws Exception {
|
||||||
|
return FileUtils.createSymLink(new File(db.getWorkTree(), link),
|
||||||
|
target);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,7 @@
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.eclipse.jgit.api.Git;
|
import org.eclipse.jgit.api.Git;
|
||||||
|
@ -107,6 +108,11 @@ protected File writeTrashFile(final String name, final String data)
|
||||||
return JGitTestUtil.writeTrashFile(db, name, data);
|
return JGitTestUtil.writeTrashFile(db, name, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Path writeLink(final String link, final String target)
|
||||||
|
throws Exception {
|
||||||
|
return JGitTestUtil.writeLink(db, link, target);
|
||||||
|
}
|
||||||
|
|
||||||
protected File writeTrashFile(final String subdir, final String name,
|
protected File writeTrashFile(final String subdir, final String name,
|
||||||
final String data)
|
final String data)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
|
|
@ -923,6 +923,299 @@ public void testCheckoutOutChanges() throws IOException {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCheckoutChangeLinkToEmptyDir() throws Exception {
|
||||||
|
String fname = "was_file";
|
||||||
|
Git git = Git.wrap(db);
|
||||||
|
|
||||||
|
// Add a file
|
||||||
|
writeTrashFile(fname, "a");
|
||||||
|
git.add().addFilepattern(fname).call();
|
||||||
|
|
||||||
|
// Add a link to file
|
||||||
|
String linkName = "link";
|
||||||
|
File link = writeLink(linkName, fname).toFile();
|
||||||
|
git.add().addFilepattern(linkName).call();
|
||||||
|
git.commit().setMessage("Added file and link").call();
|
||||||
|
|
||||||
|
assertWorkDir(mkmap(linkName, "a", fname, "a"));
|
||||||
|
|
||||||
|
// replace link with empty directory
|
||||||
|
FileUtils.delete(link);
|
||||||
|
FileUtils.mkdir(link);
|
||||||
|
assertTrue("Link must be a directory now", link.isDirectory());
|
||||||
|
|
||||||
|
// modify file
|
||||||
|
writeTrashFile(fname, "b");
|
||||||
|
assertWorkDir(mkmap(fname, "b", linkName, "/"));
|
||||||
|
|
||||||
|
// revert both paths to HEAD state
|
||||||
|
git.checkout().setStartPoint(Constants.HEAD)
|
||||||
|
.addPath(fname).addPath(linkName).call();
|
||||||
|
|
||||||
|
assertWorkDir(mkmap(fname, "a", linkName, "a"));
|
||||||
|
|
||||||
|
Status st = git.status().call();
|
||||||
|
assertTrue(st.isClean());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCheckoutChangeLinkToEmptyDirs() throws Exception {
|
||||||
|
String fname = "was_file";
|
||||||
|
Git git = Git.wrap(db);
|
||||||
|
|
||||||
|
// Add a file
|
||||||
|
writeTrashFile(fname, "a");
|
||||||
|
git.add().addFilepattern(fname).call();
|
||||||
|
|
||||||
|
// Add a link to file
|
||||||
|
String linkName = "link";
|
||||||
|
File link = writeLink(linkName, fname).toFile();
|
||||||
|
git.add().addFilepattern(linkName).call();
|
||||||
|
git.commit().setMessage("Added file and link").call();
|
||||||
|
|
||||||
|
assertWorkDir(mkmap(linkName, "a", fname, "a"));
|
||||||
|
|
||||||
|
// replace link with directory containing only directories, no files
|
||||||
|
FileUtils.delete(link);
|
||||||
|
FileUtils.mkdirs(new File(link, "dummyDir"));
|
||||||
|
assertTrue("Link must be a directory now", link.isDirectory());
|
||||||
|
|
||||||
|
assertFalse("Must not delete non empty directory", link.delete());
|
||||||
|
|
||||||
|
// modify file
|
||||||
|
writeTrashFile(fname, "b");
|
||||||
|
assertWorkDir(mkmap(fname, "b", linkName + "/dummyDir", "/"));
|
||||||
|
|
||||||
|
// revert both paths to HEAD state
|
||||||
|
git.checkout().setStartPoint(Constants.HEAD)
|
||||||
|
.addPath(fname).addPath(linkName).call();
|
||||||
|
|
||||||
|
assertWorkDir(mkmap(fname, "a", linkName, "a"));
|
||||||
|
|
||||||
|
Status st = git.status().call();
|
||||||
|
assertTrue(st.isClean());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCheckoutChangeLinkToNonEmptyDirs() throws Exception {
|
||||||
|
String fname = "file";
|
||||||
|
Git git = Git.wrap(db);
|
||||||
|
|
||||||
|
// Add a file
|
||||||
|
writeTrashFile(fname, "a");
|
||||||
|
git.add().addFilepattern(fname).call();
|
||||||
|
|
||||||
|
// Add a link to file
|
||||||
|
String linkName = "link";
|
||||||
|
File link = writeLink(linkName, fname).toFile();
|
||||||
|
git.add().addFilepattern(linkName).call();
|
||||||
|
git.commit().setMessage("Added file and link").call();
|
||||||
|
|
||||||
|
assertWorkDir(mkmap(linkName, "a", fname, "a"));
|
||||||
|
|
||||||
|
// replace link with directory containing only directories, no files
|
||||||
|
FileUtils.delete(link);
|
||||||
|
|
||||||
|
// create but do not add a file in the new directory to the index
|
||||||
|
writeTrashFile(linkName + "/dir1", "file1", "c");
|
||||||
|
|
||||||
|
// create but do not add a file in the new directory to the index
|
||||||
|
writeTrashFile(linkName + "/dir2", "file2", "d");
|
||||||
|
|
||||||
|
assertTrue("File must be a directory now", link.isDirectory());
|
||||||
|
assertFalse("Must not delete non empty directory", link.delete());
|
||||||
|
|
||||||
|
// 2 extra files are created
|
||||||
|
assertWorkDir(mkmap(fname, "a", linkName + "/dir1/file1", "c",
|
||||||
|
linkName + "/dir2/file2", "d"));
|
||||||
|
|
||||||
|
// revert path to HEAD state
|
||||||
|
git.checkout().setStartPoint(Constants.HEAD).addPath(linkName).call();
|
||||||
|
|
||||||
|
// expect only the one added to the index
|
||||||
|
assertWorkDir(mkmap(linkName, "a", fname, "a"));
|
||||||
|
|
||||||
|
Status st = git.status().call();
|
||||||
|
assertTrue(st.isClean());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCheckoutChangeLinkToNonEmptyDirsAndNewIndexEntry()
|
||||||
|
throws Exception {
|
||||||
|
String fname = "file";
|
||||||
|
Git git = Git.wrap(db);
|
||||||
|
|
||||||
|
// Add a file
|
||||||
|
writeTrashFile(fname, "a");
|
||||||
|
git.add().addFilepattern(fname).call();
|
||||||
|
|
||||||
|
// Add a link to file
|
||||||
|
String linkName = "link";
|
||||||
|
File link = writeLink(linkName, fname).toFile();
|
||||||
|
git.add().addFilepattern(linkName).call();
|
||||||
|
git.commit().setMessage("Added file and link").call();
|
||||||
|
|
||||||
|
assertWorkDir(mkmap(linkName, "a", fname, "a"));
|
||||||
|
|
||||||
|
// replace link with directory containing only directories, no files
|
||||||
|
FileUtils.delete(link);
|
||||||
|
|
||||||
|
// create and add a file in the new directory to the index
|
||||||
|
writeTrashFile(linkName + "/dir1", "file1", "c");
|
||||||
|
git.add().addFilepattern(linkName + "/dir1/file1").call();
|
||||||
|
|
||||||
|
// create but do not add a file in the new directory to the index
|
||||||
|
writeTrashFile(linkName + "/dir2", "file2", "d");
|
||||||
|
|
||||||
|
assertTrue("File must be a directory now", link.isDirectory());
|
||||||
|
assertFalse("Must not delete non empty directory", link.delete());
|
||||||
|
|
||||||
|
// 2 extra files are created
|
||||||
|
assertWorkDir(mkmap(fname, "a", linkName + "/dir1/file1", "c",
|
||||||
|
linkName + "/dir2/file2", "d"));
|
||||||
|
|
||||||
|
// revert path to HEAD state
|
||||||
|
git.checkout().setStartPoint(Constants.HEAD).addPath(linkName).call();
|
||||||
|
|
||||||
|
// original file and link
|
||||||
|
assertWorkDir(mkmap(linkName, "a", fname, "a"));
|
||||||
|
|
||||||
|
Status st = git.status().call();
|
||||||
|
assertFalse(st.isClean());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCheckoutChangeFileToEmptyDir() throws Exception {
|
||||||
|
String fname = "was_file";
|
||||||
|
Git git = Git.wrap(db);
|
||||||
|
|
||||||
|
// Add a file
|
||||||
|
File file = writeTrashFile(fname, "a");
|
||||||
|
git.add().addFilepattern(fname).call();
|
||||||
|
git.commit().setMessage("Added file").call();
|
||||||
|
|
||||||
|
// replace file with empty directory
|
||||||
|
FileUtils.delete(file);
|
||||||
|
FileUtils.mkdir(file);
|
||||||
|
assertTrue("File must be a directory now", file.isDirectory());
|
||||||
|
|
||||||
|
assertWorkDir(mkmap(fname, "/"));
|
||||||
|
|
||||||
|
// revert path to HEAD state
|
||||||
|
git.checkout().setStartPoint(Constants.HEAD).addPath(fname).call();
|
||||||
|
|
||||||
|
assertWorkDir(mkmap(fname, "a"));
|
||||||
|
|
||||||
|
Status st = git.status().call();
|
||||||
|
assertTrue(st.isClean());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCheckoutChangeFileToEmptyDirs() throws Exception {
|
||||||
|
String fname = "was_file";
|
||||||
|
Git git = Git.wrap(db);
|
||||||
|
|
||||||
|
// Add a file
|
||||||
|
File file = writeTrashFile(fname, "a");
|
||||||
|
git.add().addFilepattern(fname).call();
|
||||||
|
git.commit().setMessage("Added file").call();
|
||||||
|
|
||||||
|
// replace file with directory containing only directories, no files
|
||||||
|
FileUtils.delete(file);
|
||||||
|
FileUtils.mkdirs(new File(file, "dummyDir"));
|
||||||
|
assertTrue("File must be a directory now", file.isDirectory());
|
||||||
|
assertFalse("Must not delete non empty directory", file.delete());
|
||||||
|
|
||||||
|
assertWorkDir(mkmap(fname + "/dummyDir", "/"));
|
||||||
|
|
||||||
|
// revert path to HEAD state
|
||||||
|
git.checkout().setStartPoint(Constants.HEAD).addPath(fname).call();
|
||||||
|
|
||||||
|
assertWorkDir(mkmap(fname, "a"));
|
||||||
|
|
||||||
|
Status st = git.status().call();
|
||||||
|
assertTrue(st.isClean());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCheckoutChangeFileToNonEmptyDirs() throws Exception {
|
||||||
|
String fname = "was_file";
|
||||||
|
Git git = Git.wrap(db);
|
||||||
|
|
||||||
|
// Add a file
|
||||||
|
File file = writeTrashFile(fname, "a");
|
||||||
|
git.add().addFilepattern(fname).call();
|
||||||
|
git.commit().setMessage("Added file").call();
|
||||||
|
|
||||||
|
assertWorkDir(mkmap(fname, "a"));
|
||||||
|
|
||||||
|
// replace file with directory containing only directories, no files
|
||||||
|
FileUtils.delete(file);
|
||||||
|
|
||||||
|
// create but do not add a file in the new directory to the index
|
||||||
|
writeTrashFile(fname + "/dir1", "file1", "c");
|
||||||
|
|
||||||
|
// create but do not add a file in the new directory to the index
|
||||||
|
writeTrashFile(fname + "/dir2", "file2", "d");
|
||||||
|
|
||||||
|
assertTrue("File must be a directory now", file.isDirectory());
|
||||||
|
assertFalse("Must not delete non empty directory", file.delete());
|
||||||
|
|
||||||
|
// 2 extra files are created
|
||||||
|
assertWorkDir(
|
||||||
|
mkmap(fname + "/dir1/file1", "c", fname + "/dir2/file2", "d"));
|
||||||
|
|
||||||
|
// revert path to HEAD state
|
||||||
|
git.checkout().setStartPoint(Constants.HEAD).addPath(fname).call();
|
||||||
|
|
||||||
|
// expect only the one added to the index
|
||||||
|
assertWorkDir(mkmap(fname, "a"));
|
||||||
|
|
||||||
|
Status st = git.status().call();
|
||||||
|
assertTrue(st.isClean());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCheckoutChangeFileToNonEmptyDirsAndNewIndexEntry()
|
||||||
|
throws Exception {
|
||||||
|
String fname = "was_file";
|
||||||
|
Git git = Git.wrap(db);
|
||||||
|
|
||||||
|
// Add a file
|
||||||
|
File file = writeTrashFile(fname, "a");
|
||||||
|
git.add().addFilepattern(fname).call();
|
||||||
|
git.commit().setMessage("Added file").call();
|
||||||
|
|
||||||
|
assertWorkDir(mkmap(fname, "a"));
|
||||||
|
|
||||||
|
// replace file with directory containing only directories, no files
|
||||||
|
FileUtils.delete(file);
|
||||||
|
|
||||||
|
// create and add a file in the new directory to the index
|
||||||
|
writeTrashFile(fname + "/dir", "file1", "c");
|
||||||
|
git.add().addFilepattern(fname + "/dir/file1").call();
|
||||||
|
|
||||||
|
// create but do not add a file in the new directory to the index
|
||||||
|
writeTrashFile(fname + "/dir", "file2", "d");
|
||||||
|
|
||||||
|
assertTrue("File must be a directory now", file.isDirectory());
|
||||||
|
assertFalse("Must not delete non empty directory", file.delete());
|
||||||
|
|
||||||
|
// 2 extra files are created
|
||||||
|
assertWorkDir(
|
||||||
|
mkmap(fname + "/dir/file1", "c", fname + "/dir/file2", "d"));
|
||||||
|
|
||||||
|
// revert path to HEAD state
|
||||||
|
git.checkout().setStartPoint(Constants.HEAD).addPath(fname).call();
|
||||||
|
assertWorkDir(mkmap(fname, "a"));
|
||||||
|
|
||||||
|
Status st = git.status().call();
|
||||||
|
assertFalse(st.isClean());
|
||||||
|
assertEquals(1, st.getAdded().size());
|
||||||
|
assertTrue(st.getAdded().contains(fname + "/dir/file1"));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCheckoutOutChangesAutoCRLFfalse() throws IOException {
|
public void testCheckoutOutChangesAutoCRLFfalse() throws IOException {
|
||||||
setupCase(mk("foo"), mkmap("foo/bar", "foo\nbar"), mk("foo"));
|
setupCase(mk("foo"), mkmap("foo/bar", "foo\nbar"), mk("foo"));
|
||||||
|
@ -1023,6 +1316,102 @@ public void testOverwriteUntrackedIgnoredFile() throws IOException,
|
||||||
assertTrue(git.status().call().isClean());
|
assertTrue(git.status().call().isClean());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOverwriteUntrackedFileModeChange()
|
||||||
|
throws IOException, GitAPIException {
|
||||||
|
String fname = "file.txt";
|
||||||
|
Git git = Git.wrap(db);
|
||||||
|
|
||||||
|
// Add a file
|
||||||
|
File file = writeTrashFile(fname, "a");
|
||||||
|
git.add().addFilepattern(fname).call();
|
||||||
|
git.commit().setMessage("create file").call();
|
||||||
|
assertWorkDir(mkmap(fname, "a"));
|
||||||
|
|
||||||
|
// Create branch
|
||||||
|
git.branchCreate().setName("side").call();
|
||||||
|
|
||||||
|
// Switch branches
|
||||||
|
git.checkout().setName("side").call();
|
||||||
|
|
||||||
|
// replace file with directory containing files
|
||||||
|
FileUtils.delete(file);
|
||||||
|
|
||||||
|
// create and add a file in the new directory to the index
|
||||||
|
writeTrashFile(fname + "/dir1", "file1", "c");
|
||||||
|
git.add().addFilepattern(fname + "/dir1/file1").call();
|
||||||
|
|
||||||
|
// create but do not add a file in the new directory to the index
|
||||||
|
writeTrashFile(fname + "/dir2", "file2", "d");
|
||||||
|
|
||||||
|
assertTrue("File must be a directory now", file.isDirectory());
|
||||||
|
assertFalse("Must not delete non empty directory", file.delete());
|
||||||
|
|
||||||
|
// 2 extra files are created
|
||||||
|
assertWorkDir(
|
||||||
|
mkmap(fname + "/dir1/file1", "c", fname + "/dir2/file2", "d"));
|
||||||
|
|
||||||
|
try {
|
||||||
|
git.checkout().setName("master").call();
|
||||||
|
fail("did not throw exception");
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 2 extra files are still there
|
||||||
|
assertWorkDir(mkmap(fname + "/dir1/file1", "c",
|
||||||
|
fname + "/dir2/file2", "d"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOverwriteUntrackedLinkModeChange()
|
||||||
|
throws Exception {
|
||||||
|
String fname = "file.txt";
|
||||||
|
Git git = Git.wrap(db);
|
||||||
|
|
||||||
|
// Add a file
|
||||||
|
writeTrashFile(fname, "a");
|
||||||
|
git.add().addFilepattern(fname).call();
|
||||||
|
|
||||||
|
// Add a link to file
|
||||||
|
String linkName = "link";
|
||||||
|
File link = writeLink(linkName, fname).toFile();
|
||||||
|
git.add().addFilepattern(linkName).call();
|
||||||
|
git.commit().setMessage("Added file and link").call();
|
||||||
|
|
||||||
|
assertWorkDir(mkmap(linkName, "a", fname, "a"));
|
||||||
|
|
||||||
|
// Create branch
|
||||||
|
git.branchCreate().setName("side").call();
|
||||||
|
|
||||||
|
// Switch branches
|
||||||
|
git.checkout().setName("side").call();
|
||||||
|
|
||||||
|
// replace link with directory containing files
|
||||||
|
FileUtils.delete(link);
|
||||||
|
|
||||||
|
// create and add a file in the new directory to the index
|
||||||
|
writeTrashFile(linkName + "/dir1", "file1", "c");
|
||||||
|
git.add().addFilepattern(linkName + "/dir1/file1").call();
|
||||||
|
|
||||||
|
// create but do not add a file in the new directory to the index
|
||||||
|
writeTrashFile(linkName + "/dir2", "file2", "d");
|
||||||
|
|
||||||
|
assertTrue("Link must be a directory now", link.isDirectory());
|
||||||
|
assertFalse("Must not delete non empty directory", link.delete());
|
||||||
|
|
||||||
|
// 2 extra files are created
|
||||||
|
assertWorkDir(mkmap(fname, "a", linkName + "/dir1/file1", "c",
|
||||||
|
linkName + "/dir2/file2", "d"));
|
||||||
|
|
||||||
|
try {
|
||||||
|
git.checkout().setName("master").call();
|
||||||
|
fail("did not throw exception");
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 2 extra files are still there
|
||||||
|
assertWorkDir(mkmap(fname, "a", linkName + "/dir1/file1", "c",
|
||||||
|
linkName + "/dir2/file2", "d"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFileModeChangeWithNoContentChangeUpdate() throws Exception {
|
public void testFileModeChangeWithNoContentChangeUpdate() throws Exception {
|
||||||
if (!FS.DETECTED.supportsExecute())
|
if (!FS.DETECTED.supportsExecute())
|
||||||
|
@ -1219,7 +1608,8 @@ public void testFileModeChangeAndContentChangeNoConflict() throws Exception {
|
||||||
assertNotNull(git.checkout().setName(Constants.MASTER).call());
|
assertNotNull(git.checkout().setName(Constants.MASTER).call());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void assertWorkDir(HashMap<String, String> i) throws CorruptObjectException,
|
public void assertWorkDir(Map<String, String> i)
|
||||||
|
throws CorruptObjectException,
|
||||||
IOException {
|
IOException {
|
||||||
TreeWalk walk = new TreeWalk(db);
|
TreeWalk walk = new TreeWalk(db);
|
||||||
walk.setRecursive(false);
|
walk.setRecursive(false);
|
||||||
|
|
|
@ -21,4 +21,12 @@
|
||||||
</message_arguments>
|
</message_arguments>
|
||||||
</filter>
|
</filter>
|
||||||
</resource>
|
</resource>
|
||||||
|
<resource path="src/org/eclipse/jgit/util/FileUtils.java" type="org.eclipse.jgit.util.FileUtils">
|
||||||
|
<filter id="338792546">
|
||||||
|
<message_arguments>
|
||||||
|
<message_argument value="org.eclipse.jgit.util.FileUtils"/>
|
||||||
|
<message_argument value="createSymLink(File, String)"/>
|
||||||
|
</message_arguments>
|
||||||
|
</filter>
|
||||||
|
</resource>
|
||||||
</component>
|
</component>
|
||||||
|
|
|
@ -457,7 +457,7 @@ public void apply(DirCacheEntry ent) {
|
||||||
|
|
||||||
private void checkoutPath(DirCacheEntry entry, ObjectReader reader) {
|
private void checkoutPath(DirCacheEntry entry, ObjectReader reader) {
|
||||||
try {
|
try {
|
||||||
DirCacheCheckout.checkoutEntry(repo, entry, reader);
|
DirCacheCheckout.checkoutEntry(repo, entry, reader, true);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new JGitInternalException(MessageFormat.format(
|
throw new JGitInternalException(MessageFormat.format(
|
||||||
JGitText.get().checkoutConflictWithFile,
|
JGitText.get().checkoutConflictWithFile,
|
||||||
|
|
|
@ -357,7 +357,7 @@ private void resetUntracked(RevTree tree) throws CheckoutConflictException,
|
||||||
|
|
||||||
private void checkoutPath(DirCacheEntry entry, ObjectReader reader) {
|
private void checkoutPath(DirCacheEntry entry, ObjectReader reader) {
|
||||||
try {
|
try {
|
||||||
DirCacheCheckout.checkoutEntry(repo, entry, reader);
|
DirCacheCheckout.checkoutEntry(repo, entry, reader, true);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new JGitInternalException(MessageFormat.format(
|
throw new JGitInternalException(MessageFormat.format(
|
||||||
JGitText.get().checkoutConflictWithFile,
|
JGitText.get().checkoutConflictWithFile,
|
||||||
|
|
|
@ -447,7 +447,7 @@ private boolean doCheckout() throws CorruptObjectException, IOException,
|
||||||
for (String path : updated.keySet()) {
|
for (String path : updated.keySet()) {
|
||||||
DirCacheEntry entry = dc.getEntry(path);
|
DirCacheEntry entry = dc.getEntry(path);
|
||||||
if (!FileMode.GITLINK.equals(entry.getRawMode()))
|
if (!FileMode.GITLINK.equals(entry.getRawMode()))
|
||||||
checkoutEntry(repo, entry, objectReader);
|
checkoutEntry(repo, entry, objectReader, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// commit the index builder - a new index is persisted
|
// commit the index builder - a new index is persisted
|
||||||
|
@ -1127,6 +1127,13 @@ private boolean isModifiedSubtree_IndexTree(String path, ObjectId tree)
|
||||||
* final filename.
|
* final filename.
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
|
* <b>Note:</b> if the entry path on local file system exists as a non-empty
|
||||||
|
* directory, and the target entry type is a link or file, the checkout will
|
||||||
|
* fail with {@link IOException} since existing non-empty directory 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
|
* TODO: this method works directly on File IO, we may need another
|
||||||
* abstraction (like WorkingTreeIterator). This way we could tell e.g.
|
* abstraction (like WorkingTreeIterator). This way we could tell e.g.
|
||||||
* Eclipse that Files in the workspace got changed
|
* Eclipse that Files in the workspace got changed
|
||||||
|
@ -1143,6 +1150,42 @@ private boolean isModifiedSubtree_IndexTree(String path, ObjectId tree)
|
||||||
*/
|
*/
|
||||||
public static void checkoutEntry(Repository repo, DirCacheEntry entry,
|
public static void checkoutEntry(Repository repo, DirCacheEntry entry,
|
||||||
ObjectReader or) throws IOException {
|
ObjectReader or) throws IOException {
|
||||||
|
checkoutEntry(repo, entry, or, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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>
|
||||||
|
*
|
||||||
|
* <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
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
* @since 4.2
|
||||||
|
*/
|
||||||
|
public static void checkoutEntry(Repository repo, DirCacheEntry entry,
|
||||||
|
ObjectReader or, boolean deleteRecursive) throws IOException {
|
||||||
ObjectLoader ol = or.open(entry.getObjectId());
|
ObjectLoader ol = or.open(entry.getObjectId());
|
||||||
File f = new File(repo.getWorkTree(), entry.getPathString());
|
File f = new File(repo.getWorkTree(), entry.getPathString());
|
||||||
File parentDir = f.getParentFile();
|
File parentDir = f.getParentFile();
|
||||||
|
@ -1153,6 +1196,9 @@ public static void checkoutEntry(Repository repo, DirCacheEntry entry,
|
||||||
&& opt.getSymLinks() == SymLinks.TRUE) {
|
&& opt.getSymLinks() == SymLinks.TRUE) {
|
||||||
byte[] bytes = ol.getBytes();
|
byte[] bytes = ol.getBytes();
|
||||||
String target = RawParseUtils.decode(bytes);
|
String target = RawParseUtils.decode(bytes);
|
||||||
|
if (deleteRecursive && f.isDirectory()) {
|
||||||
|
FileUtils.delete(f, FileUtils.RECURSIVE);
|
||||||
|
}
|
||||||
fs.createSymLink(f, target);
|
fs.createSymLink(f, target);
|
||||||
entry.setLength(bytes.length);
|
entry.setLength(bytes.length);
|
||||||
entry.setLastModified(fs.lastModified(f));
|
entry.setLastModified(fs.lastModified(f));
|
||||||
|
@ -1183,11 +1229,18 @@ public static void checkoutEntry(Repository repo, DirCacheEntry entry,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
if (deleteRecursive && f.isDirectory()) {
|
||||||
|
FileUtils.delete(f, FileUtils.RECURSIVE);
|
||||||
|
}
|
||||||
FileUtils.rename(tmpFile, f);
|
FileUtils.rename(tmpFile, f);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new IOException(MessageFormat.format(
|
throw new IOException(MessageFormat.format(
|
||||||
JGitText.get().renameFileFailed, tmpFile.getPath(),
|
JGitText.get().renameFileFailed, tmpFile.getPath(),
|
||||||
f.getPath()));
|
f.getPath()));
|
||||||
|
} finally {
|
||||||
|
if (tmpFile.exists()) {
|
||||||
|
FileUtils.delete(tmpFile);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
entry.setLastModified(f.lastModified());
|
entry.setLastModified(f.lastModified());
|
||||||
}
|
}
|
||||||
|
|
|
@ -399,20 +399,25 @@ public static void createNewFile(File f) throws IOException {
|
||||||
*
|
*
|
||||||
* @param path
|
* @param path
|
||||||
* @param target
|
* @param target
|
||||||
|
* @return path to the created link
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
* @since 3.0
|
* @since 4.2
|
||||||
*/
|
*/
|
||||||
public static void createSymLink(File path, String target)
|
public static Path createSymLink(File path, String target)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
Path nioPath = path.toPath();
|
Path nioPath = path.toPath();
|
||||||
if (Files.exists(nioPath, LinkOption.NOFOLLOW_LINKS)) {
|
if (Files.exists(nioPath, LinkOption.NOFOLLOW_LINKS)) {
|
||||||
Files.delete(nioPath);
|
if (Files.isRegularFile(nioPath)) {
|
||||||
|
delete(path);
|
||||||
|
} else {
|
||||||
|
delete(path, EMPTY_DIRECTORIES_ONLY | RECURSIVE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (SystemReader.getInstance().isWindows()) {
|
if (SystemReader.getInstance().isWindows()) {
|
||||||
target = target.replace('/', '\\');
|
target = target.replace('/', '\\');
|
||||||
}
|
}
|
||||||
Path nioTarget = new File(target).toPath();
|
Path nioTarget = new File(target).toPath();
|
||||||
Files.createSymbolicLink(nioPath, nioTarget);
|
return Files.createSymbolicLink(nioPath, nioTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue