# This patch file was generated by NetBeans IDE
# Following Index: paths are relative to: /home/ondra/storage/netbeans/core-main
# This patch can be applied using context Tools: Patch action on respective folder.
# It uses platform neutral UTF-8 encoding and \n newlines.
# Above lines and this line are ignored by the patching process.
Index: libs.git/apichanges.xml
--- libs.git/apichanges.xml
+++ libs.git/apichanges.xml
@@ -112,6 +112,28 @@
New method for updating a reference (branch) to a new commit id.
+
+
+
+
+
+
+ - Git client accepts the parameter telling the merge command how
+ to proceed with regard to fast-forward commits. Users may require
+ either to enforce or to completely eliminate (and always create a merge commit)
+ fast-forward merges.
+ - Git Repository instance allows users to query for the current default fast-forward
+ option via a new getter method.
+
+
+
+
+
+
+
+
+
+ New method for updating a reference (branch) to a new commit id.
Index: libs.git/manifest.mf
--- libs.git/manifest.mf
+++ libs.git/manifest.mf
@@ -1,4 +1,4 @@
Manifest-Version: 1.0
OpenIDE-Module: org.netbeans.libs.git/1
OpenIDE-Module-Localizing-Bundle: org/netbeans/libs/git/Bundle.properties
-OpenIDE-Module-Specification-Version: 1.25
+OpenIDE-Module-Specification-Version: 1.26
Index: libs.git/src/org/netbeans/libs/git/GitClient.java
--- libs.git/src/org/netbeans/libs/git/GitClient.java
+++ libs.git/src/org/netbeans/libs/git/GitClient.java
@@ -53,6 +53,7 @@
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryState;
+import org.netbeans.libs.git.GitRepository.FastForwardOption;
import org.netbeans.libs.git.GitRevisionInfo.GitFileInfo;
import org.netbeans.libs.git.jgit.GitClassFactory;
import org.netbeans.libs.git.jgit.JGitCredentialsProvider;
@@ -867,7 +868,10 @@
}
/**
- * Merges a given revision with the current head
+ * Merges a given revision with the current head.
+ *
+ * Fast-forward option will default to the one stated in .git/config.
+ *
* @param revision id of a revision to merge.
* @param monitor progress monitor
* @return result of the merge
@@ -875,8 +879,22 @@
* @throws GitException an unexpected error occurs
*/
public GitMergeResult merge (String revision, ProgressMonitor monitor) throws GitException.CheckoutConflictException, GitException {
+ return merge(revision, null, monitor);
+ }
+
+ /**
+ * Merges a given revision with the current head.
+ * @param revision id of a revision to merge.
+ * @param fastForward option telling merge to enforce or disable fast forward merges.
+ * @param monitor progress monitor
+ * @return result of the merge
+ * @throws GitException.CheckoutConflictException there are local modifications in Working Tree, merge fails in such a case
+ * @throws GitException an unexpected error occurs
+ * @since 1.26
+ */
+ public GitMergeResult merge (String revision, FastForwardOption fastForward, ProgressMonitor monitor) throws GitException.CheckoutConflictException, GitException {
Repository repository = gitRepository.getRepository();
- MergeCommand cmd = new MergeCommand(repository, getClassFactory(), revision, monitor);
+ MergeCommand cmd = new MergeCommand(repository, getClassFactory(), revision, fastForward, monitor);
cmd.execute();
return cmd.getResult();
}
Index: libs.git/src/org/netbeans/libs/git/GitMergeResult.java
--- libs.git/src/org/netbeans/libs/git/GitMergeResult.java
+++ libs.git/src/org/netbeans/libs/git/GitMergeResult.java
@@ -78,6 +78,16 @@
return "Fast-forward";
}
},
+ /**
+ * Fast forward merge cannot be executed, a commit is needed.
+ * @since 1.26
+ */
+ ABORTED {
+ @Override
+ public String toString() {
+ return "Aborted";
+ }
+ },
ALREADY_UP_TO_DATE {
@Override
public String toString() {
@@ -178,8 +188,6 @@
mergeStatus = MergeResult.MergeStatus.MERGED;
} else if (mergeStatus == MergeResult.MergeStatus.MERGED_SQUASHED_NOT_COMMITTED) {
mergeStatus = MergeResult.MergeStatus.MERGED;
- } else if (mergeStatus == MergeResult.MergeStatus.ABORTED) {
- mergeStatus = MergeResult.MergeStatus.FAILED;
} else if (mergeStatus == MergeResult.MergeStatus.CHECKOUT_CONFLICT) {
mergeStatus = MergeResult.MergeStatus.CONFLICTING;
}
Index: libs.git/src/org/netbeans/libs/git/GitRepository.java
--- libs.git/src/org/netbeans/libs/git/GitRepository.java
+++ libs.git/src/org/netbeans/libs/git/GitRepository.java
@@ -45,6 +45,8 @@
import java.io.File;
import java.util.Map;
import java.util.WeakHashMap;
+import org.eclipse.jgit.api.MergeCommand;
+import org.eclipse.jgit.merge.MergeConfig;
import org.eclipse.jgit.transport.SshSessionFactory;
import org.netbeans.libs.git.jgit.JGitRepository;
import org.netbeans.libs.git.jgit.JGitSshSessionFactory;
@@ -77,7 +79,56 @@
private static final Map repositoryPool = new WeakHashMap(5);
private final File repositoryLocation;
private JGitRepository gitRepository;
+
+ /**
+ * Option specifying how to deal with merges and merge commits. Required by
+ * {@link GitClient#merge(java.lang.String, org.netbeans.libs.git.GitRepository.FastForwardOption, org.netbeans.libs.git.progress.ProgressMonitor)}.
+ * To get the repository's default value, get it with {@link #getDefaultFastForwardOption()}.
+ *
+ * @since 1.26
+ */
+ public enum FastForwardOption {
+ /**
+ * Merge will not create a new commit if possible and only update the
+ * branch reference to the merged commit. This will usually happen if
+ * the merged commit is a descendant of the branch's head commit.
+ */
+ FAST_FORWARD {
+
+ @Override
+ public String toString () {
+ return "--ff"; //NOI18N
+ }
+
+ },
+
+ /**
+ * Merge will fail if fast forward is impossible, no merge commit will
+ * be created under any circumstances.
+ */
+ FAST_FORWARD_ONLY {
+
+ @Override
+ public String toString () {
+ return "--ff-only"; //NOI18N
+ }
+
+ },
+
+ /**
+ * Will always create a merge commit even if fast forward were possible.
+ */
+ NO_FAST_FORWARD {
+
+ @Override
+ public String toString () {
+ return "--no-ff"; //NOI18N
+ }
+
+ };
+ }
+
/**
* Returns the instance of {@link GitRepository} representing an existing or not yet existing repository
* specified by the given local folder.
@@ -109,11 +160,43 @@
* @throws GitException when an error occurs while loading repository data from disk.
*/
public synchronized GitClient createClient () throws GitException {
+ getRepository();
+ return createClient(gitRepository);
+ }
+
+ /**
+ * Parses the repository configuration file and returns the default fast-forward merge
+ * option set for the repository and its current branch.
+ *
+ * @return the default fast-forward option for the current repository and the active branch.
+ * @throws GitException an error occurs
+ * @since 1.26
+ */
+ public FastForwardOption getDefaultFastForwardOption () throws GitException {
+ JGitRepository repository = getRepository();
+ repository.increaseClientUsage();
+ try {
+ MergeConfig cfg = MergeConfig.getConfigForCurrentBranch(repository.getRepository());
+ MergeCommand.FastForwardMode mode = cfg.getFastForwardMode();
+ switch (mode) {
+ case FF_ONLY:
+ return FastForwardOption.FAST_FORWARD_ONLY;
+ case NO_FF:
+ return FastForwardOption.NO_FAST_FORWARD;
+ default:
+ return FastForwardOption.FAST_FORWARD;
+ }
+ } finally {
+ repository.decreaseClientUsage();
+ }
+ }
+
+ private synchronized JGitRepository getRepository () {
if (gitRepository == null) {
gitRepository = new JGitRepository(repositoryLocation);
SshSessionFactory.setInstance(JGitSshSessionFactory.getDefault());
}
- return createClient(gitRepository);
+ return gitRepository;
}
/**
Index: libs.git/src/org/netbeans/libs/git/jgit/commands/MergeCommand.java
--- libs.git/src/org/netbeans/libs/git/jgit/commands/MergeCommand.java
+++ libs.git/src/org/netbeans/libs/git/jgit/commands/MergeCommand.java
@@ -52,6 +52,7 @@
import org.eclipse.jgit.lib.Repository;
import org.netbeans.libs.git.GitException;
import org.netbeans.libs.git.GitMergeResult;
+import org.netbeans.libs.git.GitRepository.FastForwardOption;
import org.netbeans.libs.git.jgit.GitClassFactory;
import org.netbeans.libs.git.jgit.Utils;
import org.netbeans.libs.git.progress.ProgressMonitor;
@@ -64,9 +65,12 @@
private final String revision;
private GitMergeResult result;
private String commitMessage;
+ private final FastForwardOption ffOption;
- public MergeCommand (Repository repository, GitClassFactory gitFactory, String revision, ProgressMonitor monitor) {
+ public MergeCommand (Repository repository, GitClassFactory gitFactory, String revision,
+ FastForwardOption ffOption, ProgressMonitor monitor) {
super(repository, gitFactory, monitor);
+ this.ffOption = ffOption;
this.revision = revision;
}
@@ -74,6 +78,7 @@
protected void run () throws GitException {
Repository repository = getRepository();
org.eclipse.jgit.api.MergeCommand command = new Git(repository).merge();
+ setFastForward(command);
Ref ref = null;
try {
ref = repository.getRef(revision);
@@ -106,7 +111,11 @@
@Override
protected String getCommandDescription () {
- return new StringBuilder("git merge ").append(revision).toString(); //NOI18N
+ StringBuilder sb = new StringBuilder("git merge "); //NOI18N
+ if (ffOption != null) {
+ sb.append(ffOption).append(" "); //NOI18N
+ }
+ return sb.append(revision).toString();
}
public GitMergeResult getResult () {
@@ -127,4 +136,22 @@
}
throw new GitException(original);
}
+
+ private void setFastForward (org.eclipse.jgit.api.MergeCommand cmd) {
+ if (ffOption == null) {
+ // will fall back on the config default
+ return;
+ }
+ switch (ffOption) {
+ case FAST_FORWARD:
+ cmd.setFastForward(org.eclipse.jgit.api.MergeCommand.FastForwardMode.FF);
+ break;
+ case FAST_FORWARD_ONLY:
+ cmd.setFastForward(org.eclipse.jgit.api.MergeCommand.FastForwardMode.FF_ONLY);
+ break;
+ case NO_FAST_FORWARD:
+ cmd.setFastForward(org.eclipse.jgit.api.MergeCommand.FastForwardMode.NO_FF);
+ break;
+ }
+ }
}
Index: libs.git/src/org/netbeans/libs/git/jgit/commands/PullCommand.java
--- libs.git/src/org/netbeans/libs/git/jgit/commands/PullCommand.java
+++ libs.git/src/org/netbeans/libs/git/jgit/commands/PullCommand.java
@@ -85,7 +85,7 @@
fetch.setCredentialsProvider(getCredentialsProvider());
fetch.run();
this.updates = fetch.getUpdates();
- MergeCommand merge = new MergeCommand(getRepository(), getClassFactory(), branchToMerge, monitor);
+ MergeCommand merge = new MergeCommand(getRepository(), getClassFactory(), branchToMerge, null, monitor);
merge.setCommitMessage("branch \'" + findRemoteBranchName() + "\' of " + fetch.getResult().getURI().setUser(null).setPass(null).toString());
merge.run();
this.mergeResult = merge.getResult();
Index: libs.git/test/unit/src/org/netbeans/libs/git/jgit/commands/MergeTest.java
--- libs.git/test/unit/src/org/netbeans/libs/git/jgit/commands/MergeTest.java
+++ libs.git/test/unit/src/org/netbeans/libs/git/jgit/commands/MergeTest.java
@@ -56,6 +56,7 @@
import org.netbeans.libs.git.GitException;
import org.netbeans.libs.git.GitMergeResult;
import org.netbeans.libs.git.GitMergeResult.MergeStatus;
+import org.netbeans.libs.git.GitRepository;
import org.netbeans.libs.git.GitRevisionInfo;
import org.netbeans.libs.git.GitTransportUpdate;
import org.netbeans.libs.git.SearchCriteria;
@@ -381,4 +382,89 @@
client.checkoutRevision(Constants.MASTER, true, NULL_PROGRESS_MONITOR);
client.merge(BRANCH_NAME, NULL_PROGRESS_MONITOR);
}
+
+ public void testMergeNoFastForward () throws Exception {
+ File f = new File(workDir, "file");
+ write(f, "init");
+ add(f);
+ commit(f);
+
+ GitClient client = getClient(workDir);
+ client.createBranch(BRANCH_NAME, Constants.MASTER, NULL_PROGRESS_MONITOR);
+ client.checkoutRevision(BRANCH_NAME, true, NULL_PROGRESS_MONITOR);
+ write(f, BRANCH_NAME);
+ add(f);
+ GitRevisionInfo info = client.commit(new File[] { f }, "change on branch", null, null, NULL_PROGRESS_MONITOR);
+ client.checkoutRevision(Constants.MASTER, true, NULL_PROGRESS_MONITOR);
+
+ assertEquals("init", read(f));
+
+ GitMergeResult result = client.merge(BRANCH_NAME, NULL_PROGRESS_MONITOR);
+ assertEquals(MergeStatus.FAST_FORWARD, result.getMergeStatus());
+ assertEquals(BRANCH_NAME, read(f));
+
+ SearchCriteria crit = new SearchCriteria();
+ crit.setRevisionTo(Constants.MASTER);
+ GitRevisionInfo[] logs = client.log(crit, NULL_PROGRESS_MONITOR);
+ assertEquals(2, logs.length);
+ assertEquals(logs[0].getRevision(), info.getRevision());
+
+ // continue working on branch
+ client.checkoutRevision(BRANCH_NAME, true, NULL_PROGRESS_MONITOR);
+ remove(false, f);
+ client.commit(new File[] { f }, "delete on branch", null, null, NULL_PROGRESS_MONITOR);
+ client.checkoutRevision(Constants.MASTER, true, NULL_PROGRESS_MONITOR);
+
+ assertEquals(BRANCH_NAME, read(f));
+
+ result = client.merge(BRANCH_NAME, GitRepository.FastForwardOption.NO_FAST_FORWARD, NULL_PROGRESS_MONITOR);
+ assertEquals(MergeStatus.MERGED, result.getMergeStatus());
+ assertFalse(f.exists());
+
+ crit = new SearchCriteria();
+ crit.setRevisionTo(Constants.MASTER);
+ logs = client.log(crit, NULL_PROGRESS_MONITOR);
+ assertEquals(4, logs.length);
+ assertEquals(2, logs[0].getParents().length);
+ }
+
+ public void testMergeFFOnly () throws Exception {
+ File f1 = new File(workDir, "file1");
+ File f2 = new File(workDir, "file2");
+ write(f1, "init");
+ write(f2, "init");
+ add(f1, f2);
+ commit(f1, f2);
+
+ GitClient client = getClient(workDir);
+ client.createBranch(BRANCH_NAME, Constants.MASTER, NULL_PROGRESS_MONITOR);
+ client.checkoutRevision(BRANCH_NAME, true, NULL_PROGRESS_MONITOR);
+ write(f1, BRANCH_NAME);
+ add(f1);
+ client.commit(new File[] { f1 }, "change on branch", null, null, NULL_PROGRESS_MONITOR);
+ client.checkoutRevision(Constants.MASTER, true, NULL_PROGRESS_MONITOR);
+ write(f2, "another change");
+ add(f2);
+ client.commit(new File[] { f2 }, "change on master", null, null, NULL_PROGRESS_MONITOR);
+
+ GitMergeResult result = client.merge(BRANCH_NAME, GitRepository.FastForwardOption.FAST_FORWARD_ONLY, NULL_PROGRESS_MONITOR);
+ // no merge commits allowed => FAIL
+ assertEquals(MergeStatus.ABORTED, result.getMergeStatus());
+
+ // test also config files
+ assertEquals(GitRepository.FastForwardOption.FAST_FORWARD, GitRepository.getInstance(workDir).getDefaultFastForwardOption());
+
+ StoredConfig cfg = repo.getConfig();
+ cfg.setEnum(ConfigConstants.CONFIG_KEY_MERGE, null,
+ ConfigConstants.CONFIG_KEY_FF, org.eclipse.jgit.api.MergeCommand.FastForwardMode.Merge.ONLY);
+ cfg.save();
+ assertEquals(GitRepository.FastForwardOption.FAST_FORWARD_ONLY, GitRepository.getInstance(workDir).getDefaultFastForwardOption());
+ result = client.merge(BRANCH_NAME, NULL_PROGRESS_MONITOR);
+ // no merge commits allowed => FAIL
+ assertEquals(MergeStatus.ABORTED, result.getMergeStatus());
+
+ result = client.merge(BRANCH_NAME, GitRepository.FastForwardOption.FAST_FORWARD, NULL_PROGRESS_MONITOR);
+ // merge commits allowed => OK
+ assertEquals(MergeStatus.MERGED, result.getMergeStatus());
+ }
}