MergeMessageFormatter.java

  1. /*
  2.  * Copyright (C) 2010-2012, Robin Stocker <robin@nibor.org> and others
  3.  *
  4.  * This program and the accompanying materials are made available under the
  5.  * terms of the Eclipse Distribution License v. 1.0 which is available at
  6.  * https://www.eclipse.org/org/documents/edl-v10.php.
  7.  *
  8.  * SPDX-License-Identifier: BSD-3-Clause
  9.  */
  10. package org.eclipse.jgit.merge;

  11. import java.util.ArrayList;
  12. import java.util.List;

  13. import org.eclipse.jgit.lib.Constants;
  14. import org.eclipse.jgit.lib.ObjectId;
  15. import org.eclipse.jgit.lib.Ref;
  16. import org.eclipse.jgit.lib.Repository;
  17. import org.eclipse.jgit.util.ChangeIdUtil;
  18. import org.eclipse.jgit.util.StringUtils;

  19. /**
  20.  * Formatter for constructing the commit message for a merge commit.
  21.  * <p>
  22.  * The format should be the same as C Git does it, for compatibility.
  23.  */
  24. public class MergeMessageFormatter {
  25.     /**
  26.      * Construct the merge commit message.
  27.      *
  28.      * @param refsToMerge
  29.      *            the refs which will be merged
  30.      * @param target
  31.      *            the branch ref which will be merged into
  32.      * @return merge commit message
  33.      */
  34.     public String format(List<Ref> refsToMerge, Ref target) {
  35.         StringBuilder sb = new StringBuilder();
  36.         sb.append("Merge "); //$NON-NLS-1$

  37.         List<String> branches = new ArrayList<>();
  38.         List<String> remoteBranches = new ArrayList<>();
  39.         List<String> tags = new ArrayList<>();
  40.         List<String> commits = new ArrayList<>();
  41.         List<String> others = new ArrayList<>();
  42.         for (Ref ref : refsToMerge) {
  43.             if (ref.getName().startsWith(Constants.R_HEADS)) {
  44.                 branches.add("'" + Repository.shortenRefName(ref.getName()) //$NON-NLS-1$
  45.                         + "'"); //$NON-NLS-1$
  46.             } else if (ref.getName().startsWith(Constants.R_REMOTES)) {
  47.                 remoteBranches.add("'" //$NON-NLS-1$
  48.                         + Repository.shortenRefName(ref.getName()) + "'"); //$NON-NLS-1$
  49.             } else if (ref.getName().startsWith(Constants.R_TAGS)) {
  50.                 tags.add("'" + Repository.shortenRefName(ref.getName()) + "'"); //$NON-NLS-1$ //$NON-NLS-2$
  51.             } else {
  52.                 ObjectId objectId = ref.getObjectId();
  53.                 if (objectId != null && ref.getName().equals(objectId.getName())) {
  54.                     commits.add("'" + ref.getName() + "'"); //$NON-NLS-1$ //$NON-NLS-2$
  55.                 } else {
  56.                     others.add(ref.getName());
  57.                 }
  58.             }
  59.         }

  60.         List<String> listings = new ArrayList<>();

  61.         if (!branches.isEmpty())
  62.             listings.add(joinNames(branches, "branch", "branches")); //$NON-NLS-1$//$NON-NLS-2$

  63.         if (!remoteBranches.isEmpty())
  64.             listings.add(joinNames(remoteBranches, "remote-tracking branch", //$NON-NLS-1$
  65.                     "remote-tracking branches")); //$NON-NLS-1$

  66.         if (!tags.isEmpty())
  67.             listings.add(joinNames(tags, "tag", "tags")); //$NON-NLS-1$ //$NON-NLS-2$

  68.         if (!commits.isEmpty())
  69.             listings.add(joinNames(commits, "commit", "commits")); //$NON-NLS-1$ //$NON-NLS-2$

  70.         if (!others.isEmpty())
  71.             listings.add(StringUtils.join(others, ", ", " and ")); //$NON-NLS-1$ //$NON-NLS-2$

  72.         sb.append(StringUtils.join(listings, ", ")); //$NON-NLS-1$

  73.         String targetName = target.getLeaf().getName();
  74.         if (!targetName.equals(Constants.R_HEADS + Constants.MASTER)) {
  75.             String targetShortName = Repository.shortenRefName(targetName);
  76.             sb.append(" into " + targetShortName); //$NON-NLS-1$
  77.         }

  78.         return sb.toString();
  79.     }

  80.     /**
  81.      * Add section with conflicting paths to merge message.
  82.      *
  83.      * @param message
  84.      *            the original merge message
  85.      * @param conflictingPaths
  86.      *            the paths with conflicts
  87.      * @return merge message with conflicting paths added
  88.      */
  89.     public String formatWithConflicts(String message,
  90.             List<String> conflictingPaths) {
  91.         StringBuilder sb = new StringBuilder();
  92.         String[] lines = message.split("\n"); //$NON-NLS-1$
  93.         int firstFooterLine = ChangeIdUtil.indexOfFirstFooterLine(lines);
  94.         for (int i = 0; i < firstFooterLine; i++)
  95.             sb.append(lines[i]).append('\n');
  96.         if (firstFooterLine == lines.length && message.length() != 0)
  97.             sb.append('\n');
  98.         addConflictsMessage(conflictingPaths, sb);
  99.         if (firstFooterLine < lines.length)
  100.             sb.append('\n');
  101.         for (int i = firstFooterLine; i < lines.length; i++)
  102.             sb.append(lines[i]).append('\n');
  103.         return sb.toString();
  104.     }

  105.     private static void addConflictsMessage(List<String> conflictingPaths,
  106.             StringBuilder sb) {
  107.         sb.append("Conflicts:\n"); //$NON-NLS-1$
  108.         for (String conflictingPath : conflictingPaths) {
  109.             sb.append('\t').append(conflictingPath).append('\n');
  110.         }
  111.     }

  112.     private static String joinNames(List<String> names, String singular,
  113.             String plural) {
  114.         if (names.size() == 1) {
  115.             return singular + " " + names.get(0); //$NON-NLS-1$
  116.         }
  117.         return plural + " " + StringUtils.join(names, ", ", " and "); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
  118.     }
  119. }