diff options
author | Matthias Sohn <matthias.sohn@sap.com> | 2013-12-05 00:14:08 +0100 |
---|---|---|
committer | Matthias Sohn <matthias.sohn@sap.com> | 2013-12-05 00:14:25 +0100 |
commit | 162a5c4c89b289af3755a2f26843cdf908e93c50 (patch) | |
tree | 377792666836715cee1ec2f4d5582641d854dce3 /org.eclipse.jgit/src/org/eclipse/jgit/api | |
parent | fceae20181b2b20632fe44731407bfb940093817 (diff) | |
parent | f86a488e32906593903acb31a93a82bed8d87915 (diff) | |
download | jgit-162a5c4c89b289af3755a2f26843cdf908e93c50.tar.gz jgit-162a5c4c89b289af3755a2f26843cdf908e93c50.zip |
Merge branch 'master' into stable-3.2
* master:
Implement rebase.autostash
CLI status should support --porcelain
More helpful InvalidPathException messages (include reason)
Fix IgnoreRule#isMatch returning wrong result due to missing reset
Fix exception on conflicts with recursive merge
Add pgm test for checkout of existing branch with checkout conflict
Fix broken symbolic links on Cygwin.
Do not allow non-ff-rebase if there are uncommitted changes
Manage CheckoutConflictException in pgm
Fix handling of file/folder conflicts during a checkout
Mention null return in Javadoc of Config#getString
Fix applying stash on other commit
Use static factory methods instead of overloaded constructors
Break up GCTest to run in parallel
Modify T0004_PackReaderTest to use existing pack
Move SampleDataRepositoryTestCase to org.eclipse.jgit.test
Support running from JARs in JGitTestUtil
Cache SimpleDateFormat in GitDateParser per locale
Fix FIXUP error for blank lines in interactive rebase
Fix parsing Rebase todo lines when commit message is missing
Add close() method to API
Update Jetty to 7.6.14.v20131031
Document that path parameters should use '/' as separator
Improve Javadoc for typeHint parameter
Do not update the ref hot bit when checking isIndexLoaded
Don't delete .idx file if .pack file can't be deleted
Change-Id: I02abfc09000d0fe9bdf4331c65bec7046f586179
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
Diffstat (limited to 'org.eclipse.jgit/src/org/eclipse/jgit/api')
22 files changed, 301 insertions, 77 deletions
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java index ef2e987b4e..c23256c74b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/AddCommand.java @@ -93,11 +93,15 @@ public class AddCommand extends GitCommand<DirCache> { } /** + * Add a path to a file/directory whose content should be added. + * <p> + * A directory name (e.g. <code>dir</code> to add <code>dir/file1</code> and + * <code>dir/file2</code>) can also be given to add all files in the + * directory, recursively. Fileglobs (e.g. *.c) are not yet supported. + * * @param filepattern - * File to add content from. Also a leading directory name (e.g. - * dir to add dir/file1 and dir/file2) can be given to add all - * files in the directory, recursively. Fileglobs (e.g. *.c) are - * not yet supported. + * repository-relative path of file/directory to add (with + * <code>/</code> as separator) * @return {@code this} */ public AddCommand addFilepattern(String filepattern) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/BlameCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/BlameCommand.java index 12be64bb02..11dfd1c585 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/BlameCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/BlameCommand.java @@ -86,9 +86,10 @@ public class BlameCommand extends GitCommand<BlameResult> { } /** - * Set file path + * Set file path. * * @param filePath + * file path (with <code>/</code> as separator) * @return this command */ public BlameCommand setFilePath(String filePath) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java index eb447f3142..8dfd211a08 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java @@ -305,15 +305,16 @@ public class CheckoutCommand extends GitCommand<Ref> { } /** - * Add a single path to the list of paths to check out. To check out all - * paths, use {@link #setAllPaths(boolean)}. + * Add a single slash-separated path to the list of paths to check out. To + * check out all paths, use {@link #setAllPaths(boolean)}. * <p> * If this option is set, neither the {@link #setCreateBranch(boolean)} nor * {@link #setName(String)} option is considered. In other words, these * options are exclusive. * * @param path - * path to update in the working tree and index + * path to update in the working tree and index (with + * <code>/</code> as separator) * @return {@code this} */ public CheckoutCommand addPath(String path) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CleanCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CleanCommand.java index b42c80f67b..f273eafe1f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CleanCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CleanCommand.java @@ -174,7 +174,7 @@ public class CleanCommand extends GitCommand<Set<String>> { * If paths are set, only these paths are affected by the cleaning. * * @param paths - * the paths to set + * the paths to set (with <code>/</code> as separator) * @return {@code this} */ public CleanCommand setPaths(Set<String> paths) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java index 399d78e095..21d7138c9f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java @@ -667,14 +667,14 @@ public class CommitCommand extends GitCommand<RevCommit> { } /** - * Commit dedicated path only - * + * Commit dedicated path only. + * <p> * This method can be called several times to add multiple paths. Full file * paths are supported as well as directory paths; in the latter case this - * commits all files/ directories below the specified path. + * commits all files/directories below the specified path. * * @param only - * path to commit + * path to commit (with <code>/</code> as separator) * @return {@code this} */ public CommitCommand setOnly(String only) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java index 08ab88005d..983b6b552e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java @@ -125,6 +125,26 @@ public class Git { } /** + * Frees resources held by the underlying {@link Repository} instance. It is + * recommended to call this method as soon as you don't need a reference to + * this {@link Git} instance and the underlying {@link Repository} instance + * anymore. This method closes the underlying object and ref databases. This + * will free memory and file handles. E.g. on Windows the repository will + * keep file handles on pack files unless you call this method. Such open + * file handles may for example prevent that the repository folder in the + * filesystem can be deleted. + * <p> + * After calling close() you should not use this {@link Git} instance and + * the underlying {@link Repository} instance anymore. + * + * @since 3.2 + */ + public void close() { + if (repo != null) + repo.close(); + } + + /** * Returns a command object to execute a {@code clone} command * * @see <a diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/LogCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/LogCommand.java index 51a233458f..9690f799c1 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/LogCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/LogCommand.java @@ -282,11 +282,11 @@ public class LogCommand extends GitCommand<Iterable<RevCommit>> { /** * Show only commits that affect any of the specified paths. The path must - * either name a file or a directory exactly. Note that regex expressions or - * wildcards are not supported. + * either name a file or a directory exactly and use <code>/</code> (slash) + * as separator. Note that regex expressions or wildcards are not supported. * * @param path - * a path is relative to the top level of the repository + * a repository-relative path (with <code>/</code> as separator) * @return {@code this} */ public LogCommand addPath(String path) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java index 509203e528..78b260df71 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java @@ -379,8 +379,7 @@ public class MergeCommand extends GitCommand<MergeResult> { if (failingPaths != null) { repo.writeMergeCommitMsg(null); repo.writeMergeHeads(null); - return new MergeResult(null, - merger.getBaseCommit(0, 1), + return new MergeResult(null, merger.getBaseCommitId(), new ObjectId[] { headCommit.getId(), srcCommit.getId() }, MergeStatus.FAILED, mergeStrategy, @@ -390,8 +389,7 @@ public class MergeCommand extends GitCommand<MergeResult> { .formatWithConflicts(mergeMessage, unmergedPaths); repo.writeMergeCommitMsg(mergeMessageWithConflicts); - return new MergeResult(null, - merger.getBaseCommit(0, 1), + return new MergeResult(null, merger.getBaseCommitId(), new ObjectId[] { headCommit.getId(), srcCommit.getId() }, MergeStatus.CONFLICTING, mergeStrategy, diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java index 8ae51d74ce..10b273a744 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java @@ -70,6 +70,7 @@ import org.eclipse.jgit.api.errors.NoHeadException; import org.eclipse.jgit.api.errors.NoMessageException; import org.eclipse.jgit.api.errors.RefAlreadyExistsException; import org.eclipse.jgit.api.errors.RefNotFoundException; +import org.eclipse.jgit.api.errors.StashApplyFailureException; import org.eclipse.jgit.api.errors.UnmergedPathsException; import org.eclipse.jgit.api.errors.WrongRepositoryStateException; import org.eclipse.jgit.diff.DiffFormatter; @@ -79,6 +80,7 @@ import org.eclipse.jgit.dircache.DirCacheIterator; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.lib.AbbreviatedObjectId; import org.eclipse.jgit.lib.AnyObjectId; +import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.NullProgressMonitor; import org.eclipse.jgit.lib.ObjectId; @@ -158,6 +160,10 @@ public class RebaseCommand extends GitCommand<RebaseResult> { private static final String MESSAGE_SQUASH = "message-squash"; //$NON-NLS-1$ + private static final String AUTOSTASH = "autostash"; //$NON-NLS-1$ + + private static final String AUTOSTASH_MSG = "On {0}: autostash"; + /** * The available operations */ @@ -257,11 +263,26 @@ public class RebaseCommand extends GitCommand<RebaseResult> { .resolve(upstreamCommitId)); break; case BEGIN: + autoStash(); + if (stopAfterInitialization + || !walk.isMergedInto( + walk.parseCommit(repo.resolve(Constants.HEAD)), + upstreamCommit)) { + org.eclipse.jgit.api.Status status = Git.wrap(repo) + .status().call(); + if (status.hasUncommittedChanges()) { + List<String> list = new ArrayList<String>(); + list.addAll(status.getUncommittedChanges()); + return RebaseResult.uncommittedChanges(list); + } + } RebaseResult res = initFilesAndRewind(); if (stopAfterInitialization) return RebaseResult.INTERACTIVE_PREPARED_RESULT; - if (res != null) + if (res != null) { + autoStashApply(); return res; + } } if (monitor.isCancelled()) @@ -321,12 +342,63 @@ public class RebaseCommand extends GitCommand<RebaseResult> { } return finishRebase(newHead, lastStepWasForward); } catch (CheckoutConflictException cce) { - return new RebaseResult(cce.getConflictingPaths()); + return RebaseResult.conflicts(cce.getConflictingPaths()); } catch (IOException ioe) { throw new JGitInternalException(ioe.getMessage(), ioe); } } + private void autoStash() throws GitAPIException, IOException { + if (repo.getConfig().getBoolean(ConfigConstants.CONFIG_REBASE_SECTION, + ConfigConstants.CONFIG_KEY_AUTOSTASH, false)) { + String message = MessageFormat.format( + AUTOSTASH_MSG, + Repository + .shortenRefName(getHeadName(getHead()))); + RevCommit stashCommit = Git.wrap(repo).stashCreate().setRef(null) + .setWorkingDirectoryMessage( + message) + .call(); + if (stashCommit != null) { + FileUtils.mkdir(rebaseState.getDir()); + rebaseState.createFile(AUTOSTASH, stashCommit.getName()); + } + } + } + + private boolean autoStashApply() throws IOException, GitAPIException { + boolean conflicts = false; + if (rebaseState.getFile(AUTOSTASH).exists()) { + String stash = rebaseState.readFile(AUTOSTASH); + try { + Git.wrap(repo).stashApply().setStashRef(stash) + .ignoreRepositoryState(true).call(); + } catch (StashApplyFailureException e) { + conflicts = true; + RevWalk rw = new RevWalk(repo); + ObjectId stashId = repo.resolve(stash); + RevCommit commit = rw.parseCommit(stashId); + updateStashRef(commit, commit.getAuthorIdent(), + commit.getShortMessage()); + } + } + return conflicts; + } + + private void updateStashRef(ObjectId commitId, PersonIdent refLogIdent, + String refLogMessage) throws IOException { + Ref currentRef = repo.getRef(Constants.R_STASH); + RefUpdate refUpdate = repo.updateRef(Constants.R_STASH); + refUpdate.setNewObjectId(commitId); + refUpdate.setRefLogIdent(refLogIdent); + refUpdate.setRefLogMessage(refLogMessage, false); + if (currentRef != null) + refUpdate.setExpectedOldObjectId(currentRef.getObjectId()); + else + refUpdate.setExpectedOldObjectId(ObjectId.zeroId()); + refUpdate.forceUpdate(); + } + private RebaseResult processStep(RebaseTodoLine step, boolean shouldPick) throws IOException, GitAPIException { if (Action.COMMENT.equals(step.getAction())) @@ -340,7 +412,7 @@ public class RebaseCommand extends GitCommand<RebaseResult> { RevCommit commitToPick = walk.parseCommit(ids.iterator().next()); if (shouldPick) { if (monitor.isCancelled()) - return new RebaseResult(commitToPick, Status.STOPPED); + return RebaseResult.result(Status.STOPPED, commitToPick); RebaseResult result = cherryPickCommit(commitToPick); if (result != null) return result; @@ -403,8 +475,8 @@ public class RebaseCommand extends GitCommand<RebaseResult> { switch (cherryPickResult.getStatus()) { case FAILED: if (operation == Operation.BEGIN) - return abort(new RebaseResult( - cherryPickResult.getFailingPaths())); + return abort(RebaseResult.failed(cherryPickResult + .getFailingPaths())); else return stop(commitToPick, Status.STOPPED); case CONFLICTING: @@ -420,10 +492,13 @@ public class RebaseCommand extends GitCommand<RebaseResult> { } private RebaseResult finishRebase(RevCommit newHead, - boolean lastStepWasForward) throws IOException { + boolean lastStepWasForward) throws IOException, GitAPIException { String headName = rebaseState.readFile(HEAD_NAME); updateHead(headName, newHead, upstreamCommit); + boolean stashConflicts = autoStashApply(); FileUtils.delete(rebaseState.getDir(), FileUtils.RECURSIVE); + if (stashConflicts) + return RebaseResult.STASH_APPLY_CONFLICTS_RESULT; if (lastStepWasForward || newHead == null) return RebaseResult.FAST_FORWARD_RESULT; return RebaseResult.OK_RESULT; @@ -550,7 +625,7 @@ public class RebaseCommand extends GitCommand<RebaseResult> { } else { sb.append("# The ").append(count).append(ordinal) .append(" commit message will be skipped:\n# "); - sb.append(commitToPick.getFullMessage().replaceAll("([\n\r]+)", + sb.append(commitToPick.getFullMessage().replaceAll("([\n\r])", "$1# ")); } // Add the previous message without header (i.e first line) @@ -735,7 +810,7 @@ public class RebaseCommand extends GitCommand<RebaseResult> { // Remove cherry pick state file created by CherryPickCommand, it's not // needed for rebase repo.writeCherryPickHead(null); - return new RebaseResult(commitToPick, status); + return RebaseResult.result(status, commitToPick); } String toAuthorScript(PersonIdent author) { @@ -797,16 +872,9 @@ public class RebaseCommand extends GitCommand<RebaseResult> { // we need to store everything into files so that we can implement // --skip, --continue, and --abort - Ref head = repo.getRef(Constants.HEAD); - if (head == null || head.getObjectId() == null) - throw new RefNotFoundException(MessageFormat.format( - JGitText.get().refNotResolved, Constants.HEAD)); + Ref head = getHead(); - String headName; - if (head.isSymbolic()) - headName = head.getTarget().getName(); - else - headName = head.getObjectId().getName(); + String headName = getHeadName(head); ObjectId headId = head.getObjectId(); if (headId == null) throw new RefNotFoundException(MessageFormat.format( @@ -845,7 +913,7 @@ public class RebaseCommand extends GitCommand<RebaseResult> { Collections.reverse(cherryPickList); // create the folder for the meta information - FileUtils.mkdir(rebaseState.getDir()); + FileUtils.mkdir(rebaseState.getDir(), true); repo.writeOrigHead(headId); rebaseState.createFile(REBASE_HEAD, headId.name()); @@ -881,6 +949,23 @@ public class RebaseCommand extends GitCommand<RebaseResult> { return null; } + private static String getHeadName(Ref head) { + String headName; + if (head.isSymbolic()) + headName = head.getTarget().getName(); + else + headName = head.getObjectId().getName(); + return headName; + } + + private Ref getHead() throws IOException, RefNotFoundException { + Ref head = repo.getRef(Constants.HEAD); + if (head == null || head.getObjectId() == null) + throw new RefNotFoundException(MessageFormat.format( + JGitText.get().refNotResolved, Constants.HEAD)); + return head; + } + private boolean isInteractive() { return interactiveHandler != null; } @@ -895,10 +980,7 @@ public class RebaseCommand extends GitCommand<RebaseResult> { */ public RevCommit tryFastForward(RevCommit newCommit) throws IOException, GitAPIException { - Ref head = repo.getRef(Constants.HEAD); - if (head == null || head.getObjectId() == null) - throw new RefNotFoundException(MessageFormat.format( - JGitText.get().refNotResolved, Constants.HEAD)); + Ref head = getHead(); ObjectId headId = head.getObjectId(); if (headId == null) @@ -908,11 +990,7 @@ public class RebaseCommand extends GitCommand<RebaseResult> { if (walk.isMergedInto(newCommit, headCommit)) return newCommit; - String headName; - if (head.isSymbolic()) - headName = head.getTarget().getName(); - else - headName = head.getObjectId().getName(); + String headName = getHeadName(head); return tryFastForward(headName, headCommit, newCommit); } @@ -992,7 +1070,8 @@ public class RebaseCommand extends GitCommand<RebaseResult> { } } - private RebaseResult abort(RebaseResult result) throws IOException { + private RebaseResult abort(RebaseResult result) throws IOException, + GitAPIException { try { ObjectId origHead = repo.readOrigHead(); String commitId = origHead != null ? origHead.name() : null; @@ -1041,9 +1120,12 @@ public class RebaseCommand extends GitCommand<RebaseResult> { JGitText.get().abortingRebaseFailed); } } + boolean stashConflicts = autoStashApply(); // cleanup the files FileUtils.delete(rebaseState.getDir(), FileUtils.RECURSIVE); repo.writeCherryPickHead(null); + if (stashConflicts) + return RebaseResult.STASH_APPLY_CONFLICTS_RESULT; return result; } finally { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseResult.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseResult.java index aaa75d9b88..92c1347ab2 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseResult.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseResult.java @@ -105,6 +105,18 @@ public class RebaseResult { } }, /** + * The repository contains uncommitted changes and the rebase is not a + * fast-forward + * + * @since 3.2 + */ + UNCOMMITTED_CHANGES { + @Override + public boolean isSuccessful() { + return false; + } + }, + /** * Conflicts: checkout of target HEAD failed */ CONFLICTS { @@ -153,6 +165,18 @@ public class RebaseResult { public boolean isSuccessful() { return false; } + }, + + /** + * Applying stash resulted in conflicts + * + * @since 3.2 + */ + STASH_APPLY_CONFLICTS { + @Override + public boolean isSuccessful() { + return true; + } }; /** @@ -177,6 +201,9 @@ public class RebaseResult { static final RebaseResult INTERACTIVE_PREPARED_RESULT = new RebaseResult( Status.INTERACTIVE_PREPARED); + static final RebaseResult STASH_APPLY_CONFLICTS_RESULT = new RebaseResult( + Status.STASH_APPLY_CONFLICTS); + private final Status status; private final RevCommit currentCommit; @@ -185,21 +212,29 @@ public class RebaseResult { private List<String> conflicts; + private List<String> uncommittedChanges; + private RebaseResult(Status status) { this.status = status; currentCommit = null; } + private RebaseResult(Status status, RevCommit commit) { + this.status = status; + currentCommit = commit; + } + /** - * Create <code>RebaseResult</code> with status {@link Status#STOPPED} + * Create <code>RebaseResult</code> * + * @param status * @param commit * current commit - * @param status + * @return the RebaseResult */ - RebaseResult(RevCommit commit, RebaseResult.Status status) { - this.status = status; - currentCommit = commit; + static RebaseResult result(RebaseResult.Status status, + RevCommit commit) { + return new RebaseResult(status, commit); } /** @@ -207,11 +242,13 @@ public class RebaseResult { * * @param failingPaths * list of paths causing this rebase to fail + * @return the RebaseResult */ - RebaseResult(Map<String, MergeFailureReason> failingPaths) { - status = Status.FAILED; - currentCommit = null; - this.failingPaths = failingPaths; + static RebaseResult failed( + Map<String, MergeFailureReason> failingPaths) { + RebaseResult result = new RebaseResult(Status.FAILED); + result.failingPaths = failingPaths; + return result; } /** @@ -219,11 +256,26 @@ public class RebaseResult { * * @param conflicts * the list of conflicting paths + * @return the RebaseResult */ - RebaseResult(List<String> conflicts) { - status = Status.CONFLICTS; - currentCommit = null; - this.conflicts = conflicts; + static RebaseResult conflicts(List<String> conflicts) { + RebaseResult result = new RebaseResult(Status.CONFLICTS); + result.conflicts = conflicts; + return result; + } + + /** + * Create <code>RebaseResult</code> with status + * {@link Status#UNCOMMITTED_CHANGES} + * + * @param uncommittedChanges + * the list of paths + * @return the RebaseResult + */ + static RebaseResult uncommittedChanges(List<String> uncommittedChanges) { + RebaseResult result = new RebaseResult(Status.UNCOMMITTED_CHANGES); + result.uncommittedChanges = uncommittedChanges; + return result; } /** @@ -256,4 +308,15 @@ public class RebaseResult { public List<String> getConflicts() { return conflicts; } + + /** + * @return the list of uncommitted changes if status is + * {@link Status#UNCOMMITTED_CHANGES} + * + * @since 3.2 + */ + public List<String> getUncommittedChanges() { + return uncommittedChanges; + } + } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java index 3a1c209a2d..7c2192dd9f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java @@ -279,16 +279,17 @@ public class ResetCommand extends GitCommand<Ref> { } /** - * @param file - * the file to add + * @param path + * repository-relative path of file/directory to reset (with + * <code>/</code> as separator) * @return this instance */ - public ResetCommand addPath(String file) { + public ResetCommand addPath(String path) { if (mode != null) throw new JGitInternalException(MessageFormat.format( JGitText.get().illegalCombinationOfArguments, "<paths>...", "[--mixed | --soft | --hard]")); //$NON-NLS-1$ - filepaths.add(file); + filepaths.add(path); return this; } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RevertCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RevertCommand.java index 2bc9d22449..bc1b29c2f6 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RevertCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RevertCommand.java @@ -191,14 +191,14 @@ public class RevertCommand extends GitCommand<RevCommit> { .getFailingPaths(); if (failingPaths != null) failingResult = new MergeResult(null, - merger.getBaseCommit(0, 1), + merger.getBaseCommitId(), new ObjectId[] { headCommit.getId(), srcParent.getId() }, MergeStatus.FAILED, MergeStrategy.RECURSIVE, merger.getMergeResults(), failingPaths, null); else failingResult = new MergeResult(null, - merger.getBaseCommit(0, 1), + merger.getBaseCommitId(), new ObjectId[] { headCommit.getId(), srcParent.getId() }, MergeStatus.CONFLICTING, diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RmCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RmCommand.java index ac30ffcb7d..c70b4aeaf2 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RmCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RmCommand.java @@ -104,7 +104,8 @@ public class RmCommand extends GitCommand<DirCache> { /** * @param filepattern - * File to remove. + * repository-relative path of file to remove (with + * <code>/</code> as separator) * @return {@code this} */ public RmCommand addFilepattern(String filepattern) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java index 020a6dc5f2..8440d8b950 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java @@ -90,6 +90,8 @@ public class StashApplyCommand extends GitCommand<ObjectId> { private boolean applyIndex = true; + private boolean ignoreRepositoryState; + /** * Create command to apply the changes of a stashed commit * @@ -113,6 +115,16 @@ public class StashApplyCommand extends GitCommand<ObjectId> { return this; } + /** + * @param ignoreRepositoryState + * @return {@code this} + * @since 3.2 + */ + public StashApplyCommand ignoreRepositoryState(boolean ignoreRepositoryState) { + this.ignoreRepositoryState = ignoreRepositoryState; + return this; + } + private ObjectId getStashId() throws GitAPIException { final String revision = stashRef != null ? stashRef : DEFAULT_REF; final ObjectId stashId; @@ -143,7 +155,8 @@ public class StashApplyCommand extends GitCommand<ObjectId> { StashApplyFailureException { checkCallable(); - if (repo.getRepositoryState() != RepositoryState.SAFE) + if (!ignoreRepositoryState + && repo.getRepositoryState() != RepositoryState.SAFE) throw new WrongRepositoryStateException(MessageFormat.format( JGitText.get().stashApplyOnUnsafeRepository, repo.getRepositoryState())); @@ -185,6 +198,7 @@ public class StashApplyCommand extends GitCommand<ObjectId> { .newMerger(repo, true); ixMerger.setCommitNames(new String[] { "stashed HEAD", "HEAD", "stashed index" }); + ixMerger.setBase(stashHeadCommit); boolean ok = ixMerger.merge(headCommit, stashIndexCommit); if (ok) { resetIndex(revWalk diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashCreateCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashCreateCommand.java index fc21b919b6..cf0b6d1d9c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashCreateCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashCreateCommand.java @@ -154,6 +154,7 @@ public class StashCreateCommand extends GitCommand<RevCommit> { /** * Set the reference to update with the stashed commit id + * If null, no reference is updated * <p> * This value defaults to {@link Constants#R_STASH} * @@ -185,6 +186,8 @@ public class StashCreateCommand extends GitCommand<RevCommit> { private void updateStashRef(ObjectId commitId, PersonIdent refLogIdent, String refLogMessage) throws IOException { + if (ref == null) + return; Ref currentRef = repo.getRef(ref); RefUpdate refUpdate = repo.updateRef(ref); refUpdate.setNewObjectId(commitId); 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 e840c2f608..c3fcd8bfe8 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/Status.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/Status.java @@ -43,6 +43,7 @@ package org.eclipse.jgit.api; import java.util.Collections; +import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -66,19 +67,22 @@ public class Status { private final boolean clean; + private final boolean hasUncommittedChanges;; + /** * @param diff */ public Status(IndexDiff diff) { super(); this.diff = diff; - clean = diff.getAdded().isEmpty() // - && diff.getChanged().isEmpty() // - && diff.getRemoved().isEmpty() // - && diff.getMissing().isEmpty() // - && diff.getModified().isEmpty() // - && diff.getUntracked().isEmpty() // - && diff.getConflicting().isEmpty(); + hasUncommittedChanges = !diff.getAdded().isEmpty() // + || !diff.getChanged().isEmpty() // + || !diff.getRemoved().isEmpty() // + || !diff.getMissing().isEmpty() // + || !diff.getModified().isEmpty() // + || !diff.getConflicting().isEmpty(); + clean = !hasUncommittedChanges // + && diff.getUntracked().isEmpty(); } /** @@ -90,6 +94,15 @@ public class Status { } /** + * @return true if any tracked file is changed + * + * @since 3.2 + */ + public boolean hasUncommittedChanges() { + return hasUncommittedChanges; + } + + /** * @return list of files added to the index, not in HEAD (e.g. what you get * if you call 'git add ...' on a newly created file) */ @@ -168,4 +181,21 @@ public class Status { public Set<String> getIgnoredNotInIndex() { return Collections.unmodifiableSet(diff.getIgnoredNotInIndex()); } + + /** + * @return set of files and folders that are known to the repo and changed + * either in the index or in the working tree. + * + * @since 3.2 + */ + public Set<String> getUncommittedChanges() { + Set<String> uncommittedChanges = new HashSet<String>(); + uncommittedChanges.addAll(diff.getAdded()); + uncommittedChanges.addAll(diff.getChanged()); + uncommittedChanges.addAll(diff.getRemoved()); + uncommittedChanges.addAll(diff.getMissing()); + uncommittedChanges.addAll(diff.getModified()); + uncommittedChanges.addAll(diff.getConflicting()); + return uncommittedChanges; + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/StatusCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/StatusCommand.java index eaf5483671..dee0a31b91 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/StatusCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/StatusCommand.java @@ -89,7 +89,8 @@ public class StatusCommand extends GitCommand<Status> { * supported. * * @param path - * a path is relative to the top level of the repository + * repository-relative path of file/directory to show status for + * (with <code>/</code> as separator) * @return {@code this} * @since 3.1 */ diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleAddCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleAddCommand.java index bfef053d85..09e4cf0a1b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleAddCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleAddCommand.java @@ -93,6 +93,7 @@ public class SubmoduleAddCommand extends * Set repository-relative path of submodule * * @param path + * (with <code>/</code> as separator) * @return this command */ public SubmoduleAddCommand setPath(final String path) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleInitCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleInitCommand.java index e799bfb8bd..0ed02acc82 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleInitCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleInitCommand.java @@ -83,6 +83,7 @@ public class SubmoduleInitCommand extends GitCommand<Collection<String>> { * Add repository-relative submodule path to initialize * * @param path + * (with <code>/</code> as separator) * @return this command */ public SubmoduleInitCommand addPath(final String path) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleStatusCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleStatusCommand.java index bbc01adbae..6e89f9873e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleStatusCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleStatusCommand.java @@ -83,6 +83,7 @@ public class SubmoduleStatusCommand extends * Add repository-relative submodule path to limit status reporting to * * @param path + * (with <code>/</code> as separator) * @return this command */ public SubmoduleStatusCommand addPath(final String path) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleSyncCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleSyncCommand.java index 11d3c5acca..e7fe71a890 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleSyncCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleSyncCommand.java @@ -85,6 +85,7 @@ public class SubmoduleSyncCommand extends GitCommand<Map<String, String>> { * Add repository-relative submodule path to synchronize * * @param path + * (with <code>/</code> as separator) * @return this command */ public SubmoduleSyncCommand addPath(final String path) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java index 40f6a9f9a4..e2f356a08e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java @@ -110,6 +110,7 @@ public class SubmoduleUpdateCommand extends * Add repository-relative submodule path to initialize * * @param path + * (with <code>/</code> as separator) * @return this command */ public SubmoduleUpdateCommand addPath(final String path) { |