]> source.dussan.org Git - gitblit.git/commitdiff
Add integration strategy to merge tickes fast-forward or with commit.
authorFlorian Zschocke <florian.zschocke@cycos.com>
Sat, 21 Jun 2014 00:53:21 +0000 (02:53 +0200)
committerFlorian Zschocke <florian.zschocke@devolo.de>
Fri, 28 Oct 2016 09:02:25 +0000 (11:02 +0200)
Add the option to merge a ticket branch to the integration branch
only when it can be fast-forwarded, or
always with a merge commit, or
by fast-foward if possible, otherwise with a merge commit.

Adds a new property ticket.mergeType with the valid values
FAST_FOWARD_ONLY, MERGE_ALWAYS and MERGE_IF_NECESSARY.

Merging and canMerge were refactored to make use of a new
IntegrationStrategy class for each type of strategy.

src/main/distrib/data/defaults.properties
src/main/java/com/gitblit/Constants.java
src/main/java/com/gitblit/git/PatchsetReceivePack.java
src/main/java/com/gitblit/manager/RepositoryManager.java
src/main/java/com/gitblit/models/RepositoryModel.java
src/main/java/com/gitblit/utils/JGitUtils.java
src/main/java/com/gitblit/wicket/pages/TicketPage.java

index 0c7d6cd42abde6054636072361fce2ffcd6892e3..208fd992a7ae9243f508547171a7204fddb2024c 100644 (file)
@@ -567,6 +567,21 @@ tickets.acceptNewPatchsets = true
 # SINCE 1.4.0
 tickets.requireApproval = false
 
+# Default setting to control how patchsets are merged to the integration branch.
+# Valid values: 
+# MERGE_ALWAYS       - Always merge with a merge commit. Every ticket will show up as a branch,
+#                       even if it could have been fast-forward merged. This is the default.
+# MERGE_IF_NECESSARY - If possible, fast-forward the integration branch,
+#                       if not, merge with a merge commit.
+# FAST_FORWARD_ONLY  - Only merge when a fast-forward is possible. This produces a strictly
+#                       linear history of the integration branch.
+#
+# This setting can be overriden per-repository.
+#
+# RESTART REQUIRED
+# SINCE 1.9.0
+tickets.mergeType = MERGE_ALWAYS
+
 # The case-insensitive regular expression used to identify and close tickets on
 # push to the integration branch for commits that are NOT already referenced as
 # a patchset tip.
index 6232552e189895c124fd2d0969a49f6de7f5bf7d..321f84f96363382ae29a418d45b5f37d7f60f925 100644 (file)
@@ -639,6 +639,37 @@ public class Constants {
                }\r
        }\r
 \r
