|
|
|
@ -60,6 +60,7 @@ import org.eclipse.jgit.errors.MissingObjectException;
|
|
|
|
|
import org.eclipse.jgit.lib.FileMode; |
|
|
|
|
import org.eclipse.jgit.lib.ObjectId; |
|
|
|
|
import org.eclipse.jgit.lib.ObjectLoader; |
|
|
|
|
import org.eclipse.jgit.lib.ObjectReader; |
|
|
|
|
import org.eclipse.jgit.lib.Repository; |
|
|
|
|
import org.eclipse.jgit.treewalk.AbstractTreeIterator; |
|
|
|
|
import org.eclipse.jgit.treewalk.CanonicalTreeParser; |
|
|
|
@ -386,64 +387,68 @@ public class DirCacheCheckout {
|
|
|
|
|
MissingObjectException, IncorrectObjectTypeException, |
|
|
|
|
CheckoutConflictException, IndexWriteException { |
|
|
|
|
toBeDeleted.clear(); |
|
|
|
|
if (headCommitTree != null) |
|
|
|
|
preScanTwoTrees(); |
|
|
|
|
else |
|
|
|
|
prescanOneTree(); |
|
|
|
|
|
|
|
|
|
if (!conflicts.isEmpty()) { |
|
|
|
|
if (failOnConflict) { |
|
|
|
|
dc.unlock(); |
|
|
|
|
throw new CheckoutConflictException(conflicts.toArray(new String[conflicts.size()])); |
|
|
|
|
} else |
|
|
|
|
cleanUpConflicts(); |
|
|
|
|
} |
|
|
|
|
ObjectReader objectReader = repo.getObjectDatabase().newReader(); |
|
|
|
|
try { |
|
|
|
|
if (headCommitTree != null) |
|
|
|
|
preScanTwoTrees(); |
|
|
|
|
else |
|
|
|
|
prescanOneTree(); |
|
|
|
|
|
|
|
|
|
// update our index
|
|
|
|
|
builder.finish(); |
|
|
|
|
|
|
|
|
|
File file=null; |
|
|
|
|
String last = ""; |
|
|
|
|
// when deleting files process them in the opposite order as they have
|
|
|
|
|
// been reported. This ensures the files are deleted before we delete
|
|
|
|
|
// their parent folders
|
|
|
|
|
for (int i = removed.size() - 1; i >= 0; i--) { |
|
|
|
|
String r = removed.get(i); |
|
|
|
|
file = new File(repo.getWorkTree(), r); |
|
|
|
|
if (!file.delete() && file.exists()) |
|
|
|
|
toBeDeleted.add(r); |
|
|
|
|
else { |
|
|
|
|
if (!isSamePrefix(r, last)) |
|
|
|
|
removeEmptyParents(new File(repo.getWorkTree(), last)); |
|
|
|
|
last = r; |
|
|
|
|
if (!conflicts.isEmpty()) { |
|
|
|
|
if (failOnConflict) { |
|
|
|
|
dc.unlock(); |
|
|
|
|
throw new CheckoutConflictException(conflicts.toArray(new String[conflicts.size()])); |
|
|
|
|
} else |
|
|
|
|
cleanUpConflicts(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (file != null) |
|
|
|
|
removeEmptyParents(file); |
|
|
|
|
|
|
|
|
|
for (String path : updated.keySet()) { |
|
|
|
|
// ... create/overwrite this file ...
|
|
|
|
|
file = new File(repo.getWorkTree(), path); |
|
|
|
|
if (!file.getParentFile().mkdirs()) { |
|
|
|
|
// ignore
|
|
|
|
|
// update our index
|
|
|
|
|
builder.finish(); |
|
|
|
|
|
|
|
|
|
File file = null; |
|
|
|
|
String last = ""; |
|
|
|
|
// when deleting files process them in the opposite order as they have
|
|
|
|
|
// been reported. This ensures the files are deleted before we delete
|
|
|
|
|
// their parent folders
|
|
|
|
|
for (int i = removed.size() - 1; i >= 0; i--) { |
|
|
|
|
String r = removed.get(i); |
|
|
|
|
file = new File(repo.getWorkTree(), r); |
|
|
|
|
if (!file.delete() && file.exists()) |
|
|
|
|
toBeDeleted.add(r); |
|
|
|
|
else { |
|
|
|
|
if (!isSamePrefix(r, last)) |
|
|
|
|
removeEmptyParents(new File(repo.getWorkTree(), last)); |
|
|
|
|
last = r; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (file != null) |
|
|
|
|
removeEmptyParents(file); |
|
|
|
|
|
|
|
|
|
for (String path : updated.keySet()) { |
|
|
|
|
// ... create/overwrite this file ...
|
|
|
|
|
file = new File(repo.getWorkTree(), path); |
|
|
|
|
if (!file.getParentFile().mkdirs()) { |
|
|
|
|
// ignore
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
DirCacheEntry entry = dc.getEntry(path); |
|
|
|
|
|
|
|
|
|
// submodules are handled with separate operations
|
|
|
|
|
if (FileMode.GITLINK.equals(entry.getRawMode())) |
|
|
|
|
continue; |
|
|
|
|
DirCacheEntry entry = dc.getEntry(path); |
|
|
|
|
|
|
|
|
|
checkoutEntry(repo, file, entry); |
|
|
|
|
} |
|
|
|
|
// submodules are handled with separate operations
|
|
|
|
|
if (FileMode.GITLINK.equals(entry.getRawMode())) |
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
checkoutEntry(repo, file, entry, objectReader); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// commit the index builder - a new index is persisted
|
|
|
|
|
if (!builder.commit()) { |
|
|
|
|
dc.unlock(); |
|
|
|
|
throw new IndexWriteException(); |
|
|
|
|
// commit the index builder - a new index is persisted
|
|
|
|
|
if (!builder.commit()) { |
|
|
|
|
dc.unlock(); |
|
|
|
|
throw new IndexWriteException(); |
|
|
|
|
} |
|
|
|
|
} finally { |
|
|
|
|
objectReader.release(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return toBeDeleted.size() == 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -844,26 +849,65 @@ public class DirCacheCheckout {
|
|
|
|
|
return 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. Use this method only for checkout of a single entry. |
|
|
|
|
* Otherwise use |
|
|
|
|
* {@code checkoutEntry(Repository, File f, DirCacheEntry, ObjectReader)} |
|
|
|
|
* instead which allows to reuse one {@code ObjectReader} for multiple |
|
|
|
|
* entries. |
|
|
|
|
* |
|
|
|
|
* <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 repository |
|
|
|
|
* @param f |
|
|
|
|
* the file to be modified. The parent directory for this file |
|
|
|
|
* has to exist already |
|
|
|
|
* @param entry |
|
|
|
|
* the entry containing new mode and content |
|
|
|
|
* @throws IOException |
|
|
|
|
*/ |
|
|
|
|
public static void checkoutEntry(final Repository repository, File f, |
|
|
|
|
DirCacheEntry entry) throws IOException { |
|
|
|
|
ObjectReader or = repository.newObjectReader(); |
|
|
|
|
try { |
|
|
|
|
checkoutEntry(repository, f, entry, repository.newObjectReader()); |
|
|
|
|
} finally { |
|
|
|
|
or.release(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 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> |
|
|
|
|
* 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 |
|
|
|
|
* @param f |
|
|
|
|
* the file to be modified. The parent directory for this file |
|
|
|
|
* has to exist already |
|
|
|
|
* @param entry |
|
|
|
|
* the entry containing new mode and content |
|
|
|
|
* @param or |
|
|
|
|
* object reader to use for checkout |
|
|
|
|
* @throws IOException |
|
|
|
|
*/ |
|
|
|
|
public static void checkoutEntry(final Repository repo, File f, |
|
|
|
|
DirCacheEntry entry) throws IOException { |
|
|
|
|
ObjectLoader ol = repo.open(entry.getObjectId()); |
|
|
|
|
DirCacheEntry entry, ObjectReader or) throws IOException { |
|
|
|
|
ObjectLoader ol = or.open(entry.getObjectId()); |
|
|
|
|
File parentDir = f.getParentFile(); |
|
|
|
|
File tmpFile = File.createTempFile("._" + f.getName(), null, parentDir); |
|
|
|
|
FileOutputStream channel = new FileOutputStream(tmpFile); |
|
|
|
|