From 2778bb2cc9bf7bdfb2ed7b3a99dd931d6d3fbbfa Mon Sep 17 00:00:00 2001 From: Han-Wen Nienhuys Date: Thu, 25 Aug 2022 19:37:35 +0200 Subject: [PATCH 1/4] WorkTreeUpdater: remove safeWrite option This was added in Ideaefd5178 to anticipate on writing files for ApplyCommand, but we are keeping WorkTreeUpdater private to the merge package for now. Change-Id: Ifa79dac245e60eb7a77eaea4cc1249222e347d38 --- .../org/eclipse/jgit/merge/ResolveMerger.java | 2 +- .../eclipse/jgit/util/WorkTreeUpdater.java | 25 ++----------------- 2 files changed, 3 insertions(+), 24 deletions(-) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java index d79f5d410..f4d19cb79 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java @@ -915,7 +915,7 @@ private File writeMergedFile(TemporaryBuffer rawMerged, StreamLoader contentLoader = WorkTreeUpdater.createStreamLoader(rawMerged::openInputStream, rawMerged.length()); workTreeUpdater.updateFileWithContent(contentLoader, - eol, tw.getSmudgeCommand(attributes), of.getPath(), of, false); + eol, tw.getSmudgeCommand(attributes), of.getPath(), of); return of; } 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 e5de2b4a7..d35efe3e3 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/WorkTreeUpdater.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/WorkTreeUpdater.java @@ -18,8 +18,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.nio.file.Files; -import java.nio.file.StandardCopyOption; import java.time.Instant; import java.util.HashMap; import java.util.LinkedList; @@ -611,37 +609,18 @@ public void close() throws IOException { * of the file to be updated * @param file * to be updated - * @param safeWrite - * whether the content should be written to a buffer first * @throws IOException * if the file cannot be updated */ public void updateFileWithContent(StreamLoader resultStreamLoader, EolStreamType streamType, String smudgeCommand, String path, - File file, boolean safeWrite) throws IOException { + File file) throws IOException { if (inCore) { return; } CheckoutMetadata metadata = new CheckoutMetadata(streamType, smudgeCommand); - if (safeWrite) { - // 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; - } + try (OutputStream outputStream = new FileOutputStream(file)) { DirCacheCheckout.getContent(repo, path, metadata, resultStreamLoader, workingTreeOptions, outputStream); From 6d2bcb6043c1f32dc7fd7029a29d671babf271cf Mon Sep 17 00:00:00 2001 From: Han-Wen Nienhuys Date: Tue, 30 Aug 2022 10:07:21 +0200 Subject: [PATCH 2/4] DirCacheCheckout#getContent: also take InputStream supplier This lets us use DirCacheCheckout for routines that want to write files in the worktree that aren't available as a git object. DirCacheCheckout#getContent takes a InputStream supplier rather than InputStream: if filtering fails with IOException, the data is placed unfiltered in the checkout. This means that the stream has to be read again, from the start. Use it in this way in ApplyCommand. This use is incorrect, though: the same InputStream is returned twice, so if the read to be retried, the stream will return 0 bytes. It doesn't really matter, because in either case, the SHA1 will not match up, and the patch fails. Change-Id: I2efa9a6da06806ff79b155032fe4b34be8fec09e --- .../org/eclipse/jgit/api/ApplyCommand.java | 6 +- .../jgit/dircache/DirCacheCheckout.java | 109 ++++++++++++++---- 2 files changed, 88 insertions(+), 27 deletions(-) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java index 64fba98b4..c955d7983 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java @@ -398,7 +398,7 @@ private void checkOid(ObjectId baseId, ObjectId id, ChangeType type, File f, } private void applyBinary(Repository repository, String path, File f, - FileHeader fh, WorkTreeUpdater.StreamSupplier loader, ObjectId id, + FileHeader fh, DirCacheCheckout.StreamSupplier loader, ObjectId id, CheckoutMetadata checkOut) throws PatchApplyException, IOException { if (!fh.getOldId().isComplete() || !fh.getNewId().isComplete()) { @@ -430,9 +430,7 @@ private void applyBinary(Repository repository, String path, File f, hunk.getBuffer(), start, length))))) { DirCacheCheckout.getContent(repository, path, checkOut, - WorkTreeUpdater.createStreamLoader(() -> inflated, - hunk.getSize()), - null, out); + () -> inflated, null, out); if (!fh.getNewId().toObjectId().equals(hash.toObjectId())) { throw new PatchApplyException(MessageFormat.format( JGitText.get().applyBinaryResultOidWrong, 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 2365c90d0..1fb81b71e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java @@ -21,6 +21,7 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.nio.file.StandardCopyOption; import java.text.MessageFormat; @@ -1605,6 +1606,60 @@ public static void getContent(Repository repo, String path, CheckoutMetadata checkoutMetadata, ObjectLoader ol, WorkingTreeOptions opt, OutputStream os) throws IOException { + getContent(repo, path, checkoutMetadata, ol::openStream, opt, os); + } + + + /** + * Something that can supply an {@link InputStream}. + * + * @since 6.3 + */ + public interface StreamSupplier { + + /** + * Loads the input stream. + * + * @return the loaded stream + * @throws IOException + * if any reading error occurs + */ + InputStream load() throws IOException; + } + + /** + * Return filtered content for blob contents. EOL handling and smudge-filter + * handling are applied in the same way as it would be done during a + * checkout. + * + * @param repo + * the repository + * @param path + * the path used to determine the correct filters for the object + * @param checkoutMetadata + * containing + * + * @param inputStream + * A supplier for the raw content of the object. Each call should + * yield a fresh stream of the same object. + * @param opt + * the working tree options where only 'core.autocrlf' is used + * for EOL handling if 'checkoutMetadata.eolStreamType' is not + * valid + * @param os + * the output stream the filtered content is written to. The + * caller is responsible to close the stream. + * @throws IOException + * @since 6.3 + */ + public static void getContent(Repository repo, String path, + CheckoutMetadata checkoutMetadata, StreamSupplier inputStream, + WorkingTreeOptions opt, OutputStream os) + throws IOException { EolStreamType nonNullEolStreamType; if (checkoutMetadata.eolStreamType != null) { nonNullEolStreamType = checkoutMetadata.eolStreamType; @@ -1618,21 +1673,23 @@ public static void getContent(Repository repo, String path, if (checkoutMetadata.smudgeFilterCommand != null) { if (FilterCommandRegistry .isRegistered(checkoutMetadata.smudgeFilterCommand)) { - runBuiltinFilterCommand(repo, checkoutMetadata, ol, + runBuiltinFilterCommand(repo, checkoutMetadata, inputStream, channel); } else { - runExternalFilterCommand(repo, path, checkoutMetadata, ol, + runExternalFilterCommand(repo, path, checkoutMetadata, inputStream, channel); } } else { - ol.copyTo(channel); + try (InputStream in = inputStream.load()) { + in.transferTo(channel); + } } } } // Run an external filter command private static void runExternalFilterCommand(Repository repo, String path, - CheckoutMetadata checkoutMetadata, ObjectLoader ol, + CheckoutMetadata checkoutMetadata, StreamSupplier inputStream, OutputStream channel) throws IOException { FS fs = repo.getFS(); ProcessBuilder filterProcessBuilder = fs.runInShell( @@ -1644,7 +1701,9 @@ private static void runExternalFilterCommand(Repository repo, String path, int rc; try { // TODO: wire correctly with AUTOCRLF - result = fs.execute(filterProcessBuilder, ol.openStream()); + try (InputStream in = inputStream.load()) { + result = fs.execute(filterProcessBuilder, in); + } rc = result.getRc(); if (rc == 0) { result.getStdout().writeTo(channel, @@ -1665,31 +1724,35 @@ private static void runExternalFilterCommand(Repository repo, String path, // Run a builtin filter command private static void runBuiltinFilterCommand(Repository repo, - CheckoutMetadata checkoutMetadata, ObjectLoader ol, + CheckoutMetadata checkoutMetadata, StreamSupplier inputStream, OutputStream channel) throws MissingObjectException, IOException { boolean isMandatory = repo.getConfig().getBoolean( ConfigConstants.CONFIG_FILTER_SECTION, ConfigConstants.CONFIG_SECTION_LFS, ConfigConstants.CONFIG_KEY_REQUIRED, false); FilterCommand command = null; - try { - command = FilterCommandRegistry.createFilterCommand( - checkoutMetadata.smudgeFilterCommand, repo, ol.openStream(), - channel); - } catch (IOException e) { - LOG.error(JGitText.get().failedToDetermineFilterDefinition, e); - if (!isMandatory) { - // In case an IOException occurred during creating of the - // command then proceed as if there would not have been a - // builtin filter (only if the filter is not mandatory). - ol.copyTo(channel); - } else { - throw e; + try (InputStream in = inputStream.load()) { + try { + command = FilterCommandRegistry.createFilterCommand( + checkoutMetadata.smudgeFilterCommand, repo, in, + channel); + } catch (IOException e) { + LOG.error(JGitText.get().failedToDetermineFilterDefinition, e); + if (!isMandatory) { + // In case an IOException occurred during creating of the + // command then proceed as if there would not have been a + // builtin filter (only if the filter is not mandatory). + try (InputStream again = inputStream.load()) { + again.transferTo(channel); + } + } else { + throw e; + } } - } - if (command != null) { - while (command.run() != -1) { - // loop as long as command.run() tells there is work to do + if (command != null) { + while (command.run() != -1) { + // loop as long as command.run() tells there is work to do + } } } } From 6ed4c074cadaa857400e24a23d80f76342732dfe Mon Sep 17 00:00:00 2001 From: Han-Wen Nienhuys Date: Tue, 30 Aug 2022 14:18:25 +0200 Subject: [PATCH 3/4] WorkTreeUpdater: use DirCacheCheckout#StreamSupplier This avoids having to introduce the StreamLoader bridging class. Change-Id: I98de155c458745236df24d6323eabed5061e7f8c --- .../org/eclipse/jgit/api/ApplyCommand.java | 8 +- .../org/eclipse/jgit/merge/ResolveMerger.java | 5 +- .../eclipse/jgit/util/WorkTreeUpdater.java | 133 ++---------------- 3 files changed, 16 insertions(+), 130 deletions(-) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java index c955d7983..e7f40d811 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java @@ -58,7 +58,6 @@ import org.eclipse.jgit.util.FileUtils; import org.eclipse.jgit.util.IO; import org.eclipse.jgit.util.RawParseUtils; -import org.eclipse.jgit.util.WorkTreeUpdater; import org.eclipse.jgit.util.StringUtils; import org.eclipse.jgit.util.TemporaryBuffer; import org.eclipse.jgit.util.TemporaryBuffer.LocalFile; @@ -461,8 +460,7 @@ private void applyBinary(Repository repository, String path, File f, SHA1InputStream hashed = new SHA1InputStream(hash, input)) { DirCacheCheckout.getContent(repository, path, checkOut, - WorkTreeUpdater.createStreamLoader(() -> hashed, finalSize), - null, out); + () -> hashed, null, out); if (!fh.getNewId().toObjectId() .equals(hash.toObjectId())) { throw new PatchApplyException(MessageFormat.format( @@ -630,9 +628,7 @@ && canApplyAt(hunkLines, newLines, 0)) { } try (OutputStream output = new FileOutputStream(f)) { DirCacheCheckout.getContent(repository, path, checkOut, - WorkTreeUpdater.createStreamLoader(buffer::openInputStream, - buffer.length()), - null, output); + buffer::openInputStream, null, output); } } finally { buffer.destroy(); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java index f4d19cb79..b134cdcf5 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java @@ -61,7 +61,6 @@ import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.LfsFactory; import org.eclipse.jgit.util.WorkTreeUpdater; -import org.eclipse.jgit.util.WorkTreeUpdater.StreamLoader; import org.eclipse.jgit.util.TemporaryBuffer; /** @@ -912,9 +911,7 @@ private File writeMergedFile(TemporaryBuffer rawMerged, if (!fs.exists(parentFolder)) { parentFolder.mkdirs(); } - StreamLoader contentLoader = WorkTreeUpdater.createStreamLoader(rawMerged::openInputStream, - rawMerged.length()); - workTreeUpdater.updateFileWithContent(contentLoader, + workTreeUpdater.updateFileWithContent(rawMerged::openInputStream, eol, tw.getSmudgeCommand(attributes), of.getPath(), of); return of; } 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 d35efe3e3..16cd7f890 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/WorkTreeUpdater.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/WorkTreeUpdater.java @@ -11,7 +11,6 @@ import static org.eclipse.jgit.lib.Constants.OBJ_BLOB; -import java.io.BufferedInputStream; import java.io.Closeable; import java.io.File; import java.io.FileOutputStream; @@ -34,22 +33,19 @@ import org.eclipse.jgit.dircache.DirCacheBuildIterator; import org.eclipse.jgit.dircache.DirCacheBuilder; import org.eclipse.jgit.dircache.DirCacheCheckout; +import org.eclipse.jgit.dircache.DirCacheCheckout.StreamSupplier; import org.eclipse.jgit.dircache.DirCacheCheckout.CheckoutMetadata; import org.eclipse.jgit.dircache.DirCacheEntry; import org.eclipse.jgit.errors.IndexWriteException; -import org.eclipse.jgit.errors.LargeObjectException; import org.eclipse.jgit.errors.NoWorkTreeException; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.ConfigConstants; -import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.CoreConfig.EolStreamType; import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectInserter; -import org.eclipse.jgit.lib.ObjectLoader; import org.eclipse.jgit.lib.ObjectReader; -import org.eclipse.jgit.lib.ObjectStream; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.treewalk.TreeWalk.OperationType; import org.eclipse.jgit.treewalk.WorkingTreeOptions; @@ -245,77 +241,6 @@ public static WorkTreeUpdater createInCoreWorkTreeUpdater(Repository repo, return new WorkTreeUpdater(repo, dirCache, oi); } - /** - * Something that can supply an {@link InputStream}. - */ - public interface StreamSupplier { - - /** - * Loads the input stream. - * - * @return the loaded stream - * @throws IOException - * if any reading error occurs - */ - InputStream load() throws IOException; - } - - /** - * We want to use DirCacheCheckout for its CR-LF and smudge filters, but DirCacheCheckout needs an - * ObjectLoader rather than InputStream. This class provides a bridge between the two. - */ - public static class StreamLoader extends ObjectLoader { - - private final StreamSupplier data; - - private final long size; - - private StreamLoader(StreamSupplier data, long length) { - this.data = data; - this.size = length; - } - - @Override - public int getType() { - return Constants.OBJ_BLOB; - } - - @Override - public long getSize() { - return size; - } - - @Override - public boolean isLarge() { - return true; - } - - @Override - public byte[] getCachedBytes() throws LargeObjectException { - throw new LargeObjectException(); - } - - @Override - public ObjectStream openStream() throws IOException { - return new ObjectStream.Filter(getType(), getSize(), - new BufferedInputStream(data.load())); - } - } - - /** - * Creates stream loader for the given supplier. - * - * @param supplier - * to wrap - * @param length - * of the supplied content - * @return the result stream loader - */ - public static StreamLoader createStreamLoader(StreamSupplier supplier, - long length) { - return new StreamLoader(supplier, length); - } - private static int getInCoreFileSizeLimit(Config config) { return config.getInt(ConfigConstants.CONFIG_MERGE_SECTION, ConfigConstants.CONFIG_KEY_IN_CORE_LIMIT, 10 << 20); @@ -599,8 +524,8 @@ public void close() throws IOException { /** * Updates the file in the checkout with the given content. * - * @param resultStreamLoader - * with the content to be updated + * @param inputStream + * the content to be updated * @param streamType * for parsing the content * @param smudgeCommand @@ -612,7 +537,7 @@ public void close() throws IOException { * @throws IOException * if the file cannot be updated */ - public void updateFileWithContent(StreamLoader resultStreamLoader, + public void updateFileWithContent(StreamSupplier inputStream, EolStreamType streamType, String smudgeCommand, String path, File file) throws IOException { if (inCore) { @@ -623,7 +548,7 @@ public void updateFileWithContent(StreamLoader resultStreamLoader, try (OutputStream outputStream = new FileOutputStream(file)) { DirCacheCheckout.getContent(repo, path, metadata, - resultStreamLoader, workingTreeOptions, outputStream); + inputStream, workingTreeOptions, outputStream); } } @@ -631,8 +556,8 @@ public void updateFileWithContent(StreamLoader resultStreamLoader, * Creates a path with the given content, and adds it to the specified stage * to the index builder. * - * @param inputStream - * with the content to be updated + * @param input + * the content to be updated * @param path * of the file to be updated * @param fileMode @@ -649,43 +574,12 @@ public void updateFileWithContent(StreamLoader resultStreamLoader, * @throws IOException * if inserting the content fails */ - public DirCacheEntry insertToIndex(InputStream inputStream, byte[] path, - FileMode fileMode, int entryStage, Instant lastModified, int len, - Attribute lfsAttribute) throws IOException { - StreamLoader contentLoader = createStreamLoader(() -> inputStream, len); - return insertToIndex(contentLoader, path, fileMode, entryStage, - lastModified, len, lfsAttribute); - } - - /** - * Creates a path with the given content, and adds it to the specified stage - * to the index builder. - * - * @param resultStreamLoader - * with the content to be updated - * @param path - * of the file to be updated - * @param fileMode - * of the modified file - * @param entryStage - * of the new entry - * @param lastModified - * instant of the modified file - * @param len - * of the content - * @param lfsAttribute - * for checking for LFS enablement - * @return the entry which was added to the index - * @throws IOException - * if inserting the content fails - */ - public DirCacheEntry insertToIndex(StreamLoader resultStreamLoader, + public DirCacheEntry insertToIndex(InputStream input, byte[] path, FileMode fileMode, int entryStage, Instant lastModified, int len, Attribute lfsAttribute) throws IOException { - return addExistingToIndex( - insertResult(resultStreamLoader, lfsAttribute), path, fileMode, - entryStage, lastModified, len); + return addExistingToIndex(insertResult(input, lfsAttribute, len), path, + fileMode, entryStage, lastModified, len); } /** @@ -713,16 +607,15 @@ public DirCacheEntry addExistingToIndex(ObjectId objectId, byte[] path, dce.setLastModified(lastModified); } dce.setLength(inCore ? 0 : len); - dce.setObjectId(objectId); builder.add(dce); return dce; } - private ObjectId insertResult(StreamLoader resultStreamLoader, - Attribute lfsAttribute) throws IOException { + private ObjectId insertResult(InputStream input, + Attribute lfsAttribute, long length) throws IOException { try (LfsInputStream is = LfsFactory.getInstance().applyCleanFilter(repo, - resultStreamLoader.data.load(), resultStreamLoader.size, + input, length, lfsAttribute)) { return inserter.insert(OBJ_BLOB, is.getLength(), is); } From 448052dc2e698b2e4e5d6dbca54be773aac687da Mon Sep 17 00:00:00 2001 From: Han-Wen Nienhuys Date: Tue, 30 Aug 2022 15:08:48 +0200 Subject: [PATCH 4/4] Move WorkTreeUpdater to merge package This avoids making it public with the associated costs for backward compatibility guarantees. Change-Id: I888f313f3854deace8d4cd92f354a6ef0d3b5460 --- .../src/org/eclipse/jgit/merge/ResolveMerger.java | 1 - .../org/eclipse/jgit/{util => merge}/WorkTreeUpdater.java | 7 +++---- 2 files changed, 3 insertions(+), 5 deletions(-) rename org.eclipse.jgit/src/org/eclipse/jgit/{util => merge}/WorkTreeUpdater.java (99%) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java index b134cdcf5..23f8e4a5d 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java @@ -60,7 +60,6 @@ import org.eclipse.jgit.treewalk.filter.TreeFilter; import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.LfsFactory; -import org.eclipse.jgit.util.WorkTreeUpdater; import org.eclipse.jgit.util.TemporaryBuffer; /** diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/WorkTreeUpdater.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/WorkTreeUpdater.java similarity index 99% rename from org.eclipse.jgit/src/org/eclipse/jgit/util/WorkTreeUpdater.java rename to org.eclipse.jgit/src/org/eclipse/jgit/merge/WorkTreeUpdater.java index 16cd7f890..1db9bc659 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/WorkTreeUpdater.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/WorkTreeUpdater.java @@ -7,7 +7,7 @@ * * SPDX-License-Identifier: BSD-3-Clause */ -package org.eclipse.jgit.util; +package org.eclipse.jgit.merge; import static org.eclipse.jgit.lib.Constants.OBJ_BLOB; @@ -49,6 +49,7 @@ import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.treewalk.TreeWalk.OperationType; import org.eclipse.jgit.treewalk.WorkingTreeOptions; +import org.eclipse.jgit.util.LfsFactory; import org.eclipse.jgit.util.LfsFactory.LfsInputStream; import org.eclipse.jgit.util.io.EolStreamTypeUtil; @@ -58,10 +59,8 @@ * You should use a single instance for all of your file changes. In case of an * error, make sure your instance is released, and initiate a new one if * necessary. - * - * @since 6.3 */ -public class WorkTreeUpdater implements Closeable { +class WorkTreeUpdater implements Closeable { /** * The result of writing the index changes.