diff options
18 files changed, 629 insertions, 249 deletions
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/StatusTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/StatusTest.java index 13f8c319c1..73ae598a8c 100644 --- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/StatusTest.java +++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/StatusTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, François Rey <eclipse.org_@_francois_._rey_._name> + * Copyright (C) 2012, 2013 François Rey <eclipse.org_@_francois_._rey_._name> * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available @@ -191,7 +191,7 @@ public class StatusTest extends CLIRepositoryTestCase { "# On branch master", // "# Unmerged paths:", // "# ", // - "# \tunmerged", // + "# \tboth modified: unmerged", // "# ", // "# Untracked files:", // "# ", // @@ -205,7 +205,7 @@ public class StatusTest extends CLIRepositoryTestCase { "# Not currently on any branch.", // "# Unmerged paths:", // "# ", // - "# \tunmerged", // + "# \tboth modified: unmerged", // "# ", // "# Untracked files:", // "# ", // diff --git a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/CLIText.properties b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/CLIText.properties index 43b6f17768..3d6952bc93 100644 --- a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/CLIText.properties +++ b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/CLIText.properties @@ -7,7 +7,6 @@ N=N alreadyOnBranch=Already on ''{0}'' alreadyUpToDate=Already up-to-date. -archiveEntryModeIgnored=warning: mode of {0} ignored authorInfo=Author: {0} <{1}> averageMSPerRead=average {0} ms/read branchAlreadyExists=A branch named ''{0}'' already exists. @@ -48,6 +47,7 @@ deletedRemoteBranch=Deleted remote branch {0} doesNotExist={0} does not exist dontOverwriteLocalChanges=error: Your local changes to the following file would be overwritten by merge: everythingUpToDate=Everything up-to-date +exceptionCaughtDuringExecutionOfArchiveCommand=Exception caught during execution of archive command expectedNumberOfbytes=Expected {0} bytes. exporting=Exporting {0} failedToCommitIndex=failed to commit index @@ -153,9 +153,17 @@ serviceNotSupported=Service ''{0}'' not supported skippingObject=skipping {0} {1} statusFileListFormat=\t%1$s statusFileListFormatWithPrefix=\t%1$-11s %2$s +statusFileListFormatUnmerged=\t%1$-20s%2$s statusModified=modified: statusNewFile=new file: statusRemoved=deleted: +statusBothDeleted=both deleted: +statusAddedByUs=added by us: +statusDeletedByThem=deleted by them: +statusAddedByThem=added by them: +statusDeletedByUs=deleted by us: +statusBothAdded=both added: +statusBothModified=both modified: switchedToNewBranch=Switched to a new branch ''{0}'' switchedToBranch=Switched to branch ''{0}'' tagAlreadyExists=tag ''{0}'' already exists diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Archive.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Archive.java index 963528d106..5685aa4267 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Archive.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Archive.java @@ -43,144 +43,33 @@ package org.eclipse.jgit.pgm; -import java.lang.String; -import java.lang.System; -import java.io.IOException; -import java.io.OutputStream; -import java.util.EnumMap; -import java.util.Map; -import java.text.MessageFormat; - -import org.apache.commons.compress.archivers.ArchiveOutputStream; -import org.apache.commons.compress.archivers.tar.TarArchiveEntry; -import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; -import org.apache.commons.compress.archivers.tar.TarConstants; -import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; -import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; -import org.eclipse.jgit.lib.FileMode; -import org.eclipse.jgit.lib.MutableObjectId; -import org.eclipse.jgit.lib.ObjectLoader; -import org.eclipse.jgit.lib.ObjectReader; +import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.pgm.CLIText; import org.eclipse.jgit.pgm.TextBuiltin; -import org.eclipse.jgit.treewalk.AbstractTreeIterator; -import org.eclipse.jgit.treewalk.TreeWalk; +import org.eclipse.jgit.pgm.archive.ArchiveCommand; import org.kohsuke.args4j.Argument; import org.kohsuke.args4j.Option; @Command(common = true, usage = "usage_archive") class Archive extends TextBuiltin { @Argument(index = 0, metaVar = "metaVar_treeish") - private AbstractTreeIterator tree; + private ObjectId tree; @Option(name = "--format", metaVar = "metaVar_archiveFormat", usage = "usage_archiveFormat") - private Format format = Format.ZIP; + private ArchiveCommand.Format format = ArchiveCommand.Format.ZIP; @Override protected void run() throws Exception { - final TreeWalk walk = new TreeWalk(db); - final ObjectReader reader = walk.getObjectReader(); - final MutableObjectId idBuf = new MutableObjectId(); - final Archiver fmt = formats.get(format); - final ArchiveOutputStream outa = fmt.createArchiveOutputStream(outs); - if (tree == null) throw die(CLIText.get().treeIsRequired); - walk.reset(); - walk.addTree(tree); - walk.setRecursive(true); - while (walk.next()) { - final String name = walk.getPathString(); - final FileMode mode = walk.getFileMode(0); - - if (mode == FileMode.TREE) - // ZIP entries for directories are optional. - // Leave them out, mimicking "git archive". - continue; - - walk.getObjectId(idBuf, 0); - fmt.putEntry(name, mode, reader.open(idBuf), outa); + final ArchiveCommand cmd = new ArchiveCommand(db); + try { + cmd.setTree(tree) + .setFormat(format) + .setOutputStream(outs).call(); + } finally { + cmd.release(); } - - outa.close(); - } - - static private void warnArchiveEntryModeIgnored(String name) { - System.err.println(MessageFormat.format( // - CLIText.get().archiveEntryModeIgnored, // - name)); - } - - public enum Format { - ZIP, - TAR - } - - private static interface Archiver { - ArchiveOutputStream createArchiveOutputStream(OutputStream s); - void putEntry(String path, FileMode mode, // - ObjectLoader loader, ArchiveOutputStream out) // - throws IOException; - } - - private static final Map<Format, Archiver> formats; - static { - Map<Format, Archiver> fmts = new EnumMap<Format, Archiver>(Format.class); - fmts.put(Format.ZIP, new Archiver() { - public ArchiveOutputStream createArchiveOutputStream(OutputStream s) { - return new ZipArchiveOutputStream(s); - } - - public void putEntry(String path, FileMode mode, // - ObjectLoader loader, ArchiveOutputStream out) // - throws IOException { - final ZipArchiveEntry entry = new ZipArchiveEntry(path); - - if (mode == FileMode.REGULAR_FILE) { - // ok - } else if (mode == FileMode.EXECUTABLE_FILE - || mode == FileMode.SYMLINK) { - entry.setUnixMode(mode.getBits()); - } else { - warnArchiveEntryModeIgnored(path); - } - entry.setSize(loader.getSize()); - out.putArchiveEntry(entry); - loader.copyTo(out); - out.closeArchiveEntry(); - } - }); - fmts.put(Format.TAR, new Archiver() { - public ArchiveOutputStream createArchiveOutputStream(OutputStream s) { - return new TarArchiveOutputStream(s); - } - - public void putEntry(String path, FileMode mode, // - ObjectLoader loader, ArchiveOutputStream out) // - throws IOException { - if (mode == FileMode.SYMLINK) { - final TarArchiveEntry entry = new TarArchiveEntry( // - path, TarConstants.LF_SYMLINK); - entry.setLinkName(new String( // - loader.getCachedBytes(100), "UTF-8")); //$NON-NLS-1$ - out.putArchiveEntry(entry); - out.closeArchiveEntry(); - return; - } - - final TarArchiveEntry entry = new TarArchiveEntry(path); - if (mode == FileMode.REGULAR_FILE || - mode == FileMode.EXECUTABLE_FILE) - entry.setMode(mode.getBits()); - else - warnArchiveEntryModeIgnored(path); - entry.setSize(loader.getSize()); - out.putArchiveEntry(entry); - loader.copyTo(out); - out.closeArchiveEntry(); - } - }); - formats = fmts; } } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CLIText.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CLIText.java index 1f14fa272b..c6f913c681 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CLIText.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CLIText.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010, 2012 Sasa Zivkov <sasa.zivkov@sap.com> + * Copyright (C) 2010, 2013 Sasa Zivkov <sasa.zivkov@sap.com> * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available @@ -76,7 +76,6 @@ public class CLIText extends TranslationBundle { // @formatter:off /***/ public String alreadyOnBranch; /***/ public String alreadyUpToDate; - /***/ public String archiveEntryModeIgnored; /***/ public String authorInfo; /***/ public String averageMSPerRead; /***/ public String branchAlreadyExists; @@ -117,6 +116,7 @@ public class CLIText extends TranslationBundle { /***/ public String doesNotExist; /***/ public String dontOverwriteLocalChanges; /***/ public String everythingUpToDate; + /***/ public String exceptionCaughtDuringExecutionOfArchiveCommand; /***/ public String expectedNumberOfbytes; /***/ public String exporting; /***/ public String failedToCommitIndex; @@ -216,9 +216,17 @@ public class CLIText extends TranslationBundle { /***/ public String skippingObject; /***/ public String statusFileListFormat; /***/ public String statusFileListFormatWithPrefix; + /***/ public String statusFileListFormatUnmerged; /***/ public String statusModified; /***/ public String statusNewFile; /***/ public String statusRemoved; + /***/ public String statusBothDeleted; + /***/ public String statusAddedByUs; + /***/ public String statusDeletedByThem; + /***/ public String statusAddedByThem; + /***/ public String statusDeletedByUs; + /***/ public String statusBothAdded; + /***/ public String statusBothModified; /***/ public String switchedToNewBranch; /***/ public String switchedToBranch; /***/ public String tagAlreadyExists; diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java index 4d2308e214..c1b635ca9f 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, François Rey <eclipse.org_@_francois_._rey_._name> + * Copyright (C) 2011, 2013 François Rey <eclipse.org_@_francois_._rey_._name> * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available @@ -47,10 +47,13 @@ import java.io.IOException; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; +import java.util.Map; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.IndexDiff.StageState; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; @@ -63,6 +66,8 @@ class Status extends TextBuiltin { protected final String statusFileListFormatWithPrefix = CLIText.get().statusFileListFormatWithPrefix; + protected final String statusFileListFormatUnmerged = CLIText.get().statusFileListFormatUnmerged; + @Override protected void run() throws Exception { // Print current branch name @@ -82,7 +87,8 @@ class Status extends TextBuiltin { Collection<String> modified = status.getModified(); Collection<String> missing = status.getMissing(); Collection<String> untracked = status.getUntracked(); - Collection<String> unmerged = status.getConflicting(); + Map<String, StageState> unmergedStates = status + .getConflictingStageState(); Collection<String> toBeCommitted = new ArrayList<String>(added); toBeCommitted.addAll(changed); toBeCommitted.addAll(removed); @@ -106,12 +112,12 @@ class Status extends TextBuiltin { modified, missing, null); firstHeader = false; } - int nbUnmerged = unmerged.size(); + int nbUnmerged = unmergedStates.size(); if (nbUnmerged > 0) { if (!firstHeader) printSectionHeader(""); //$NON-NLS-1$ printSectionHeader(CLIText.get().unmergedPaths); - printList(unmerged); + printUnmerged(unmergedStates); firstHeader = false; } int nbUntracked = untracked.size(); @@ -168,4 +174,40 @@ class Status extends TextBuiltin { } return list.size(); } + + private void printUnmerged(Map<String, StageState> unmergedStates) + throws IOException { + List<String> paths = new ArrayList<String>(unmergedStates.keySet()); + Collections.sort(paths); + for (String path : paths) { + StageState state = unmergedStates.get(path); + String stateDescription = getStageStateDescription(state); + outw.println(CLIText.formatLine(String.format( + statusFileListFormatUnmerged, stateDescription, path))); + outw.flush(); + } + } + + private static String getStageStateDescription(StageState stageState) { + CLIText text = CLIText.get(); + switch (stageState) { + case BOTH_DELETED: + return text.statusBothDeleted; + case ADDED_BY_US: + return text.statusAddedByUs; + case DELETED_BY_THEM: + return text.statusDeletedByThem; + case ADDED_BY_THEM: + return text.statusAddedByThem; + case DELETED_BY_US: + return text.statusDeletedByUs; + case BOTH_ADDED: + return text.statusBothAdded; + case BOTH_MODIFIED: + return text.statusBothModified; + default: + throw new IllegalArgumentException("Unknown StageState: " //$NON-NLS-1$ + + stageState); + } + } } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/archive/ArchiveCommand.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/archive/ArchiveCommand.java new file mode 100644 index 0000000000..7c2e7c0993 --- /dev/null +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/archive/ArchiveCommand.java @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2012 Google Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.eclipse.jgit.pgm.archive; + +import java.lang.String; +import java.io.IOException; +import java.io.OutputStream; +import java.util.EnumMap; +import java.util.Map; +import java.text.MessageFormat; + +import org.apache.commons.compress.archivers.ArchiveOutputStream; +import org.apache.commons.compress.archivers.tar.TarArchiveEntry; +import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; +import org.apache.commons.compress.archivers.tar.TarConstants; +import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; +import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; +import org.eclipse.jgit.api.GitCommand; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.api.errors.JGitInternalException; +import org.eclipse.jgit.lib.FileMode; +import org.eclipse.jgit.lib.MutableObjectId; +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.pgm.CLIText; +import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.treewalk.TreeWalk; + +/** + * Create an archive of files from a named tree. + * <p> + * Examples (<code>git</code> is a {@link Git} instance): + * <p> + * Create a tarball from HEAD: + * + * <pre> + * cmd = new ArchiveCommand(git.getRepository()); + * try { + * cmd.setTree(db.resolve("HEAD")) + * .setOutputStream(out).call(); + * } finally { + * cmd.release(); + * } + * </pre> + * <p> + * Create a ZIP file from master: + * + * <pre> + * try { + * cmd.setTree(db.resolve("master")) + * .setFormat(ArchiveCommand.Format.ZIP) + * .setOutputStream(out).call(); + * } finally { + * cmd.release(); + * } + * </pre> + * + * @see <a href="http://git-htmldocs.googlecode.com/git/git-archive.html" + * >Git documentation about archive</a> + */ +public class ArchiveCommand extends GitCommand<OutputStream> { + /** + * Available archival formats (corresponding to values for + * the --format= option) + */ + public static enum Format { + ZIP, + TAR + } + + private static interface Archiver { + ArchiveOutputStream createArchiveOutputStream(OutputStream s); + void putEntry(String path, FileMode mode, // + ObjectLoader loader, ArchiveOutputStream out) // + throws IOException; + } + + private static final Map<Format, Archiver> formats; + + static { + Map<Format, Archiver> fmts = new EnumMap<Format, Archiver>(Format.class); + fmts.put(Format.ZIP, new Archiver() { + public ArchiveOutputStream createArchiveOutputStream(OutputStream s) { + return new ZipArchiveOutputStream(s); + } + + public void putEntry(String path, FileMode mode, // + ObjectLoader loader, ArchiveOutputStream out) // + throws IOException { + final ZipArchiveEntry entry = new ZipArchiveEntry(path); + + if (mode == FileMode.REGULAR_FILE) { + // ok + } else if (mode == FileMode.EXECUTABLE_FILE + || mode == FileMode.SYMLINK) { + entry.setUnixMode(mode.getBits()); + } else { + // TODO(jrn): Let the caller know the tree contained + // an entry with unsupported mode (e.g., a submodule). + } + entry.setSize(loader.getSize()); + out.putArchiveEntry(entry); + loader.copyTo(out); + out.closeArchiveEntry(); + } + }); + fmts.put(Format.TAR, new Archiver() { + public ArchiveOutputStream createArchiveOutputStream(OutputStream s) { + return new TarArchiveOutputStream(s); + } + + public void putEntry(String path, FileMode mode, // + ObjectLoader loader, ArchiveOutputStream out) // + throws IOException { + if (mode == FileMode.SYMLINK) { + final TarArchiveEntry entry = new TarArchiveEntry( // + path, TarConstants.LF_SYMLINK); + entry.setLinkName(new String( // + loader.getCachedBytes(100), "UTF-8")); //$NON-NLS-1$ + out.putArchiveEntry(entry); + out.closeArchiveEntry(); + return; + } + + final TarArchiveEntry entry = new TarArchiveEntry(path); + if (mode == FileMode.REGULAR_FILE || + mode == FileMode.EXECUTABLE_FILE) { + entry.setMode(mode.getBits()); + } else { + // TODO(jrn): Let the caller know the tree contained + // an entry with unsupported mode (e.g., a submodule). + } + entry.setSize(loader.getSize()); + out.putArchiveEntry(entry); + loader.copyTo(out); + out.closeArchiveEntry(); + } + }); + formats = fmts; + } + + private OutputStream out; + private TreeWalk walk; + private Format format = Format.TAR; + + /** + * @param repo + */ + public ArchiveCommand(Repository repo) { + super(repo); + walk = new TreeWalk(repo); + } + + /** + * Release any resources used by the internal ObjectReader. + * <p> + * This does not close the output stream set with setOutputStream, which + * belongs to the caller. + */ + public void release() { + walk.release(); + } + + /** + * @return the stream to which the archive has been written + */ + @Override + public OutputStream call() throws GitAPIException { + final MutableObjectId idBuf = new MutableObjectId(); + final Archiver fmt = formats.get(format); + final ArchiveOutputStream outa = fmt.createArchiveOutputStream(out); + final ObjectReader reader = walk.getObjectReader(); + + try { + try { + walk.setRecursive(true); + while (walk.next()) { + final String name = walk.getPathString(); + final FileMode mode = walk.getFileMode(0); + + if (mode == FileMode.TREE) + // ZIP entries for directories are optional. + // Leave them out, mimicking "git archive". + continue; + + walk.getObjectId(idBuf, 0); + fmt.putEntry(name, mode, reader.open(idBuf), outa); + } + } finally { + outa.close(); + } + } catch (IOException e) { + // TODO(jrn): Throw finer-grained errors. + throw new JGitInternalException( + CLIText.get().exceptionCaughtDuringExecutionOfArchiveCommand, e); + } + + return out; + } + + /** + * @param tree + * the tag, commit, or tree object to produce an archive for + * @return this + */ + public ArchiveCommand setTree(ObjectId tree) throws IOException { + final RevWalk rw = new RevWalk(walk.getObjectReader()); + walk.reset(rw.parseTree(tree)); + return this; + } + + /** + * @param out + * the stream to which to write the archive + * @return this + */ + public ArchiveCommand setOutputStream(OutputStream out) { + this.out = out; + return this; + } + + /** + * @param fmt + * archive format (e.g., Format.TAR) + * @return this + */ + public ArchiveCommand setFormat(Format fmt) { + this.format = fmt; + return this; + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java index 6040dfed78..51ba5f13ea 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java @@ -2,6 +2,7 @@ * Copyright (C) 2007, Dave Watson <dwatson@mimvista.com> * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com> * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> + * Copyright (C) 2013, Robin Stocker <robin@nibor.org> * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available @@ -46,6 +47,7 @@ package org.eclipse.jgit.lib; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.io.File; @@ -61,10 +63,12 @@ import org.eclipse.jgit.api.MergeResult; import org.eclipse.jgit.api.MergeResult.MergeStatus; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.dircache.DirCache; +import org.eclipse.jgit.dircache.DirCacheBuilder; import org.eclipse.jgit.dircache.DirCacheEditor; import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit; import org.eclipse.jgit.dircache.DirCacheEntry; import org.eclipse.jgit.junit.RepositoryTestCase; +import org.eclipse.jgit.lib.IndexDiff.StageState; import org.eclipse.jgit.merge.MergeStrategy; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.treewalk.FileTreeIterator; @@ -212,6 +216,8 @@ public class IndexDiffTest extends RepositoryTestCase { assertEquals("[]", diff.getMissing().toString()); assertEquals("[]", diff.getModified().toString()); assertEquals("[a]", diff.getConflicting().toString()); + assertEquals(StageState.BOTH_MODIFIED, + diff.getConflictingStageStates().get("a")); assertEquals(Collections.EMPTY_SET, diff.getUntrackedFolders()); } @@ -251,6 +257,8 @@ public class IndexDiffTest extends RepositoryTestCase { assertEquals("[]", diff.getMissing().toString()); assertEquals("[]", diff.getModified().toString()); assertEquals("[a]", diff.getConflicting().toString()); + assertEquals(StageState.DELETED_BY_THEM, + diff.getConflictingStageStates().get("a")); assertEquals(Collections.EMPTY_SET, diff.getUntrackedFolders()); } @@ -500,6 +508,46 @@ public class IndexDiffTest extends RepositoryTestCase { assertEquals(Collections.EMPTY_SET, diff.getUntrackedFolders()); } + @Test + public void testStageState() throws IOException { + final int base = DirCacheEntry.STAGE_1; + final int ours = DirCacheEntry.STAGE_2; + final int theirs = DirCacheEntry.STAGE_3; + verifyStageState(StageState.BOTH_DELETED, base); + verifyStageState(StageState.DELETED_BY_THEM, ours, base); + verifyStageState(StageState.DELETED_BY_US, base, theirs); + verifyStageState(StageState.BOTH_MODIFIED, base, ours, theirs); + verifyStageState(StageState.ADDED_BY_US, ours); + verifyStageState(StageState.BOTH_ADDED, ours, theirs); + verifyStageState(StageState.ADDED_BY_THEM, theirs); + + assertTrue(StageState.BOTH_DELETED.hasBase()); + assertFalse(StageState.BOTH_DELETED.hasOurs()); + assertFalse(StageState.BOTH_DELETED.hasTheirs()); + assertFalse(StageState.BOTH_ADDED.hasBase()); + assertTrue(StageState.BOTH_ADDED.hasOurs()); + assertTrue(StageState.BOTH_ADDED.hasTheirs()); + } + + private void verifyStageState(StageState expected, int... stages) + throws IOException { + DirCacheBuilder builder = db.lockDirCache().builder(); + for (int stage : stages) { + DirCacheEntry entry = createEntry("a", FileMode.REGULAR_FILE, + stage, "content"); + builder.add(entry); + } + builder.commit(); + + IndexDiff diff = new IndexDiff(db, Constants.HEAD, + new FileTreeIterator(db)); + diff.diff(); + + assertEquals( + "Conflict for entries in stages " + Arrays.toString(stages), + expected, diff.getConflictingStageStates().get("a")); + } + private void removeFromIndex(String path) throws IOException { final DirCache dirc = db.lockDirCache(); final DirCacheEditor edit = dirc.editor(); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtilTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtilTest.java index f6f6753c75..3cd01453a1 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtilTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtilTest.java @@ -119,91 +119,6 @@ public class FileUtilTest { } @Test - public void testDeleteRecursiveEmpty() throws IOException { - File f1 = new File(trash, "test/test/a"); - File f2 = new File(trash, "test/a"); - File d1 = new File(trash, "test"); - File d2 = new File(trash, "test/test"); - File d3 = new File(trash, "test/b"); - FileUtils.mkdirs(f1.getParentFile()); - FileUtils.createNewFile(f2); - FileUtils.createNewFile(f1); - FileUtils.mkdirs(d3); - - // Cannot delete hierarchy since files exist - try { - FileUtils.delete(d1, FileUtils.EMPTY_DIRECTORIES_ONLY); - fail("delete should fail"); - } catch (IOException e1) { - try { - FileUtils.delete(d1, FileUtils.EMPTY_DIRECTORIES_ONLY|FileUtils.RECURSIVE); - fail("delete should fail"); - } catch (IOException e2) { - // Everything still there - assertTrue(f1.exists()); - assertTrue(f2.exists()); - assertTrue(d1.exists()); - assertTrue(d2.exists()); - assertTrue(d3.exists()); - } - } - - // setup: delete files, only directories left - assertTrue(f1.delete()); - assertTrue(f2.delete()); - - // Shall not delete hierarchy without recursive - try { - FileUtils.delete(d1, FileUtils.EMPTY_DIRECTORIES_ONLY); - fail("delete should fail"); - } catch (IOException e2) { - // Everything still there - assertTrue(d1.exists()); - assertTrue(d2.exists()); - assertTrue(d3.exists()); - } - - // Now delete the empty hierarchy - FileUtils.delete(d2, FileUtils.EMPTY_DIRECTORIES_ONLY - | FileUtils.RECURSIVE); - assertFalse(d2.exists()); - - // Will fail to delete non-existing without SKIP_MISSING - try { - FileUtils.delete(d2, FileUtils.EMPTY_DIRECTORIES_ONLY); - fail("Cannot delete non-existent entity"); - } catch (IOException e) { - // ok - } - - // ..with SKIP_MISSING there is no exception - FileUtils.delete(d2, FileUtils.EMPTY_DIRECTORIES_ONLY - | FileUtils.SKIP_MISSING); - FileUtils.delete(d2, FileUtils.EMPTY_DIRECTORIES_ONLY - | FileUtils.RECURSIVE | FileUtils.SKIP_MISSING); - - // essentially the same, using IGNORE_ERRORS - FileUtils.delete(d2, FileUtils.EMPTY_DIRECTORIES_ONLY - | FileUtils.IGNORE_ERRORS); - FileUtils.delete(d2, FileUtils.EMPTY_DIRECTORIES_ONLY - | FileUtils.RECURSIVE | FileUtils.IGNORE_ERRORS); - } - - @Test - public void testDeleteRecursiveEmptyDirectoriesOnlyButIsFile() - throws IOException { - File f1 = new File(trash, "test/test/a"); - FileUtils.mkdirs(f1.getParentFile()); - FileUtils.createNewFile(f1); - try { - FileUtils.delete(f1, FileUtils.EMPTY_DIRECTORIES_ONLY); - fail("delete should fail"); - } catch (IOException e) { - assertTrue(f1.exists()); - } - } - - @Test public void testMkdir() throws IOException { File d = new File(trash, "test"); FileUtils.mkdir(d); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/Status.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/Status.java index cb2ae6bf01..e840c2f608 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/Status.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/Status.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, Christian Halstrick <christian.halstrick@sap.com> + * Copyright (C) 2011, 2013 Christian Halstrick <christian.halstrick@sap.com> * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available @@ -43,9 +43,11 @@ package org.eclipse.jgit.api; import java.util.Collections; +import java.util.Map; import java.util.Set; import org.eclipse.jgit.lib.IndexDiff; +import org.eclipse.jgit.lib.IndexDiff.StageState; /** * A class telling where the working-tree, the index and the current HEAD differ @@ -153,6 +155,14 @@ public class Status { } /** + * @return a map from conflicting path to its {@link StageState}. + * @since 3.0 + */ + public Map<String, StageState> getConflictingStageState() { + return Collections.unmodifiableMap(diff.getConflictingStageStates()); + } + + /** * @return set of files and folders that are ignored and not in the index. */ public Set<String> getIgnoredNotInIndex() { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/TagCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/TagCommand.java index 1784acd79b..3b1fe88409 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/TagCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/TagCommand.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010, Chris Aniszczyk <caniszczyk@gmail.com> + * Copyright (C) 2010, 2013 Chris Aniszczyk <caniszczyk@gmail.com> * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available @@ -66,9 +66,18 @@ import org.eclipse.jgit.revwalk.RevObject; import org.eclipse.jgit.revwalk.RevWalk; /** - * A class used to execute a {@code Tag} command. It has setters for all - * supported options and arguments of this command and a {@link #call()} method - * to finally execute the command. + * Create/update an annotated tag object. + * <p> + * Examples (<code>git</code> is a {@link Git} instance): + * <p> + * Create a new annotated tag for the current commit: + * + * <pre> + * git.tag().setName("v1.0").setMessage("First stable release").call(); + * </pre> + * <p> + * Use {@link Repository#updateRef(String)} to create a lightweight tag (just a + * named reference to a commit). * * @see <a href="http://www.kernel.org/pub/software/scm/git/docs/git-tag.html" * >Git documentation about Tag</a> diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffConfig.java index 13874004d5..b1cbb914d8 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffConfig.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffConfig.java @@ -48,6 +48,7 @@ import java.text.MessageFormat; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.Config.SectionParser; +import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.util.StringUtils; /** Keeps track of diff related configuration options. */ @@ -78,10 +79,12 @@ public class DiffConfig { private final int renameLimit; private DiffConfig(final Config rc) { - noPrefix = rc.getBoolean("diff", "noprefix", false); //$NON-NLS-1$ //$NON-NLS-2$ - renameDetectionType = parseRenameDetectionType(rc.getString("diff", //$NON-NLS-1$ - null, "renames")); //$NON-NLS-1$ - renameLimit = rc.getInt("diff", "renamelimit", 200); //$NON-NLS-1$ //$NON-NLS-2$ + noPrefix = rc.getBoolean(ConfigConstants.CONFIG_DIFF_SECTION, + ConfigConstants.CONFIG_KEY_NOPREFIX, false); + renameDetectionType = parseRenameDetectionType(rc.getString( + ConfigConstants.CONFIG_DIFF_SECTION, null, ConfigConstants.CONFIG_KEY_RENAMES)); + renameLimit = rc.getInt(ConfigConstants.CONFIG_DIFF_SECTION, + ConfigConstants.CONFIG_KEY_RENAMELIMIT, 200); } /** @return true if the prefix "a/" and "b/" should be suppressed. */ @@ -108,16 +111,21 @@ public class DiffConfig { final String renameString) { if (renameString == null) return RenameDetectionType.FALSE; - else if (StringUtils.equalsIgnoreCase("copy", renameString) //$NON-NLS-1$ - || StringUtils.equalsIgnoreCase("copies", renameString)) //$NON-NLS-1$ + else if (StringUtils.equalsIgnoreCase( + ConfigConstants.CONFIG_RENAMELIMIT_COPY, renameString) + || StringUtils + .equalsIgnoreCase( + ConfigConstants.CONFIG_RENAMELIMIT_COPIES, + renameString)) return RenameDetectionType.COPY; else { final Boolean renameBoolean = StringUtils .toBooleanOrNull(renameString); if (renameBoolean == null) throw new IllegalArgumentException(MessageFormat.format( - JGitText.get().enumValueNotSupported2, "diff", //$NON-NLS-1$ - "renames", renameString)); //$NON-NLS-1$ + JGitText.get().enumValueNotSupported2, + ConfigConstants.CONFIG_DIFF_SECTION, + ConfigConstants.CONFIG_KEY_RENAMES, renameString)); else if (renameBoolean.booleanValue()) return RenameDetectionType.TRUE; else diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java index fc0e06a700..3ff4eefb1c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java @@ -195,4 +195,34 @@ public class ConfigConstants { * @since 3.0 */ public static final String CONFIG_KEY_CHECKSTAT = "checkstat"; + + /** + * The "renamelimit" key in the "diff section" + * @since 3.0 + */ + public static final String CONFIG_KEY_RENAMELIMIT = "renamelimit"; + + /** + * The "noprefix" key in the "diff section" + * @since 3.0 + */ + public static final String CONFIG_KEY_NOPREFIX = "noprefix"; + + /** + * A "renamelimit" value in the "diff section" + * @since 3.0 + */ + public static final String CONFIG_RENAMELIMIT_COPY = "copy"; + + /** + * A "renamelimit" value in the "diff section" + * @since 3.0 + */ + public static final String CONFIG_RENAMELIMIT_COPIES = "copies"; + + /** + * The "renames" key in the "diff section" + * @since 3.0 + */ + public static final String CONFIG_KEY_RENAMES = "renames"; } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java index d32eb99792..33654447ae 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java @@ -2,6 +2,7 @@ * Copyright (C) 2007, Dave Watson <dwatson@mimvista.com> * Copyright (C) 2007-2008, Robin Rosenberg <robin.rosenberg@dewire.com> * Copyright (C) 2010, Jens Baumgart <jens.baumgart@sap.com> + * Copyright (C) 2013, Robin Stocker <robin@nibor.org> * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available @@ -49,7 +50,9 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; import org.eclipse.jgit.dircache.DirCache; @@ -85,6 +88,105 @@ import org.eclipse.jgit.treewalk.filter.TreeFilter; */ public class IndexDiff { + /** + * Represents the state of the index for a certain path regarding the stages + * - which stages exist for a path and which not (base, ours, theirs). + * <p> + * This is used for figuring out what kind of conflict occurred. + * + * @see IndexDiff#getConflictingStageStates() + * @since 3.0 + */ + public static enum StageState { + /** + * Exists in base, but neither in ours nor in theirs. + */ + BOTH_DELETED(1), + + /** + * Only exists in ours. + */ + ADDED_BY_US(2), + + /** + * Exists in base and ours, but no in theirs. + */ + DELETED_BY_THEM(3), + + /** + * Only exists in theirs. + */ + ADDED_BY_THEM(4), + + /** + * Exists in base and theirs, but not in ours. + */ + DELETED_BY_US(5), + + /** + * Exists in ours and theirs, but not in base. + */ + BOTH_ADDED(6), + + /** + * Exists in all stages, content conflict. + */ + BOTH_MODIFIED(7); + + private final int stageMask; + + private StageState(int stageMask) { + this.stageMask = stageMask; + } + + int getStageMask() { + return stageMask; + } + + /** + * @return whether there is a "base" stage entry + */ + public boolean hasBase() { + return (stageMask & 1) != 0; + } + + /** + * @return whether there is an "ours" stage entry + */ + public boolean hasOurs() { + return (stageMask & 2) != 0; + } + + /** + * @return whether there is a "theirs" stage entry + */ + public boolean hasTheirs() { + return (stageMask & 4) != 0; + } + + static StageState fromMask(int stageMask) { + // bits represent: theirs, ours, base + switch (stageMask) { + case 1: // 0b001 + return BOTH_DELETED; + case 2: // 0b010 + return ADDED_BY_US; + case 3: // 0b011 + return DELETED_BY_THEM; + case 4: // 0b100 + return ADDED_BY_THEM; + case 5: // 0b101 + return DELETED_BY_US; + case 6: // 0b110 + return BOTH_ADDED; + case 7: // 0b111 + return BOTH_MODIFIED; + default: + return null; + } + } + } + private static final class ProgressReportingFilter extends TreeFilter { private final ProgressMonitor monitor; @@ -156,7 +258,7 @@ public class IndexDiff { private Set<String> untracked = new HashSet<String>(); - private Set<String> conflicts = new HashSet<String>(); + private Map<String, StageState> conflicts = new HashMap<String, StageState>(); private Set<String> ignored; @@ -295,9 +397,13 @@ public class IndexDiff { if (dirCacheIterator != null) { final DirCacheEntry dirCacheEntry = dirCacheIterator .getDirCacheEntry(); - if (dirCacheEntry != null && dirCacheEntry.getStage() > 0) { - conflicts.add(treeWalk.getPathString()); - continue; + if (dirCacheEntry != null) { + int stage = dirCacheEntry.getStage(); + if (stage > 0) { + String path = treeWalk.getPathString(); + addConflict(path, stage); + continue; + } } } @@ -355,6 +461,18 @@ public class IndexDiff { return true; } + private void addConflict(String path, int stage) { + StageState existingStageStates = conflicts.get(path); + byte stageMask = 0; + if (existingStageStates != null) + stageMask |= existingStageStates.getStageMask(); + // stage 1 (base) should be shifted 0 times + int shifts = stage - 1; + stageMask |= (1 << shifts); + StageState stageState = StageState.fromMask(stageMask); + conflicts.put(path, stageState); + } + /** * @return list of files added to the index, not in the tree */ @@ -398,9 +516,19 @@ public class IndexDiff { } /** - * @return list of files that are in conflict + * @return list of files that are in conflict, corresponds to the keys of + * {@link #getConflictingStageStates()} */ public Set<String> getConflicting() { + return conflicts.keySet(); + } + + /** + * @return the map from each path of {@link #getConflicting()} to its + * corresponding {@link StageState} + * @since 3.0 + */ + public Map<String, StageState> getConflictingStageStates() { return conflicts; } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefUpdate.java index 9ef1722d7e..8d59cb47b4 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefUpdate.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefUpdate.java @@ -531,7 +531,7 @@ public abstract class RefUpdate { final String myName = getRef().getLeaf().getName(); if (myName.startsWith(Constants.R_HEADS)) { Ref head = getRefDatabase().getRef(Constants.HEAD); - while (head.isSymbolic()) { + while (head != null && head.isSymbolic()) { head = head.getTarget(); if (myName.equals(head.getName())) return result = Result.REJECTED_CURRENT_BRANCH; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java index 540d6a8c66..5802850a30 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java @@ -53,7 +53,6 @@ import java.io.IOException; import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; -import java.util.logging.Logger; import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.dircache.DirCacheBuilder; @@ -85,8 +84,6 @@ import org.eclipse.jgit.treewalk.WorkingTreeIterator; * @since 3.0 */ public class RecursiveMerger extends ResolveMerger { - static Logger log = Logger.getLogger(RecursiveMerger.class.toString()); - /** * The maximum number of merge bases. This merge will stop when the number * of merge bases exceeds this value diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevTag.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevTag.java index 269b6c104f..12693a03e2 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevTag.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevTag.java @@ -240,8 +240,16 @@ public class RevTag extends RevObject { /** * Get a reference to the object this tag was placed on. + * <p> + * Note that the returned object has only been looked up (see + * {@link RevWalk#lookupAny(AnyObjectId, int)}. To access the contents it + * needs to be parsed, see {@link RevWalk#parseHeaders(RevObject)} and + * {@link RevWalk#parseBody(RevObject)}. + * <p> + * As an alternative, use {@link RevWalk#peel(RevObject)} and pass this + * {@link RevTag} to peel it until the first non-tag object. * - * @return object this tag refers to. + * @return object this tag refers to (only looked up, not parsed) */ public final RevObject getObject() { return object; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefSpec.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefSpec.java index 53a7b02be3..9b38b29336 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefSpec.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefSpec.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> + * Copyright (C) 2008, 2013 Shawn O. Pearce <spearce@spearce.org> * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available @@ -106,13 +106,13 @@ public class RefSpec implements Serializable { * <p> * Specifications are typically one of the following forms: * <ul> - * <li><code>refs/head/master</code></li> - * <li><code>refs/head/master:refs/remotes/origin/master</code></li> - * <li><code>refs/head/*:refs/remotes/origin/*</code></li> - * <li><code>+refs/head/master</code></li> - * <li><code>+refs/head/master:refs/remotes/origin/master</code></li> - * <li><code>+refs/head/*:refs/remotes/origin/*</code></li> - * <li><code>:refs/head/master</code></li> + * <li><code>refs/heads/master</code></li> + * <li><code>refs/heads/master:refs/remotes/origin/master</code></li> + * <li><code>refs/heads/*:refs/remotes/origin/*</code></li> + * <li><code>+refs/heads/master</code></li> + * <li><code>+refs/heads/master:refs/remotes/origin/master</code></li> + * <li><code>+refs/heads/*:refs/remotes/origin/*</code></li> + * <li><code>:refs/heads/master</code></li> * </ul> * * @param spec diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/AbstractTreeIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/AbstractTreeIterator.java index 4cf79c0a27..2dd3c3aa14 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/AbstractTreeIterator.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/AbstractTreeIterator.java @@ -425,7 +425,14 @@ public abstract class AbstractTreeIterator { return TreeWalk.pathOf(this); } - /** @return the internal buffer holding the current path. */ + /** + * Get the current entry path buffer. + * <p> + * Note that the returned byte[] has to be used together with + * {@link #getEntryPathLength()} (only use bytes up to this length). + * + * @return the internal buffer holding the current path. + */ public byte[] getEntryPathBuffer() { return path; } |