aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilipp Thun2011-03-11 08:25:46 (EST)
committerPhilipp Thun2011-03-11 08:25:46 (EST)
commita490afedba12676a53338bc52b729b9bb779f3a1 (patch)
tree5761c6a81f0f67e264410137d05214d7e67eed3b
parent42f0b11153d2917f96be1a0be94896bdf9eb1044 (diff)
downloadjgit-a490afedba12676a53338bc52b729b9bb779f3a1.zip
jgit-a490afedba12676a53338bc52b729b9bb779f3a1.tar.gz
jgit-a490afedba12676a53338bc52b729b9bb779f3a1.tar.bz2
Add -o option to commit commandrefs/changes/35/2635/5
This change adds the --only/ -o option to the commit command. Change-Id: I44352d56877f8204d985cb7a35a2e0faffb7d341 Signed-off-by: Philipp Thun <philipp.thun@sap.com>
-rw-r--r--org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/CLIText.properties6
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CLIText.java1
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java19
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitAndLogCommandTests.java1245
-rw-r--r--org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java214
7 files changed, 1483 insertions, 6 deletions
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 01b3fba..718c57a 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
@@ -62,8 +62,9 @@ metaVar_base=base
metaVar_bucket=BUCKET
metaVar_command=command
metaVar_commandDetail=DETAIL
-metaVar_commitOrTag=COMMIT|TAG
metaVar_commitish=commit-ish
+metaVar_commitOrTag=COMMIT|TAG
+metaVar_commitPaths=paths
metaVar_configFile=FILE
metaVar_connProp=conn.prop
metaVar_diffAlg=ALGORITHM
@@ -113,6 +114,7 @@ notFound=!! NOT FOUND !!
noteObjectTooLargeToPrint=Note object {0} too large to print
onlyOneMetaVarExpectedIn=Only one {0} expected in {1}.
pushTo=To {0}
+pathsRequired=at least one path has to be specified when using --only
remoteMessage=remote: {0}
remoteRefObjectChangedIsNotExpectedOne=remote ref object changed - is not expected one {0}
remoteSideDoesNotSupportDeletingRefs=remote side does not support deleting refs
@@ -125,6 +127,8 @@ unsupportedOperation=Unsupported operation: {0}
usage_CommandLineClientForamazonsS3Service=Command line client for Amazon's S3 service
usage_CommitAuthor=Override the author name used in the commit. You can use the standard A U Thor <author@example.com> format.
usage_CommitMessage=Use the given <msg> as the commit message
+usage_CommitOnly=commit specified paths only
+usage_CommitPaths=see --only
usage_CreateABareRepository=Create a bare repository
usage_CreateATag=Create a tag
usage_CreateAnEmptyGitRepository=Create an empty git repository
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 1c7e936..c460bc3 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
@@ -133,6 +133,7 @@ public class CLIText extends TranslationBundle {
/***/ public String noteObjectTooLargeToPrint;
/***/ public String onlyOneMetaVarExpectedIn;
/***/ public String pushTo;
+ /***/ public String pathsRequired;
/***/ public String remoteMessage;
/***/ public String remoteRefObjectChangedIsNotExpectedOne;
/***/ public String remoteSideDoesNotSupportDeletingRefs;
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java
index 2737422..ba66a30 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java
@@ -37,6 +37,9 @@
*/
package org.eclipse.jgit.pgm;
+import java.util.ArrayList;
+import java.util.List;
+
import org.eclipse.jgit.api.CommitCommand;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;
@@ -47,6 +50,7 @@ import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.util.RawParseUtils;
+import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.Option;
@Command(common = true, usage = "usage_recordChangesToRepository")
@@ -54,12 +58,18 @@ class Commit extends TextBuiltin {
// I don't support setting the committer, because also the native git
// command doesn't allow this.
- @Option(name = "--author", metaVar="metaVar_author", usage = "usage_CommitAuthor")
+ @Option(name = "--author", metaVar = "metaVar_author", usage = "usage_CommitAuthor")
private String author;
- @Option(name = "--message", aliases = { "-m" }, metaVar="metaVar_message", usage="usage_CommitMessage", required=true)
+ @Option(name = "--message", aliases = { "-m" }, metaVar = "metaVar_message", usage = "usage_CommitMessage", required = true)
private String message;
+ @Option(name = "--only", aliases = { "-o" }, usage = "usage_CommitOnly")
+ private boolean only;
+
+ @Argument(metaVar = "metaVar_commitPaths", usage = "usage_CommitPaths")
+ private List<String> paths = new ArrayList<String>();
+
@Override
protected void run() throws NoHeadException, NoMessageException,
ConcurrentRefUpdateException, JGitInternalException, Exception {
@@ -68,6 +78,11 @@ class Commit extends TextBuiltin {
commitCmd.setAuthor(RawParseUtils.parsePersonIdent(author));
if (message != null)
commitCmd.setMessage(message);
+ if (only && paths.isEmpty())
+ throw die(CLIText.get().pathsRequired);
+ if (!paths.isEmpty())
+ for (String p : paths)
+ commitCmd.setOnly(p);
Ref head = db.getRef(Constants.HEAD);
RevCommit commit = commitCmd.call();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitAndLogCommandTests.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitAndLogCommandTests.java
index 5fa2c81..3d79357 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitAndLogCommandTests.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitAndLogCommandTests.java
@@ -43,6 +43,7 @@
package org.eclipse.jgit.api;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -63,13 +64,90 @@ import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryTestCase;
import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.util.FileUtils;
import org.junit.Test;
+/**
+ * Testing the git commit and log commands
+ *
+ * Testing the 'commit only' option:
+ *
+ * I. A single file (f1.txt) specified as part of the --only/ -o option can have
+ * one of the following (14) states:
+ *
+ * <pre>
+ * | | expected result
+ * ---------------------------------------------------------------------
+ * | HEAD DirCache Worktree | HEAD DirCache
+ * ---------------------------------------------------------------------
+ * f1_1 | - - c | => e: path unknown
+ * f1_2 | - c - | => no changes
+ * f1_3 | c - - | - -
+ * f1_4 | - c c | c c
+ * f1_5 | c c - | - -
+ * f1_6 | c - c | => no changes
+ * f1_7 | c c c | => no changes
+ * ---------------------------------------------------------------------
+ * f1_8 | - c c' | c' c'
+ * f1_9 | c - c' | c' c'
+ * f1_10 | c c' - | - -
+ * f1_11 | c c c' | c' c'
+ * f1_12 | c c' c | => no changes
+ * f1_13 | c c' c' | c' c'
+ * ---------------------------------------------------------------------
+ * f1_14 | c c' c'' | c'' c''
+ * </pre>
+ *
+ * II. Scenarios that do not end with a successful commit (1, 2, 6, 7, 12) have
+ * to be tested with a second file (f2.txt) specified that would lead to a
+ * successful commit, if it were executed separately (e.g. scenario 14).
+ *
+ * <pre>
+ * | | expected result
+ * ---------------------------------------------------------------------------
+ * | HEAD DirCache Worktree | HEAD DirCache
+ * ---------------------------------------------------------------------------
+ * f1_1_f2_14 | - - c | => e: path unknown
+ * f1_2_f2_14 | - c - | - -
+ * f1_6_f2_14 | c - c | c c
+ * f1_7_f2_14 | c c c | c c
+ * ---------------------------------------------------------------------------
+ * f1_12_f2_14 | c c' c | c c
+ * </pre>
+ *
+ * III. All scenarios (1-14, I-II) have to be tested with different repository
+ * states, to check that the --only/ -o option does not change existing content
+ * (HEAD and DirCache). The following states for a file (f3.txt) not specified
+ * shall be tested:
+ *
+ * <pre>
+ * | HEAD DirCache
+ * --------------------
+ * *_a | - -
+ * *_b | - c
+ * *_c | c c
+ * *_d | c -
+ * --------------------
+ * *_e | c c'
+ * </pre>
+ **/
public class CommitAndLogCommandTests extends RepositoryTestCase {
+ private static final String F1 = "f1.txt";
+ private static final String F2 = "f2.txt";
+ private static final String F3 = "f3.txt";
+ private static final String MSG = "commit";
+
+ private static int A = 0;
+ private static int B = 1;
+ private static int C = 2;
+ private static int D = 3;
+ private static int E = 4;
+
@Test
public void testSomeCommits() throws NoHeadException, NoMessageException,
UnmergedPathException, ConcurrentRefUpdateException,
@@ -255,4 +333,1171 @@ public class CommitAndLogCommandTests extends RepositoryTestCase {
}
assertEquals(1, c);
}
+
+ @Test
+ public void testOnlyOption_f1_1_a() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, A);
+ prepare_f1_1(git);
+ executeAndCheck_f1_1(git, A);
+ }
+
+ @Test
+ public void testOnlyOption_f1_1_b() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, B);
+ prepare_f1_1(git);
+ executeAndCheck_f1_1(git, B);
+ }
+
+ @Test
+ public void testOnlyOption_f1_1_c() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, C);
+ prepare_f1_1(git);
+ executeAndCheck_f1_1(git, C);
+ }
+
+ @Test
+ public void testOnlyOption_f1_1_d() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, D);
+ prepare_f1_1(git);
+ executeAndCheck_f1_1(git, D);
+ }
+
+ @Test
+ public void testOnlyOption_f1_1_e() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, E);
+ prepare_f1_1(git);
+ executeAndCheck_f1_1(git, E);
+ }
+
+ @Test
+ public void testOnlyOption_f1_1_f2_14_a() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3_f2_14(git, A);
+ prepare_f1_1(git);
+ executeAndCheck_f1_1_f2_f14(git, A);
+ }
+
+ @Test
+ public void testOnlyOption_f1_1_f2_14_b() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3_f2_14(git, B);
+ prepare_f1_1(git);
+ executeAndCheck_f1_1_f2_f14(git, B);
+ }
+
+ @Test
+ public void testOnlyOption_f1_1_f2_14_c() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3_f2_14(git, C);
+ prepare_f1_1(git);
+ executeAndCheck_f1_1_f2_f14(git, C);
+ }
+
+ @Test
+ public void testOnlyOption_f1_1_f2_14_d() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3_f2_14(git, D);
+ prepare_f1_1(git);
+ executeAndCheck_f1_1_f2_f14(git, D);
+ }
+
+ @Test
+ public void testOnlyOption_f1_1_f2_14_e() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3_f2_14(git, E);
+ prepare_f1_1(git);
+ executeAndCheck_f1_1_f2_f14(git, E);
+ }
+
+ @Test
+ public void testOnlyOption_f1_2_a() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, A);
+ prepare_f1_2(git);
+ executeAndCheck_f1_2(git, A);
+ }
+
+ @Test
+ public void testOnlyOption_f1_2_b() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, B);
+ prepare_f1_2(git);
+ executeAndCheck_f1_2(git, B);
+ }
+
+ @Test
+ public void testOnlyOption_f1_2_c() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, C);
+ prepare_f1_2(git);
+ executeAndCheck_f1_2(git, C);
+ }
+
+ @Test
+ public void testOnlyOption_f1_2_d() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, D);
+ prepare_f1_2(git);
+ executeAndCheck_f1_2(git, D);
+ }
+
+ @Test
+ public void testOnlyOption_f1_2_e() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, E);
+ prepare_f1_2(git);
+ executeAndCheck_f1_2(git, E);
+ }
+
+ @Test
+ public void testOnlyOption_f1_2_f2_14_a() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3_f2_14(git, A);
+ prepare_f1_2(git);
+ executeAndCheck_f1_2_f2_f14(git, A);
+ }
+
+ @Test
+ public void testOnlyOption_f1_2_f2_14_b() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3_f2_14(git, B);
+ prepare_f1_2(git);
+ executeAndCheck_f1_2_f2_f14(git, B);
+ }
+
+ @Test
+ public void testOnlyOption_f1_2_f2_14_c() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3_f2_14(git, C);
+ prepare_f1_2(git);
+ executeAndCheck_f1_2_f2_f14(git, C);
+ }
+
+ @Test
+ public void testOnlyOption_f1_2_f2_14_d() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3_f2_14(git, D);
+ prepare_f1_2(git);
+ executeAndCheck_f1_2_f2_f14(git, D);
+ }
+
+ @Test
+ public void testOnlyOption_f1_2_f2_14_e() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3_f2_14(git, E);
+ prepare_f1_2(git);
+ executeAndCheck_f1_2_f2_f14(git, E);
+ }
+
+ @Test
+ public void testOnlyOption_f1_3_a() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, A);
+ prepare_f1_3(git);
+ executeAndCheck_f1_3(git, A);
+ }
+
+ @Test
+ public void testOnlyOption_f1_3_b() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, B);
+ prepare_f1_3(git);
+ executeAndCheck_f1_3(git, B);
+ }
+
+ @Test
+ public void testOnlyOption_f1_3_c() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, C);
+ prepare_f1_3(git);
+ executeAndCheck_f1_3(git, C);
+ }
+
+ @Test
+ public void testOnlyOption_f1_3_d() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, D);
+ prepare_f1_3(git);
+ executeAndCheck_f1_3(git, D);
+ }
+
+ @Test
+ public void testOnlyOption_f1_3_e() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, E);
+ prepare_f1_3(git);
+ executeAndCheck_f1_3(git, E);
+ }
+
+ @Test
+ public void testOnlyOption_f1_4_a() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, A);
+ prepare_f1_4(git);
+ executeAndCheck_f1_4(git, A);
+ }
+
+ @Test
+ public void testOnlyOption_f1_4_b() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, B);
+ prepare_f1_4(git);
+ executeAndCheck_f1_4(git, B);
+ }
+
+ @Test
+ public void testOnlyOption_f1_4_c() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, C);
+ prepare_f1_4(git);
+ executeAndCheck_f1_4(git, C);
+ }
+
+ @Test
+ public void testOnlyOption_f1_4_d() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, D);
+ prepare_f1_4(git);
+ executeAndCheck_f1_4(git, D);
+ }
+
+ @Test
+ public void testOnlyOption_f1_4_e() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, E);
+ prepare_f1_4(git);
+ executeAndCheck_f1_4(git, E);
+ }
+
+ @Test
+ public void testOnlyOption_f1_5_a() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, A);
+ prepare_f1_5(git);
+ executeAndCheck_f1_5(git, A);
+ }
+
+ @Test
+ public void testOnlyOption_f1_5_b() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, B);
+ prepare_f1_5(git);
+ executeAndCheck_f1_5(git, B);
+ }
+
+ @Test
+ public void testOnlyOption_f1_5_c() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, C);
+ prepare_f1_5(git);
+ executeAndCheck_f1_5(git, C);
+ }
+
+ @Test
+ public void testOnlyOption_f1_5_d() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, D);
+ prepare_f1_5(git);
+ executeAndCheck_f1_5(git, D);
+ }
+
+ @Test
+ public void testOnlyOption_f1_5_e() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, E);
+ prepare_f1_5(git);
+ executeAndCheck_f1_5(git, E);
+ }
+
+ @Test
+ public void testOnlyOption_f1_6_a() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, A);
+ prepare_f1_6(git);
+ executeAndCheck_f1_6(git, A);
+ }
+
+ @Test
+ public void testOnlyOption_f1_6_b() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, B);
+ prepare_f1_6(git);
+ executeAndCheck_f1_6(git, B);
+ }
+
+ @Test
+ public void testOnlyOption_f1_6_c() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, C);
+ prepare_f1_6(git);
+ executeAndCheck_f1_6(git, C);
+ }
+
+ @Test
+ public void testOnlyOption_f1_6_d() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, D);
+ prepare_f1_6(git);
+ executeAndCheck_f1_6(git, D);
+ }
+
+ @Test
+ public void testOnlyOption_f1_6_e() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, E);
+ prepare_f1_6(git);
+ executeAndCheck_f1_6(git, E);
+ }
+
+ @Test
+ public void testOnlyOption_f1_6_f2_14_a() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3_f2_14(git, A);
+ prepare_f1_6(git);
+ executeAndCheck_f1_6_f2_14(git, A);
+ }
+
+ @Test
+ public void testOnlyOption_f1_6_f2_14_b() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3_f2_14(git, B);
+ prepare_f1_6(git);
+ executeAndCheck_f1_6_f2_14(git, B);
+ }
+
+ @Test
+ public void testOnlyOption_f1_6_f2_14_c() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3_f2_14(git, C);
+ prepare_f1_6(git);
+ executeAndCheck_f1_6_f2_14(git, C);
+ }
+
+ @Test
+ public void testOnlyOption_f1_6_f2_14_d() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3_f2_14(git, D);
+ prepare_f1_6(git);
+ executeAndCheck_f1_6_f2_14(git, D);
+ }
+
+ @Test
+ public void testOnlyOption_f1_6_f2_14_e() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3_f2_14(git, E);
+ prepare_f1_6(git);
+ executeAndCheck_f1_6_f2_14(git, E);
+ }
+
+ @Test
+ public void testOnlyOption_f1_7_a() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, A);
+ prepare_f1_7(git);
+ executeAndCheck_f1_7(git, A);
+ }
+
+ @Test
+ public void testOnlyOption_f1_7_b() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, B);
+ prepare_f1_7(git);
+ executeAndCheck_f1_7(git, B);
+ }
+
+ @Test
+ public void testOnlyOption_f1_7_c() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, C);
+ prepare_f1_7(git);
+ executeAndCheck_f1_7(git, C);
+ }
+
+ @Test
+ public void testOnlyOption_f1_7_d() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, D);
+ prepare_f1_7(git);
+ executeAndCheck_f1_7(git, D);
+ }
+
+ @Test
+ public void testOnlyOption_f1_7_e() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, E);
+ prepare_f1_7(git);
+ executeAndCheck_f1_7(git, E);
+ }
+
+ @Test
+ public void testOnlyOption_f1_7_f2_14_a() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3_f2_14(git, A);
+ prepare_f1_7(git);
+ executeAndCheck_f1_7_f2_14(git, A);
+ }
+
+ @Test
+ public void testOnlyOption_f1_7_f2_14_b() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3_f2_14(git, B);
+ prepare_f1_7(git);
+ executeAndCheck_f1_7_f2_14(git, B);
+ }
+
+ @Test
+ public void testOnlyOption_f1_7_f2_14_c() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3_f2_14(git, C);
+ prepare_f1_7(git);
+ executeAndCheck_f1_7_f2_14(git, C);
+ }
+
+ @Test
+ public void testOnlyOption_f1_7_f2_14_d() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3_f2_14(git, D);
+ prepare_f1_7(git);
+ executeAndCheck_f1_7_f2_14(git, D);
+ }
+
+ @Test
+ public void testOnlyOption_f1_7_f2_14_e() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3_f2_14(git, E);
+ prepare_f1_7(git);
+ executeAndCheck_f1_7_f2_14(git, E);
+ }
+
+ @Test
+ public void testOnlyOption_f1_8_a() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, A);
+ prepare_f1_8(git);
+ executeAndCheck_f1_8(git, A);
+ }
+
+ @Test
+ public void testOnlyOption_f1_8_b() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, B);
+ prepare_f1_8(git);
+ executeAndCheck_f1_8(git, B);
+ }
+
+ @Test
+ public void testOnlyOption_f1_8_c() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, C);
+ prepare_f1_8(git);
+ executeAndCheck_f1_8(git, C);
+ }
+
+ @Test
+ public void testOnlyOption_f1_8_d() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, D);
+ prepare_f1_8(git);
+ executeAndCheck_f1_8(git, D);
+ }
+
+ @Test
+ public void testOnlyOption_f1_8_e() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, E);
+ prepare_f1_8(git);
+ executeAndCheck_f1_8(git, E);
+ }
+
+ @Test
+ public void testOnlyOption_f1_9_a() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, A);
+ prepare_f1_9(git);
+ executeAndCheck_f1_9(git, A);
+ }
+
+ @Test
+ public void testOnlyOption_f1_9_b() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, B);
+ prepare_f1_9(git);
+ executeAndCheck_f1_9(git, B);
+ }
+
+ @Test
+ public void testOnlyOption_f1_9_c() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, C);
+ prepare_f1_9(git);
+ executeAndCheck_f1_9(git, C);
+ }
+
+ @Test
+ public void testOnlyOption_f1_9_d() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, D);
+ prepare_f1_9(git);
+ executeAndCheck_f1_9(git, D);
+ }
+
+ @Test
+ public void testOnlyOption_f1_9_e() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, E);
+ prepare_f1_9(git);
+ executeAndCheck_f1_9(git, E);
+ }
+
+ @Test
+ public void testOnlyOption_f1_10_a() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, A);
+ prepare_f1_10(git);
+ executeAndCheck_f1_10(git, A);
+ }
+
+ @Test
+ public void testOnlyOption_f1_10_b() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, B);
+ prepare_f1_10(git);
+ executeAndCheck_f1_10(git, B);
+ }
+
+ @Test
+ public void testOnlyOption_f1_10_c() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, C);
+ prepare_f1_10(git);
+ executeAndCheck_f1_10(git, C);
+ }
+
+ @Test
+ public void testOnlyOption_f1_10_d() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, D);
+ prepare_f1_10(git);
+ executeAndCheck_f1_10(git, D);
+ }
+
+ @Test
+ public void testOnlyOption_f1_10_e() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, E);
+ prepare_f1_10(git);
+ executeAndCheck_f1_10(git, E);
+ }
+
+ @Test
+ public void testOnlyOption_f1_11_a() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, A);
+ prepare_f1_11(git);
+ executeAndCheck_f1_11(git, A);
+ }
+
+ @Test
+ public void testOnlyOption_f1_11_b() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, B);
+ prepare_f1_11(git);
+ executeAndCheck_f1_11(git, B);
+ }
+
+ @Test
+ public void testOnlyOption_f1_11_c() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, C);
+ prepare_f1_11(git);
+ executeAndCheck_f1_11(git, C);
+ }
+
+ @Test
+ public void testOnlyOption_f1_11_d() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, D);
+ prepare_f1_11(git);
+ executeAndCheck_f1_11(git, D);
+ }
+
+ @Test
+ public void testOnlyOption_f1_11_e() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, E);
+ prepare_f1_11(git);
+ executeAndCheck_f1_11(git, E);
+ }
+
+ @Test
+ public void testOnlyOption_f1_12_a() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, A);
+ prepare_f1_12(git);
+ executeAndCheck_f1_12(git, A);
+ }
+
+ @Test
+ public void testOnlyOption_f1_12_b() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, B);
+ prepare_f1_12(git);
+ executeAndCheck_f1_12(git, B);
+ }
+
+ @Test
+ public void testOnlyOption_f1_12_c() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, C);
+ prepare_f1_12(git);
+ executeAndCheck_f1_12(git, C);
+ }
+
+ @Test
+ public void testOnlyOption_f1_12_d() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, D);
+ prepare_f1_12(git);
+ executeAndCheck_f1_12(git, D);
+ }
+
+ @Test
+ public void testOnlyOption_f1_12_e() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, E);
+ prepare_f1_12(git);
+ executeAndCheck_f1_12(git, E);
+ }
+
+ @Test
+ public void testOnlyOption_f1_12_f2_14_a() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3_f2_14(git, A);
+ prepare_f1_12(git);
+ executeAndCheck_f1_12_f2_14(git, A);
+ }
+
+ @Test
+ public void testOnlyOption_f1_12_f2_14_b() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3_f2_14(git, B);
+ prepare_f1_12(git);
+ executeAndCheck_f1_12_f2_14(git, B);
+ }
+
+ @Test
+ public void testOnlyOption_f1_12_f2_14_c() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3_f2_14(git, C);
+ prepare_f1_12(git);
+ executeAndCheck_f1_12_f2_14(git, C);
+ }
+
+ @Test
+ public void testOnlyOption_f1_12_f2_14_d() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3_f2_14(git, D);
+ prepare_f1_12(git);
+ executeAndCheck_f1_12_f2_14(git, D);
+ }
+
+ @Test
+ public void testOnlyOption_f1_12_f2_14_e() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3_f2_14(git, E);
+ prepare_f1_12(git);
+ executeAndCheck_f1_12_f2_14(git, E);
+ }
+
+ @Test
+ public void testOnlyOption_f1_13_a() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, A);
+ prepare_f1_13(git);
+ executeAndCheck_f1_13(git, A);
+ }
+
+ @Test
+ public void testOnlyOption_f1_13_b() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, B);
+ prepare_f1_13(git);
+ executeAndCheck_f1_13(git, B);
+ }
+
+ @Test
+ public void testOnlyOption_f1_13_c() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, C);
+ prepare_f1_13(git);
+ executeAndCheck_f1_13(git, C);
+ }
+
+ @Test
+ public void testOnlyOption_f1_13_d() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, D);
+ prepare_f1_13(git);
+ executeAndCheck_f1_13(git, D);
+ }
+
+ @Test
+ public void testOnlyOption_f1_13_e() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, E);
+ prepare_f1_13(git);
+ executeAndCheck_f1_13(git, E);
+ }
+
+ @Test
+ public void testOnlyOption_f1_14_a() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, A);
+ prepare_f1_14(git);
+ executeAndCheck_f1_14(git, A);
+ }
+
+ @Test
+ public void testOnlyOption_f1_14_b() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, B);
+ prepare_f1_14(git);
+ executeAndCheck_f1_14(git, B);
+ }
+
+ @Test
+ public void testOnlyOption_f1_14_c() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, C);
+ prepare_f1_14(git);
+ executeAndCheck_f1_14(git, C);
+ }
+
+ @Test
+ public void testOnlyOption_f1_14_d() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, D);
+ prepare_f1_14(git);
+ executeAndCheck_f1_14(git, D);
+ }
+
+ @Test
+ public void testOnlyOption_f1_14_e() throws Exception {
+ final Git git = new Git(db);
+ prepare_f3(git, E);
+ prepare_f1_14(git);
+ executeAndCheck_f1_14(git, E);
+ }
+
+ @Test
+ public void testOnlyOptionWithDirectory() throws Exception {
+ final Git git = new Git(db);
+
+ // write files
+ final File f1 = writeTrashFile("d1/d2/f1.txt", "c1");
+ writeTrashFile("d1/d2/f2.txt", "c2");
+ final File f3 = writeTrashFile("d1/f3.txt", "c3");
+ writeTrashFile("d1/f4.txt", "c4");
+ final File f5 = writeTrashFile("d3/d4/f5.txt", "c5");
+ writeTrashFile("d3/d4/f6.txt", "c6");
+ final File f7 = writeTrashFile("d3/f7.txt", "c7");
+ writeTrashFile("d3/f8.txt", "c8");
+ final File f9 = writeTrashFile("d5/f9.txt", "c9");
+ writeTrashFile("d5/f10.txt", "c10");
+ final File f11 = writeTrashFile("d6/f11.txt", "c11");
+ writeTrashFile("d6/f12.txt", "c12");
+
+ // add files
+ git.add().addFilepattern(".").call();
+
+ // modify files, but do not stage changes
+ write(f1, "c1'");
+ write(f3, "c3'");
+ write(f5, "c5'");
+ write(f7, "c7'");
+ write(f9, "c9'");
+ write(f11, "c11'");
+
+ // commit selected files only
+ git.commit().setOnly("d1").setOnly("d3/d4/").setOnly("d5")
+ .setOnly("d6/f11.txt").setMessage(MSG).call();
+
+ assertEquals("c1'", getHead(git, "d1/d2/f1.txt"));
+ assertEquals("c2", getHead(git, "d1/d2/f2.txt"));
+ assertEquals("c3'", getHead(git, "d1/f3.txt"));
+ assertEquals("c4", getHead(git, "d1/f4.txt"));
+ assertEquals("c5'", getHead(git, "d3/d4/f5.txt"));
+ assertEquals("c6", getHead(git, "d3/d4/f6.txt"));
+ assertEquals("", getHead(git, "d3/f7.txt"));
+ assertEquals("", getHead(git, "d3/f8.txt"));
+ assertEquals("c9'", getHead(git, "d5/f9.txt"));
+ assertEquals("c10", getHead(git, "d5/f10.txt"));
+ assertEquals("c11'", getHead(git, "d6/f11.txt"));
+ assertEquals("", getHead(git, "d6/f12.txt"));
+ assertEquals("[d1/d2/f1.txt, mode:100644, content:c1']"
+ + "[d1/d2/f2.txt, mode:100644, content:c2]"
+ + "[d1/f3.txt, mode:100644, content:c3']"
+ + "[d1/f4.txt, mode:100644, content:c4]"
+ + "[d3/d4/f5.txt, mode:100644, content:c5']"
+ + "[d3/d4/f6.txt, mode:100644, content:c6]"
+ + "[d3/f7.txt, mode:100644, content:c7]"
+ + "[d3/f8.txt, mode:100644, content:c8]"
+ + "[d5/f10.txt, mode:100644, content:c10]"
+ + "[d5/f9.txt, mode:100644, content:c9']"
+ + "[d6/f11.txt, mode:100644, content:c11']"
+ + "[d6/f12.txt, mode:100644, content:c12]", indexState(CONTENT));
+ }
+
+ @SuppressWarnings("unused")
+ private File prepare_f1_1(final Git git) throws IOException {
+ return writeTrashFile(F1, "c1");
+ }
+
+ private File prepare_f1_2(final Git git) throws Exception {
+ final File f1 = prepare_f1_4(git);
+ f1.delete();
+ return f1;
+ }
+
+ private File prepare_f1_3(final Git git) throws Exception {
+ final File f1 = prepare_f1_7(git);
+ git.rm().addFilepattern(F1).call();
+ return f1;
+ }
+
+ private File prepare_f1_4(final Git git) throws Exception {
+ final File f1 = prepare_f1_1(git);
+ git.add().addFilepattern(F1).call();
+ return f1;
+ }
+
+ private File prepare_f1_5(final Git git) throws Exception {
+ final File f1 = prepare_f1_7(git);
+ f1.delete();
+ return f1;
+ }
+
+ private File prepare_f1_6(final Git git) throws Exception {
+ final File f1 = prepare_f1_3(git);
+ write(f1, "c1");
+ return f1;
+ }
+
+ private File prepare_f1_7(final Git git) throws Exception {
+ final File f1 = prepare_f1_4(git);
+ git.commit().setOnly(F1).setMessage(MSG).call();
+ return f1;
+ }
+
+ private File prepare_f1_8(final Git git) throws Exception {
+ final File f1 = prepare_f1_4(git);
+ write(f1, "c1'");
+ return f1;
+ }
+
+ private File prepare_f1_9(final Git git) throws Exception {
+ final File f1 = prepare_f1_3(git);
+ write(f1, "c1'");
+ return f1;
+ }
+
+ private File prepare_f1_10(final Git git) throws Exception {
+ final File f1 = prepare_f1_9(git);
+ git.add().addFilepattern(F1).call();
+ f1.delete();
+ return f1;
+ }
+
+ private File prepare_f1_11(final Git git) throws Exception {
+ final File f1 = prepare_f1_7(git);
+ write(f1, "c1'");
+ return f1;
+ }
+
+ private File prepare_f1_12(final Git git) throws Exception {
+ final File f1 = prepare_f1_13(git);
+ write(f1, "c1");
+ return f1;
+ }
+
+ private File prepare_f1_13(final Git git) throws Exception {
+ final File f1 = prepare_f1_11(git);
+ git.add().addFilepattern(F1).call();
+ return f1;
+ }
+
+ private File prepare_f1_14(final Git git) throws Exception {
+ final File f1 = prepare_f1_13(git);
+ write(f1, "c1''");
+ return f1;
+ }
+
+ @SuppressWarnings("null")
+ private void executeAndCheck_f1_1(final Git git, final int state)
+ throws Exception {
+ JGitInternalException exception = null;
+ try {
+ git.commit().setOnly(F1).setMessage(MSG).call();
+ } catch (JGitInternalException e) {
+ exception = e;
+ }
+ assertNotNull(exception);
+ assertTrue(exception.getMessage().contains(F1));
+
+ assertEquals(expected_f3_head(state), getHead(git, F3));
+ assertEquals(expected_f3_idx(state), indexState(CONTENT));
+ }
+
+ @SuppressWarnings("null")
+ private void executeAndCheck_f1_1_f2_f14(final Git git, final int state)
+ throws Exception {
+ JGitInternalException exception = null;
+ try {
+ git.commit().setOnly(F1).setOnly(F2).setMessage(MSG).call();
+ } catch (JGitInternalException e) {
+ exception = e;
+ }
+ assertNotNull(exception);
+ assertTrue(exception.getMessage().contains(F1));
+
+ assertEquals("c2", getHead(git, F2));
+ assertEquals(expected_f3_head(state), getHead(git, F3));
+ assertEquals("[f2.txt, mode:100644, content:c2']"
+ + expected_f3_idx(state), indexState(CONTENT));
+ }
+
+ @SuppressWarnings("null")
+ private void executeAndCheck_f1_2(final Git git, final int state)
+ throws Exception {
+ JGitInternalException exception = null;
+ try {
+ git.commit().setOnly(F1).setMessage(MSG).call();
+ } catch (JGitInternalException e) {
+ exception = e;
+ }
+ assertNotNull(exception);
+ assertTrue(exception.getMessage().contains("No changes"));
+
+ assertEquals(expected_f3_head(state), getHead(git, F3));
+ assertEquals("[f1.txt, mode:100644, content:c1]"
+ + expected_f3_idx(state), indexState(CONTENT));
+ }
+
+ private void executeAndCheck_f1_2_f2_f14(final Git git, final int state)
+ throws Exception {
+ git.commit().setOnly(F1).setOnly(F2).setMessage(MSG).call();
+
+ assertEquals("", getHead(git, F1));
+ assertEquals("c2''", getHead(git, F2));
+ assertEquals(expected_f3_head(state), getHead(git, F3));
+ assertEquals("[f2.txt, mode:100644, content:c2'']"
+ + expected_f3_idx(state), indexState(CONTENT));
+ }
+
+ private void executeAndCheck_f1_3(final Git git, final int state)
+ throws Exception {
+ git.commit().setOnly(F1).setMessage(MSG).call();
+
+ assertEquals("", getHead(git, F1));
+ assertEquals(expected_f3_head(state), getHead(git, F3));
+ assertEquals(expected_f3_idx(state), indexState(CONTENT));
+ }
+
+ private void executeAndCheck_f1_4(final Git git, final int state)
+ throws Exception {
+ git.commit().setOnly(F1).setMessage(MSG).call();
+
+ assertEquals("c1", getHead(git, F1));
+ assertEquals(expected_f3_head(state), getHead(git, F3));
+ assertEquals("[f1.txt, mode:100644, content:c1]"
+ + expected_f3_idx(state), indexState(CONTENT));
+ }
+
+ private void executeAndCheck_f1_5(final Git git, final int state)
+ throws Exception {
+ executeAndCheck_f1_3(git, state);
+ }
+
+ @SuppressWarnings("null")
+ private void executeAndCheck_f1_6(final Git git, final int state)
+ throws Exception {
+ JGitInternalException exception = null;
+ try {
+ git.commit().setOnly(F1).setMessage(MSG).call();
+ } catch (JGitInternalException e) {
+ exception = e;
+ }
+ assertNotNull(exception);
+ assertTrue(exception.getMessage().contains("No changes"));
+
+ assertEquals(expected_f3_head(state), getHead(git, F3));
+ assertEquals(expected_f3_idx(state), indexState(CONTENT));
+ }
+
+ private void executeAndCheck_f1_6_f2_14(final Git git, final int state)
+ throws Exception {
+ git.commit().setOnly(F1).setOnly(F2).setMessage(MSG).call();
+
+ assertEquals("c1", getHead(git, F1));
+ assertEquals("c2''", getHead(git, F2));
+ assertEquals(expected_f3_head(state), getHead(git, F3));
+ assertEquals("[f1.txt, mode:100644, content:c1]"
+ + "[f2.txt, mode:100644, content:c2'']"
+ + expected_f3_idx(state), indexState(CONTENT));
+ }
+
+ private void executeAndCheck_f1_7(final Git git, final int state)
+ throws Exception {
+ executeAndCheck_f1_2(git, state);
+ }
+
+ private void executeAndCheck_f1_7_f2_14(final Git git, final int state)
+ throws Exception {
+ executeAndCheck_f1_6_f2_14(git, state);
+ }
+
+ private void executeAndCheck_f1_8(final Git git, final int state)
+ throws Exception {
+ git.commit().setOnly(F1).setMessage(MSG).call();
+
+ assertEquals("c1'", getHead(git, F1));
+ assertEquals(expected_f3_head(state), getHead(git, F3));
+ assertEquals("[f1.txt, mode:100644, content:c1']"
+ + expected_f3_idx(state), indexState(CONTENT));
+ }
+
+ private void executeAndCheck_f1_9(final Git git, final int state)
+ throws Exception {
+ executeAndCheck_f1_8(git, state);
+ }
+
+ private void executeAndCheck_f1_10(final Git git, final int state)
+ throws Exception {
+ executeAndCheck_f1_3(git, state);
+ }
+
+ private void executeAndCheck_f1_11(final Git git, final int state)
+ throws Exception {
+ executeAndCheck_f1_8(git, state);
+ }
+
+ @SuppressWarnings("null")
+ private void executeAndCheck_f1_12(final Git git, final int state)
+ throws Exception {
+ JGitInternalException exception = null;
+ try {
+ git.commit().setOnly(F1).setMessage(MSG).call();
+ } catch (JGitInternalException e) {
+ exception = e;
+ }
+ assertNotNull(exception);
+ assertTrue(exception.getMessage().contains("No changes"));
+
+ assertEquals(expected_f3_head(state), getHead(git, F3));
+ assertEquals("[f1.txt, mode:100644, content:c1']"
+ + expected_f3_idx(state), indexState(CONTENT));
+ }
+
+ private void executeAndCheck_f1_12_f2_14(final Git git, final int state)
+ throws Exception {
+ executeAndCheck_f1_6_f2_14(git, state);
+ }
+
+ private void executeAndCheck_f1_13(final Git git, final int state)
+ throws Exception {
+ executeAndCheck_f1_8(git, state);
+ }
+
+ private void executeAndCheck_f1_14(final Git git, final int state)
+ throws Exception {
+ git.commit().setOnly(F1).setMessage(MSG).call();
+
+ assertEquals("c1''", getHead(git, F1));
+ assertEquals(expected_f3_head(state), getHead(git, F3));
+ assertEquals("[f1.txt, mode:100644, content:c1'']"
+ + expected_f3_idx(state), indexState(CONTENT));
+ }
+
+ private void prepare_f3(final Git git, final int state) throws Exception {
+ prepare_f3_f2_14(git, state, false);
+ }
+
+ private void prepare_f3_f2_14(final Git git, final int state)
+ throws Exception {
+ prepare_f3_f2_14(git, state, true);
+ }
+
+ private void prepare_f3_f2_14(final Git git, final int state,
+ final boolean include_f2) throws Exception {
+ File f2 = null;
+ if (include_f2) {
+ f2 = writeTrashFile(F2, "c2");
+ git.add().addFilepattern(F2).call();
+ git.commit().setMessage(MSG).call();
+ }
+
+ if (state >= 1) {
+ writeTrashFile(F3, "c3");
+ git.add().addFilepattern(F3).call();
+ }
+ if (state >= 2)
+ git.commit().setMessage(MSG).call();
+ if (state >= 3)
+ git.rm().addFilepattern(F3).call();
+ if (state == 4) {
+ writeTrashFile(F3, "c3'");
+ git.add().addFilepattern(F3).call();
+ }
+
+ if (include_f2) {
+ write(f2, "c2'");
+ git.add().addFilepattern(F2).call();
+ write(f2, "c2''");
+ }
+ }
+
+ private String expected_f3_head(final int state) {
+ switch (state) {
+ case 0:
+ case 1:
+ return "";
+ case 2:
+ case 3:
+ case 4:
+ return "c3";
+ }
+ return null;
+ }
+
+ private String expected_f3_idx(final int state) {
+ switch (state) {
+ case 0:
+ case 3:
+ return "";
+ case 1:
+ case 2:
+ return "[f3.txt, mode:100644, content:c3]";
+ case 4:
+ return "[f3.txt, mode:100644, content:c3']";
+ }
+ return null;
+ }
+
+ private String getHead(final Git git, final String path) throws Exception {
+ try {
+ final Repository repo = git.getRepository();
+ final ObjectId headId = repo.resolve(Constants.HEAD + "^{commit}");
+ final TreeWalk tw = TreeWalk.forPath(repo, path,
+ new RevWalk(repo).parseTree(headId));
+ return new String(tw.getObjectReader().open(tw.getObjectId(0))
+ .getBytes());
+ } catch (Exception e) {
+ return "";
+ }
+ }
}
diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties
index b2d9937..f96d426 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties
@@ -153,6 +153,7 @@ duplicateRef=Duplicate ref: {0}
duplicateRemoteRefUpdateIsIllegal=Duplicate remote ref update is illegal. Affected remote name: {0}
duplicateStagesNotAllowed=Duplicate stages not allowed
eitherGitDirOrWorkTreeRequired=One of setGitDir or setWorkTree must be called.
+emptyCommit=No changes
emptyPathNotPermitted=Empty path not permitted.
encryptionError=Encryption error: {0}
endOfFileInEscape=End of file in escape
@@ -207,6 +208,7 @@ hunkBelongsToAnotherFile=Hunk belongs to another file
hunkDisconnectedFromFile=Hunk disconnected from file
hunkHeaderDoesNotMatchBodyLineCountOf=Hunk header {0} does not match body line count of {1}
illegalArgumentNotA=Not {0}
+illegalCombinationOfArguments=The combination of arguments {0} and {1} is not allowed
illegalStateExists=exists {0}
improperlyPaddedBase64Input=Improperly padded Base64 input.
inMemoryBufferLimitExceeded=In-memory buffer limit exceeded
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java
index 7265db8..9ef2cd9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java
@@ -213,6 +213,7 @@ public class JGitText extends TranslationBundle {
/***/ public String duplicateRemoteRefUpdateIsIllegal;
/***/ public String duplicateStagesNotAllowed;
/***/ public String eitherGitDirOrWorkTreeRequired;
+ /***/ public String emptyCommit;
/***/ public String emptyPathNotPermitted;
/***/ public String encryptionError;
/***/ public String endOfFileInEscape;
@@ -267,6 +268,7 @@ public class JGitText extends TranslationBundle {
/***/ public String hunkDisconnectedFromFile;
/***/ public String hunkHeaderDoesNotMatchBodyLineCountOf;
/***/ public String illegalArgumentNotA;
+ /***/ public String illegalCombinationOfArguments;
/***/ public String illegalStateExists;
/***/ public String improperlyPaddedBase64Input;
/***/ public String inMemoryBufferLimitExceeded;
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 8ebee49..8d9ce98 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
@@ -43,7 +43,9 @@
package org.eclipse.jgit.api;
import java.io.IOException;
+import java.io.InputStream;
import java.text.MessageFormat;
+import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
@@ -55,6 +57,12 @@ import org.eclipse.jgit.api.errors.NoHeadException;
import org.eclipse.jgit.api.errors.NoMessageException;
import org.eclipse.jgit.api.errors.WrongRepositoryStateException;
import org.eclipse.jgit.dircache.DirCache;
+import org.eclipse.jgit.dircache.DirCacheBuilder;
+import org.eclipse.jgit.dircache.DirCacheEditor;
+import org.eclipse.jgit.dircache.DirCacheEditor.DeletePath;
+import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit;
+import org.eclipse.jgit.dircache.DirCacheEntry;
+import org.eclipse.jgit.dircache.DirCacheIterator;
import org.eclipse.jgit.errors.UnmergedPathException;
import org.eclipse.jgit.lib.CommitBuilder;
import org.eclipse.jgit.lib.Constants;
@@ -68,6 +76,9 @@ import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryState;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.treewalk.CanonicalTreeParser;
+import org.eclipse.jgit.treewalk.FileTreeIterator;
+import org.eclipse.jgit.treewalk.TreeWalk;
/**
* A class used to execute a {@code Commit} command. It has setters for all
@@ -87,6 +98,10 @@ public class CommitCommand extends GitCommand<RevCommit> {
private boolean all;
+ private List<String> only = new ArrayList<String>();
+
+ private boolean[] onlyProcessed;
+
private boolean amend;
/**
@@ -170,6 +185,9 @@ public class CommitCommand extends GitCommand<RevCommit> {
// lock the index
DirCache index = repo.lockDirCache();
try {
+ if (!only.isEmpty())
+ index = createTemporaryIndex(headId, index);
+
ObjectInserter odi = repo.newObjectInserter();
try {
// Write the index as tree to the object database. This may
@@ -241,6 +259,165 @@ public class CommitCommand extends GitCommand<RevCommit> {
}
}
+ private DirCache createTemporaryIndex(ObjectId headId, DirCache index)
+ throws IOException {
+ ObjectInserter inserter = null;
+
+ // get DirCacheEditor to modify the index if required
+ DirCacheEditor dcEditor = index.editor();
+
+ // get DirCacheBuilder for newly created in-core index to build a
+ // temporary index for this commit
+ DirCache inCoreIndex = DirCache.newInCore();
+ DirCacheBuilder dcBuilder = inCoreIndex.builder();
+
+ onlyProcessed = new boolean[only.size()];
+ boolean emptyCommit = true;
+
+ TreeWalk treeWalk = new TreeWalk(repo);
+ int dcIdx = treeWalk.addTree(new DirCacheIterator(index));
+ int fIdx = treeWalk.addTree(new FileTreeIterator(repo));
+ int hIdx = -1;
+ if (headId != null)
+ hIdx = treeWalk.addTree(new RevWalk(repo).parseTree(headId));
+ treeWalk.setRecursive(true);
+
+ while (treeWalk.next()) {
+ String path = treeWalk.getPathString();
+ // check if current entry's path matches a specified path
+ int pos = lookupOnly(path);
+
+ CanonicalTreeParser hTree = null;
+ if (hIdx != -1)
+ hTree = treeWalk.getTree(hIdx, CanonicalTreeParser.class);
+
+ if (pos >= 0) {
+ // include entry in commit
+
+ DirCacheIterator dcTree = treeWalk.getTree(dcIdx,
+ DirCacheIterator.class);
+ FileTreeIterator fTree = treeWalk.getTree(fIdx,
+ FileTreeIterator.class);
+
+ // check if entry refers to a tracked file
+ boolean tracked = dcTree != null || hTree != null;
+ if (!tracked)
+ break;
+
+ if (fTree != null) {
+ // create a new DirCacheEntry with data retrieved from disk
+ final DirCacheEntry dcEntry = new DirCacheEntry(path);
+ long entryLength = fTree.getEntryLength();
+ dcEntry.setLength(entryLength);
+ dcEntry.setLastModified(fTree.getEntryLastModified());
+ dcEntry.setFileMode(fTree.getEntryFileMode());
+
+ boolean objectExists = (dcTree != null && fTree
+ .idEqual(dcTree))
+ || (hTree != null && fTree.idEqual(hTree));
+ if (objectExists) {
+ dcEntry.setObjectId(fTree.getEntryObjectId());
+ } else {
+ // insert object
+ if (inserter == null)
+ inserter = repo.newObjectInserter();
+
+ InputStream inputStream = fTree.openEntryStream();
+ try {
+ dcEntry.setObjectId(inserter.insert(
+ Constants.OBJ_BLOB, entryLength,
+ inputStream));
+ } finally {
+ inputStream.close();
+ }
+ }
+
+ // update index
+ dcEditor.add(new PathEdit(path) {
+ @Override
+ public void apply(DirCacheEntry ent) {
+ ent.copyMetaData(dcEntry);
+ }
+ });
+ // add to temporary in-core index
+ dcBuilder.add(dcEntry);
+
+ if (emptyCommit && (hTree == null || !hTree.idEqual(fTree)))
+ // this is a change
+ emptyCommit = false;
+ } else {
+ // if no file exists on disk, remove entry from index and
+ // don't add it to temporary in-core index
+ dcEditor.add(new DeletePath(path));
+
+ if (emptyCommit && hTree != null)
+ // this is a change
+ emptyCommit = false;
+ }
+
+ // keep track of processed path
+ onlyProcessed[pos] = true;
+ } else {
+ // add entries from HEAD for all other paths
+ if (hTree != null) {
+ // create a new DirCacheEntry with data retrieved from HEAD
+ final DirCacheEntry dcEntry = new DirCacheEntry(path);
+ dcEntry.setObjectId(hTree.getEntryObjectId());
+ dcEntry.setFileMode(hTree.getEntryFileMode());
+
+ // add to temporary in-core index
+ dcBuilder.add(dcEntry);
+ }
+ }
+ }
+
+ // there must be no unprocessed paths left at this point; otherwise an
+ // untracked or unknown path has been specified
+ for (int i = 0; i < onlyProcessed.length; i++)
+ if (!onlyProcessed[i])
+ throw new JGitInternalException(MessageFormat.format(
+ JGitText.get().entryNotFoundByPath, only.get(i)));
+
+ // there must be at least one change
+ if (emptyCommit)
+ throw new JGitInternalException(JGitText.get().emptyCommit);
+
+ // update index
+ dcEditor.commit();
+ // finish temporary in-core index used for this commit
+ dcBuilder.finish();
+ return inCoreIndex;
+ }
+
+ /**
+ * Look an entry's path up in the list of paths specified by the --only/ -o
+ * option
+ *
+ * In case the complete (file) path (e.g. "d1/d2/f1") cannot be found in
+ * <code>only</code>, lookup is also tried with (parent) directory paths
+ * (e.g. "d1/d2" and "d1").
+ *
+ * @param pathString
+ * entry's path
+ * @return the item's index in <code>only</code>; -1 if no item matches
+ */
+ private int lookupOnly(String pathString) {
+ int i = 0;
+ for (String o : only) {
+ String p = pathString;
+ while (true) {
+ if (p.equals(o))
+ return i;
+ int l = p.lastIndexOf("/");
+ if (l < 1)
+ break;
+ p = p.substring(0, l);
+ }
+ i++;
+ }
+ return -1;
+ }
+
/**
* Sets default values for not explicitly specified options. Then validates
* that all required data has been provided.
@@ -386,14 +563,20 @@ public class CommitCommand extends GitCommand<RevCommit> {
/**
* If set to true the Commit command automatically stages files that have
- * been modified and deleted, but new files you not known by the repository
- * are not affected. This corresponds to the parameter -a on the command
- * line.
+ * been modified and deleted, but new files not known by the repository are
+ * not affected. This corresponds to the parameter -a on the command line.
*
* @param all
* @return {@code this}
+ * @throws JGitInternalException
+ * in case of an illegal combination of arguments/ options
*/
public CommitCommand setAll(boolean all) {
+ checkCallable();
+ if (!only.isEmpty())
+ throw new JGitInternalException(MessageFormat.format(
+ JGitText.get().illegalCombinationOfArguments, "--all",
+ "--only"));
this.all = all;
return this;
}
@@ -407,8 +590,33 @@ public class CommitCommand extends GitCommand<RevCommit> {
* @return {@code this}
*/
public CommitCommand setAmend(boolean amend) {
+ checkCallable();
this.amend = amend;
return this;
}
+ /**
+ * Commit dedicated path only
+ *
+ * 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.
+ *
+ * @param only
+ * path to commit
+ * @return {@code this}
+ */
+ public CommitCommand setOnly(String only) {
+ checkCallable();
+ if (all)
+ throw new JGitInternalException(MessageFormat.format(
+ JGitText.get().illegalCombinationOfArguments, "--only",
+ "--all"));
+ String o = only.endsWith("/") ? only.substring(0, only.length() - 1)
+ : only;
+ // ignore duplicates
+ if (!this.only.contains(o))
+ this.only.add(o);
+ return this;
+ }
}