+       /**\r
+        * The type of merge Gitblit will use when merging a ticket to the integration branch.\r
+        * <p>\r
+        * The default type is MERGE_ALWAYS.\r
+        * <p>\r
+        * This is modeled after the Gerrit SubmitType.\r
+        */\r
+       public static enum MergeType {\r
+               /** Allows a merge only if it can be fast-forward merged into the integration branch. */\r
+               FAST_FORWARD_ONLY,\r
+               /** Uses a fast-forward merge if possible, other wise a merge commit is created. */\r
+               MERGE_IF_NECESSARY,\r
+               // Future REBASE_IF_NECESSARY,\r
+               /** Always merge with a merge commit, even when a fast-forward would be possible. */\r
+               MERGE_ALWAYS,\r
+               // Future? CHERRY_PICK\r
+               ;\r
+\r
+               public static final MergeType DEFAULT_MERGE_TYPE = MERGE_ALWAYS;\r
+\r
+               public static MergeType fromName(String name) {\r
+                       for (MergeType type : values()) {\r
+                               if (type.name().equalsIgnoreCase(name)) {\r
+                                       return type;\r
+                               }\r
+                       }\r
+                       return DEFAULT_MERGE_TYPE;\r
+               }\r
+       }\r
+\r
+\r
        @Documented\r
        @Retention(RetentionPolicy.RUNTIME)\r
        public @interface Unused {\r
index 33fa47055d6c5a5d880eb50bcf200d2b74ff5fe1..4a09139aa4b76178dd66d8c88169c8a003a0e1e8 100644 (file)
@@ -599,7 +599,7 @@ public class PatchsetReceivePack extends GitblitReceivePack {
                }\r
 \r
                // ensure that the patchset can be cleanly merged right now\r
-               MergeStatus status = JGitUtils.canMerge(getRepository(), tipCommit.getName(), forBranch);\r
+               MergeStatus status = JGitUtils.canMerge(getRepository(), tipCommit.getName(), forBranch, repository.mergeType);\r
                switch (status) {\r
                case ALREADY_MERGED:\r
                        sendError("");\r
@@ -1279,6 +1279,7 @@ public class PatchsetReceivePack extends GitblitReceivePack {
                                getRepository(),\r
                                patchset.tip,\r
                                ticket.mergeTo,\r
+                               getRepositoryModel().mergeType,\r
                                committer,\r
                                message);\r
 \r
index e9bf5b8486dbf49cc68d3b6329379e96a302e5b1..baccfcfa9ac70adaf0e000398d78cba3d149d79e 100644 (file)
@@ -63,6 +63,7 @@ import com.gitblit.Constants.AccessRestrictionType;
 import com.gitblit.Constants.AuthorizationControl;
 import com.gitblit.Constants.CommitMessageRenderer;
 import com.gitblit.Constants.FederationStrategy;
+import com.gitblit.Constants.MergeType;
 import com.gitblit.Constants.PermissionType;
 import com.gitblit.Constants.RegistrantType;
 import com.gitblit.GitBlitException;
@@ -899,6 +900,7 @@ public class RepositoryManager implements IRepositoryManager {
                        model.acceptNewTickets = getConfig(config, "acceptNewTickets", true);
                        model.requireApproval = getConfig(config, "requireApproval", settings.getBoolean(Keys.tickets.requireApproval, false));
                        model.mergeTo = getConfig(config, "mergeTo", null);
+                       model.mergeType = MergeType.fromName(getConfig(config, "mergeType", settings.getString(Keys.tickets.mergeType, null)));
                        model.useIncrementalPushTags = getConfig(config, "useIncrementalPushTags", false);
                        model.incrementalPushTagPrefix = getConfig(config, "incrementalPushTagPrefix", null);
                        model.allowForks = getConfig(config, "allowForks", true);
@@ -1557,6 +1559,13 @@ public class RepositoryManager implements IRepositoryManager {
                if (!StringUtils.isEmpty(repository.mergeTo)) {
                        config.setString(Constants.CONFIG_GITBLIT, null, "mergeTo", repository.mergeTo);
                }
+               if (repository.mergeType == null || repository.mergeType == MergeType.fromName(settings.getString(Keys.tickets.mergeType, null))) {
+                       // use default
+                       config.unset(Constants.CONFIG_GITBLIT, null, "mergeType");
+               } else {
+                       // override default
+                       config.setString(Constants.CONFIG_GITBLIT, null, "mergeType", repository.mergeType.name());
+               }
                config.setBoolean(Constants.CONFIG_GITBLIT, null, "useIncrementalPushTags", repository.useIncrementalPushTags);
                if (StringUtils.isEmpty(repository.incrementalPushTagPrefix) ||
                                repository.incrementalPushTagPrefix.equals(settings.getString(Keys.git.defaultIncrementalPushTagPrefix, "r"))) {
index a81c622af4d35f0d319b2802429e7447ea2aaad4..67ee1c7e0f4866a756fe930c045b239572762502 100644 (file)
@@ -28,6 +28,7 @@ import com.gitblit.Constants.AccessRestrictionType;
 import com.gitblit.Constants.AuthorizationControl;\r
 import com.gitblit.Constants.CommitMessageRenderer;\r
 import com.gitblit.Constants.FederationStrategy;\r
+import com.gitblit.Constants.MergeType;\r
 import com.gitblit.utils.ArrayUtils;\r
 import com.gitblit.utils.ModelUtils;\r
 import com.gitblit.utils.StringUtils;\r
@@ -89,6 +90,7 @@ public class RepositoryModel implements Serializable, Comparable<RepositoryModel
        public boolean acceptNewTickets;\r
        public boolean requireApproval;
        public String mergeTo;\r
+       public MergeType mergeType;\r
 \r
        public transient boolean isCollectingGarbage;\r
        public Date lastGC;\r
@@ -111,6 +113,7 @@ public class RepositoryModel implements Serializable, Comparable<RepositoryModel
                this.isBare = true;\r
                this.acceptNewTickets = true;\r
                this.acceptNewPatchsets = true;\r
+               this.mergeType = MergeType.DEFAULT_MERGE_TYPE;\r
 \r
                addOwner(owner);\r
        }\r
index a02fc3fff798e66df9976a9d22bcf825cec86d65..0eea1d6156b4eb701bd3a56f6ffcd4fdcaf721cf 100644 (file)
@@ -99,6 +99,7 @@ import org.jetbrains.annotations.NotNull;
 import org.slf4j.Logger;\r
 import org.slf4j.LoggerFactory;\r
 \r
+import com.gitblit.Constants.MergeType;\r
 import com.gitblit.GitBlitException;\r
 import com.gitblit.IStoredSettings;\r
 import com.gitblit.Keys;\r
@@ -2453,44 +2454,13 @@ public class JGitUtils {
         * @param repository\r
         * @param src\r
         * @param toBranch\r
+        * @param mergeType\r
+        *            Defines the integration strategy to use for merging.\r
         * @return true if we can merge without conflict\r
         */\r
-       public static MergeStatus canMerge(Repository repository, String src, String toBranch) {\r
-               RevWalk revWalk = null;\r
-               try {\r
-                       revWalk = new RevWalk(repository);\r
-                       ObjectId branchId = repository.resolve(toBranch);\r
-                       if (branchId == null) {\r
-                               return MergeStatus.MISSING_INTEGRATION_BRANCH;\r
-                       }\r
-                       ObjectId srcId = repository.resolve(src);\r
-                       if (srcId == null) {\r
-                               return MergeStatus.MISSING_SRC_BRANCH;\r
-                       }\r
-                       RevCommit branchTip = revWalk.lookupCommit(branchId);\r
-                       RevCommit srcTip = revWalk.lookupCommit(srcId);\r
-                       if (revWalk.isMergedInto(srcTip, branchTip)) {\r
-                               // already merged\r
-                               return MergeStatus.ALREADY_MERGED;\r
-                       } else if (revWalk.isMergedInto(branchTip, srcTip)) {\r
-                               // fast-forward\r
-                               return MergeStatus.MERGEABLE;\r
-                       }\r
-                       RecursiveMerger merger = (RecursiveMerger) MergeStrategy.RECURSIVE.newMerger(repository, true);\r
-                       boolean canMerge = merger.merge(branchTip, srcTip);\r
-                       if (canMerge) {\r
-                               return MergeStatus.MERGEABLE;\r
-                       }\r
-               } catch (NullPointerException e) {\r
-                       LOGGER.error("Failed to determine canMerge", e);\r
-               } catch (IOException e) {\r
-                       LOGGER.error("Failed to determine canMerge", e);\r
-               } finally {\r
-                       if (revWalk != null) {\r
-                               revWalk.close();\r
-                       }\r
-               }\r
-               return MergeStatus.NOT_MERGEABLE;\r
+       public static MergeStatus canMerge(Repository repository, String src, String toBranch, MergeType mergeType) {\r
+               IntegrationStrategy strategy = IntegrationStrategyFactory.create(mergeType, repository, src, toBranch);\r
+               return strategy.canMerge();\r
        }\r
 \r
 \r
@@ -2511,11 +2481,13 @@ public class JGitUtils {
         * @param repository\r
         * @param src\r
         * @param toBranch\r
+        * @param mergeType\r
+        *            Defines the integration strategy to use for merging.\r
         * @param committer\r
         * @param message\r
         * @return the merge result\r
         */\r
-       public static MergeResult merge(Repository repository, String src, String toBranch,\r
+       public static MergeResult merge(Repository repository, String src, String toBranch, MergeType mergeType,\r
                        PersonIdent committer, String message) {\r
 \r
                if (!toBranch.startsWith(Constants.R_REFS)) {\r
@@ -2523,15 +2495,202 @@ public class JGitUtils {
                        toBranch = Constants.R_HEADS + toBranch;\r
                }\r
 \r
-               RevWalk revWalk = null;\r
+               IntegrationStrategy strategy = IntegrationStrategyFactory.create(mergeType, repository, src, toBranch);\r
+               MergeResult mergeResult = strategy.merge(committer, message);\r
+\r
+               if (mergeResult.status != MergeStatus.MERGED) {\r
+                       return mergeResult;\r
+               }\r
+\r
                try {\r
-                       revWalk = new RevWalk(repository);\r
-                       RevCommit branchTip = revWalk.lookupCommit(repository.resolve(toBranch));\r
-                       RevCommit srcTip = revWalk.lookupCommit(repository.resolve(src));\r
-                       if (revWalk.isMergedInto(srcTip, branchTip)) {\r
-                               // already merged\r
-                               return new MergeResult(MergeStatus.ALREADY_MERGED, null);\r
+                       // Update the integration branch ref\r
+                       RefUpdate mergeRefUpdate = repository.updateRef(toBranch);\r
+                       mergeRefUpdate.setNewObjectId(strategy.getMergeCommit());\r
+                       mergeRefUpdate.setRefLogMessage(strategy.getRefLogMessage(), false);\r
+                       mergeRefUpdate.setExpectedOldObjectId(strategy.branchTip);\r
+                       RefUpdate.Result rc = mergeRefUpdate.update();\r
+                       switch (rc) {\r
+                       case FAST_FORWARD:\r
+                               // successful, clean merge\r
+                               break;\r
+                       default:\r
+                               mergeResult = new MergeResult(MergeStatus.FAILED, null);\r
+                               throw new GitBlitException(MessageFormat.format("Unexpected result \"{0}\" when {1} in {2}",\r
+                                               rc.name(), strategy.getOperationMessage(), repository.getDirectory()));\r
+                       }\r
+               } catch (IOException e) {\r
+                       LOGGER.error("Failed to merge", e);\r
+               }\r
+\r
+               return mergeResult;\r
+       }\r
+\r
+\r
+       private static abstract class IntegrationStrategy {\r
+               Repository repository;\r
+               String src;\r
+               String toBranch;\r
+\r
+               RevWalk revWalk;\r
+               RevCommit branchTip;\r
+               RevCommit srcTip;\r
+\r
+               RevCommit mergeCommit;\r
+               String refLogMessage;\r
+               String operationMessage;\r
+\r
+               RevCommit getMergeCommit() {\r
+                       return mergeCommit;\r
+               }\r
+\r
+               String getRefLogMessage() {\r
+                       return refLogMessage;\r
+               }\r
+\r
+               String getOperationMessage() {\r
+                       return operationMessage;\r
+               }\r
+\r
+               IntegrationStrategy(Repository repository, String src, String toBranch) {\r
+                       this.repository = repository;\r
+                       this.src = src;\r
+                       this.toBranch = toBranch;\r
+               }\r
+\r
+               void prepare() throws IOException {\r
+                       if (revWalk == null) revWalk = new RevWalk(repository);\r
+                       ObjectId branchId = repository.resolve(toBranch);\r
+                       if (branchId != null) {\r
+                               branchTip = revWalk.lookupCommit(branchId);\r
+                       }\r
+                       ObjectId srcId = repository.resolve(src);\r
+                       if (srcId != null) {\r
+                               srcTip = revWalk.lookupCommit(srcId);\r
+                       }\r
+               }\r
+\r
+\r
+               abstract MergeStatus _canMerge() throws IOException;\r
+\r
+\r
+               MergeStatus canMerge() {\r
+                       try {\r
+                               prepare();\r
+                               if (branchTip == null) {\r
+                                       return MergeStatus.MISSING_INTEGRATION_BRANCH;\r
+                               }\r
+                               if (srcTip == null) {\r
+                                       return MergeStatus.MISSING_SRC_BRANCH;\r
+                               }\r
+                               if (revWalk.isMergedInto(srcTip, branchTip)) {\r
+                                       // already merged\r
+                                       return MergeStatus.ALREADY_MERGED;\r
+                               }\r
+                               // determined by specific integration strategy\r
+                               return _canMerge();\r
+\r
+                       } catch (NullPointerException e) {\r
+                               LOGGER.error("Failed to determine canMerge", e);\r
+                       } catch (IOException e) {\r
+                               LOGGER.error("Failed to determine canMerge", e);\r
+                       } finally {\r
+                               if (revWalk != null) {\r
+                                       revWalk.close();\r
+                               }\r
+                       }\r
+\r
+                       return MergeStatus.NOT_MERGEABLE;\r
+               }\r
+\r
+\r
+               abstract MergeResult _merge(PersonIdent committer, String message) throws IOException;\r
+\r
+\r
+               MergeResult merge(PersonIdent committer, String message) {\r
+                       try {\r
+                               prepare();\r
+                               if (revWalk.isMergedInto(srcTip, branchTip)) {\r
+                                       // already merged\r
+                                       return new MergeResult(MergeStatus.ALREADY_MERGED, null);\r
+                               }\r
+                               // determined by specific integration strategy\r
+                               return _merge(committer, message);\r
+\r
+                       } catch (IOException e) {\r
+                               LOGGER.error("Failed to merge", e);\r
+                       } finally {\r
+                               if (revWalk != null) {\r
+                                       revWalk.close();\r
+                               }\r
+                       }\r
+\r
+                       return new MergeResult(MergeStatus.FAILED, null);\r
+               }\r
+       }\r
+\r
+\r
+       private static class FastForwardOnly extends IntegrationStrategy {\r
+               FastForwardOnly(Repository repository, String src, String toBranch) {\r
+                       super(repository, src, toBranch);\r
+               }\r
+\r
+               @Override\r
+               MergeStatus _canMerge() throws IOException {\r
+                       if (revWalk.isMergedInto(branchTip, srcTip)) {\r
+                               // fast-forward\r
+                               return MergeStatus.MERGEABLE;\r
+                       }\r
+\r
+                       return MergeStatus.NOT_MERGEABLE;\r
+               }\r
+\r
+               @Override\r
+               MergeResult _merge(PersonIdent committer, String message) throws IOException {\r
+                       if (! revWalk.isMergedInto(branchTip, srcTip)) {\r
+                               // is not fast-forward\r
+                               return new MergeResult(MergeStatus.FAILED, null);\r
+                       }\r
+\r
+                       mergeCommit = srcTip;\r
+                       refLogMessage = "merge " + src + ": Fast-forward";\r
+                       operationMessage = MessageFormat.format("fast-forwarding {0} to commit {1}", srcTip.getName(), branchTip.getName());\r
+\r
+                       return new MergeResult(MergeStatus.MERGED, srcTip.getName());\r
+               }\r
+       }\r
+\r
+       private static class MergeIfNecessary extends IntegrationStrategy {\r
+               MergeIfNecessary(Repository repository, String src, String toBranch) {\r
+                       super(repository, src, toBranch);\r
+               }\r
+\r
+               @Override\r
+               MergeStatus _canMerge() throws IOException {\r
+                       if (revWalk.isMergedInto(branchTip, srcTip)) {\r
+                               // fast-forward\r
+                               return MergeStatus.MERGEABLE;\r
+                       }\r
+\r
+                       RecursiveMerger merger = (RecursiveMerger) MergeStrategy.RECURSIVE.newMerger(repository, true);\r
+                       boolean canMerge = merger.merge(branchTip, srcTip);\r
+                       if (canMerge) {\r
+                               return MergeStatus.MERGEABLE;\r
+                       }\r
+\r
+                       return MergeStatus.NOT_MERGEABLE;\r
+               }\r
+\r
+               @Override\r
+               MergeResult _merge(PersonIdent committer, String message) throws IOException {\r
+                       if (revWalk.isMergedInto(branchTip, srcTip)) {\r
+                               // fast-forward\r
+                               mergeCommit = srcTip;\r
+                               refLogMessage = "merge " + src + ": Fast-forward";\r
+                               operationMessage = MessageFormat.format("fast-forwarding {0} to commit {1}", branchTip.getName(), srcTip.getName());\r
+\r
+                               return new MergeResult(MergeStatus.MERGED, srcTip.getName());\r
                        }\r
+\r
                        RecursiveMerger merger = (RecursiveMerger) MergeStrategy.RECURSIVE.newMerger(repository, true);\r
                        boolean merged = merger.merge(branchTip, srcTip);\r
                        if (merged) {\r
@@ -2555,20 +2714,64 @@ public class JGitUtils {
                                        ObjectId mergeCommitId = odi.insert(commitBuilder);\r
                                        odi.flush();\r
 \r
-                                       // set the merge ref to the merge commit\r
-                                       RevCommit mergeCommit = revWalk.parseCommit(mergeCommitId);\r
-                                       RefUpdate mergeRefUpdate = repository.updateRef(toBranch);\r
-                                       mergeRefUpdate.setNewObjectId(mergeCommitId);\r
-                                       mergeRefUpdate.setRefLogMessage("commit: " + mergeCommit.getShortMessage(), false);\r
-                                       RefUpdate.Result rc = mergeRefUpdate.update();\r
-                                       switch (rc) {\r
-                                       case FAST_FORWARD:\r
-                                               // successful, clean merge\r
-                                               break;\r
-                                       default:\r
-                                               throw new GitBlitException(MessageFormat.format("Unexpected result \"{0}\" when merging commit {1} into {2} in {3}",\r
-                                                               rc.name(), srcTip.getName(), branchTip.getName(), repository.getDirectory()));\r
+                                       mergeCommit = revWalk.parseCommit(mergeCommitId);\r
+                                       refLogMessage = "commit: " + mergeCommit.getShortMessage();\r
+                                       operationMessage = MessageFormat.format("merging commit {0} into {1}", srcTip.getName(), branchTip.getName());\r
+\r
+                                       // return the merge commit id\r
+                                       return new MergeResult(MergeStatus.MERGED, mergeCommitId.getName());\r
+                               } finally {\r
+                                       odi.close();\r
+                               }\r
+                       }\r
+                       return new MergeResult(MergeStatus.FAILED, null);\r
+               }\r
+       }\r
+\r
+       private static class MergeAlways extends IntegrationStrategy {\r
+               MergeAlways(Repository repository, String src, String toBranch) {\r
+                       super(repository, src, toBranch);\r
+               }\r
+\r
+               @Override\r
+               MergeStatus _canMerge() throws IOException {\r
+                       RecursiveMerger merger = (RecursiveMerger) MergeStrategy.RECURSIVE.newMerger(repository, true);\r
+                       boolean canMerge = merger.merge(branchTip, srcTip);\r
+                       if (canMerge) {\r
+                               return MergeStatus.MERGEABLE;\r
+                       }\r
+\r
+                       return MergeStatus.NOT_MERGEABLE;\r
+               }\r
+\r
+               @Override\r
+               MergeResult _merge(PersonIdent committer, String message) throws IOException {\r
+                       RecursiveMerger merger = (RecursiveMerger) MergeStrategy.RECURSIVE.newMerger(repository, true);\r
+                       boolean merged = merger.merge(branchTip, srcTip);\r
+                       if (merged) {\r
+                               // create a merge commit and a reference to track the merge commit\r
+                               ObjectId treeId = merger.getResultTreeId();\r
+                               ObjectInserter odi = repository.newObjectInserter();\r
+                               try {\r
+                                       // Create a commit object\r
+                                       CommitBuilder commitBuilder = new CommitBuilder();\r
+                                       commitBuilder.setCommitter(committer);\r
+                                       commitBuilder.setAuthor(committer);\r
+                                       commitBuilder.setEncoding(Constants.CHARSET);\r
+                                       if (StringUtils.isEmpty(message)) {\r
+                                               message = MessageFormat.format("merge {0} into {1}", srcTip.getName(), branchTip.getName());\r
                                        }\r
+                                       commitBuilder.setMessage(message);\r
+                                       commitBuilder.setParentIds(branchTip.getId(), srcTip.getId());\r
+                                       commitBuilder.setTreeId(treeId);\r
+\r
+                                       // Insert the merge commit into the repository\r
+                                       ObjectId mergeCommitId = odi.insert(commitBuilder);\r
+                                       odi.flush();\r
+\r
+                                       mergeCommit = revWalk.parseCommit(mergeCommitId);\r
+                                       refLogMessage = "commit: " + mergeCommit.getShortMessage();\r
+                                       operationMessage = MessageFormat.format("merging commit {0} into {1}", srcTip.getName(), branchTip.getName());\r
 \r
                                        // return the merge commit id\r
                                        return new MergeResult(MergeStatus.MERGED, mergeCommitId.getName());\r
@@ -2576,17 +2779,27 @@ public class JGitUtils {
                                        odi.close();\r
                                }\r
                        }\r
-               } catch (IOException e) {\r
-                       LOGGER.error("Failed to merge", e);\r
-               } finally {\r
-                       if (revWalk != null) {\r
-                               revWalk.close();\r
+\r
+                       return new MergeResult(MergeStatus.FAILED, null);\r
+               }\r
+       }\r
+\r
+\r
+       private static class IntegrationStrategyFactory {\r
+               static IntegrationStrategy create(MergeType mergeType, Repository repository, String src, String toBranch) {\r
+                       switch(mergeType) {\r
+                       case FAST_FORWARD_ONLY:\r
+                               return new FastForwardOnly(repository, src, toBranch);\r
+                       case MERGE_IF_NECESSARY:\r
+                               return new MergeIfNecessary(repository, src, toBranch);\r
+                       case MERGE_ALWAYS:\r
+                               return new MergeAlways(repository, src, toBranch);\r
                        }\r
+                       return null;\r
                }\r
-               return new MergeResult(MergeStatus.FAILED, null);\r
        }\r
-       \r
-       \r
+\r
+\r
        /**\r
         * Returns the LFS URL for the given oid \r
         * Currently assumes that the Gitblit Filestore is used \r
index cd049f4d2308d92120041e0d162b8857ab42039b..e2133966aee6433a42309309d70a40df9546ea72 100644 (file)
@@ -1405,14 +1405,14 @@ public class TicketPage extends RepositoryPage {
 \r
                boolean allowMerge;\r
                if (repository.requireApproval) {\r
-                       // rpeository requires approval\r
+                       // repository requires approval\r
                        allowMerge = ticket.isOpen() && ticket.isApproved(patchset);\r
                } else {\r
-                       // vetos are binding\r
+                       // vetoes are binding\r
                        allowMerge = ticket.isOpen() && !ticket.isVetoed(patchset);\r
                }\r
 \r
-               MergeStatus mergeStatus = JGitUtils.canMerge(getRepository(), patchset.tip, ticket.mergeTo);\r
+               MergeStatus mergeStatus = JGitUtils.canMerge(getRepository(), patchset.tip, ticket.mergeTo, repository.mergeType);\r
                if (allowMerge) {\r
                        if (MergeStatus.MERGEABLE == mergeStatus) {\r
                                // patchset can be cleanly merged to integration branch OR has already been merged\r