Merge conflict messages: prefix conflict lines with a hash

C git also does so. Note that currently the comment character is
hard-coded as the hash '#' throughout JGit.

Bug: 548529
Change-Id: I4a5597694082a9e5b07412b365cfaf41fa034cfa
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
This commit is contained in:
Thomas Wolf 2022-01-16 15:50:00 +01:00
parent e297f503a1
commit 1fd15e40cc
8 changed files with 65 additions and 28 deletions

View File

@ -175,7 +175,8 @@ public void testCherryPickConflictResolution() throws Exception {
assertEquals(CherryPickStatus.CONFLICTING, result.getStatus()); assertEquals(CherryPickStatus.CONFLICTING, result.getStatus());
assertTrue(new File(db.getDirectory(), Constants.MERGE_MSG).exists()); assertTrue(new File(db.getDirectory(), Constants.MERGE_MSG).exists());
assertEquals("side\n\nConflicts:\n\ta\n", db.readMergeCommitMsg()); assertEquals("side\n\n# Conflicts:\n#\ta\n",
db.readMergeCommitMsg());
assertTrue(new File(db.getDirectory(), Constants.CHERRY_PICK_HEAD) assertTrue(new File(db.getDirectory(), Constants.CHERRY_PICK_HEAD)
.exists()); .exists());
assertEquals(sideCommit.getId(), db.readCherryPickHead()); assertEquals(sideCommit.getId(), db.readCherryPickHead());
@ -207,7 +208,7 @@ public void testCherryPickConflictResolutionNoCommit() throws Exception {
String expected = "<<<<<<< master\na(master)\n=======\na(side)\n>>>>>>> 527460a side\n"; String expected = "<<<<<<< master\na(master)\n=======\na(side)\n>>>>>>> 527460a side\n";
assertEquals(expected, read("a")); assertEquals(expected, read("a"));
assertTrue(new File(db.getDirectory(), Constants.MERGE_MSG).exists()); assertTrue(new File(db.getDirectory(), Constants.MERGE_MSG).exists());
assertEquals("side\n\nConflicts:\n\ta\n", db.readMergeCommitMsg()); assertEquals("side\n\n# Conflicts:\n#\ta\n", db.readMergeCommitMsg());
assertFalse(new File(db.getDirectory(), Constants.CHERRY_PICK_HEAD) assertFalse(new File(db.getDirectory(), Constants.CHERRY_PICK_HEAD)
.exists()); .exists());
assertEquals(RepositoryState.SAFE, db.getRepositoryState()); assertEquals(RepositoryState.SAFE, db.getRepositoryState());

View File

@ -554,7 +554,7 @@ public void testMergeMessage() throws Exception {
git.merge().include(sideBranch) git.merge().include(sideBranch)
.setStrategy(MergeStrategy.RESOLVE).call(); .setStrategy(MergeStrategy.RESOLVE).call();
assertEquals("Merge branch 'side'\n\nConflicts:\n\ta\n", assertEquals("Merge branch 'side'\n\n# Conflicts:\n#\ta\n",
db.readMergeCommitMsg()); db.readMergeCommitMsg());
} }
@ -1787,7 +1787,7 @@ public void testSquashMergeConflict() throws Exception {
+ dateFormatter.formatDate(third + dateFormatter.formatDate(third
.getAuthorIdent()) + "\n\n\tthird commit\n", .getAuthorIdent()) + "\n\n\tthird commit\n",
db.readSquashCommitMsg()); db.readSquashCommitMsg());
assertEquals("\nConflicts:\n\tfile2\n", db.readMergeCommitMsg()); assertEquals("\n# Conflicts:\n#\tfile2\n", db.readMergeCommitMsg());
Status stat = git.status().call(); Status stat = git.status().call();
assertEquals(Sets.of("file2"), stat.getConflicting()); assertEquals(Sets.of("file2"), stat.getConflicting());
@ -2013,7 +2013,7 @@ public void testMergeConflictWithMessageOption() throws Exception {
git.merge().include(sideBranch).setStrategy(MergeStrategy.RESOLVE) git.merge().include(sideBranch).setStrategy(MergeStrategy.RESOLVE)
.setMessage("user message").call(); .setMessage("user message").call();
assertEquals("user message\n\nConflicts:\n\ta\n", assertEquals("user message\n\n# Conflicts:\n#\ta\n",
db.readMergeCommitMsg()); db.readMergeCommitMsg());
} }
} }

View File

@ -232,7 +232,7 @@ public void testRevertConflictResolution() throws Exception {
assertTrue(new File(db.getDirectory(), Constants.MERGE_MSG).exists()); assertTrue(new File(db.getDirectory(), Constants.MERGE_MSG).exists());
assertEquals("Revert \"" + sideCommit.getShortMessage() assertEquals("Revert \"" + sideCommit.getShortMessage()
+ "\"\n\nThis reverts commit " + sideCommit.getId().getName() + "\"\n\nThis reverts commit " + sideCommit.getId().getName()
+ ".\n\nConflicts:\n\ta\n", + ".\n\n# Conflicts:\n#\ta\n",
db.readMergeCommitMsg()); db.readMergeCommitMsg());
assertTrue(new File(db.getDirectory(), Constants.REVERT_HEAD) assertTrue(new File(db.getDirectory(), Constants.REVERT_HEAD)
.exists()); .exists());

View File

@ -13,6 +13,7 @@
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectIdRef; import org.eclipse.jgit.lib.ObjectIdRef;
@ -157,8 +158,8 @@ public void testIntoSymbolicRefHeadPointingToMaster() throws IOException {
public void testFormatWithConflictsNoFooter() { public void testFormatWithConflictsNoFooter() {
String originalMessage = "Header Line\n\nCommit body\n"; String originalMessage = "Header Line\n\nCommit body\n";
String message = formatter.formatWithConflicts(originalMessage, String message = formatter.formatWithConflicts(originalMessage,
Arrays.asList(new String[] { "path1" })); List.of("path1"), '#');
assertEquals("Header Line\n\nCommit body\n\nConflicts:\n\tpath1\n", assertEquals("Header Line\n\nCommit body\n\n# Conflicts:\n#\tpath1\n",
message); message);
} }
@ -166,8 +167,17 @@ public void testFormatWithConflictsNoFooter() {
public void testFormatWithConflictsNoFooterNoLineBreak() { public void testFormatWithConflictsNoFooterNoLineBreak() {
String originalMessage = "Header Line\n\nCommit body"; String originalMessage = "Header Line\n\nCommit body";
String message = formatter.formatWithConflicts(originalMessage, String message = formatter.formatWithConflicts(originalMessage,
Arrays.asList(new String[] { "path1" })); List.of("path1"), '#');
assertEquals("Header Line\n\nCommit body\n\nConflicts:\n\tpath1\n", assertEquals("Header Line\n\nCommit body\n\n# Conflicts:\n#\tpath1\n",
message);
}
@Test
public void testFormatWithConflictsCustomCharacter() {
String originalMessage = "Header Line\n\nCommit body";
String message = formatter.formatWithConflicts(originalMessage,
List.of("path1"), ';');
assertEquals("Header Line\n\nCommit body\n\n; Conflicts:\n;\tpath1\n",
message); message);
} }
@ -176,9 +186,9 @@ public void testFormatWithConflictsWithFooters() {
String originalMessage = "Header Line\n\nCommit body\n\nChangeId:" String originalMessage = "Header Line\n\nCommit body\n\nChangeId:"
+ " I123456789123456789123456789123456789\nBug:1234567\n"; + " I123456789123456789123456789123456789\nBug:1234567\n";
String message = formatter.formatWithConflicts(originalMessage, String message = formatter.formatWithConflicts(originalMessage,
Arrays.asList(new String[] { "path1" })); List.of("path1"), '#');
assertEquals( assertEquals(
"Header Line\n\nCommit body\n\nConflicts:\n\tpath1\n\n" "Header Line\n\nCommit body\n\n# Conflicts:\n#\tpath1\n\n"
+ "ChangeId: I123456789123456789123456789123456789\nBug:1234567\n", + "ChangeId: I123456789123456789123456789123456789\nBug:1234567\n",
message); message);
} }
@ -188,9 +198,9 @@ public void testFormatWithConflictsWithFooterlikeLineInBody() {
String originalMessage = "Header Line\n\nCommit body\nBug:1234567\nMore Body\n\nChangeId:" String originalMessage = "Header Line\n\nCommit body\nBug:1234567\nMore Body\n\nChangeId:"
+ " I123456789123456789123456789123456789\nBug:1234567\n"; + " I123456789123456789123456789123456789\nBug:1234567\n";
String message = formatter.formatWithConflicts(originalMessage, String message = formatter.formatWithConflicts(originalMessage,
Arrays.asList(new String[] { "path1" })); List.of("path1"), '#');
assertEquals( assertEquals(
"Header Line\n\nCommit body\nBug:1234567\nMore Body\n\nConflicts:\n\tpath1\n\n" "Header Line\n\nCommit body\nBug:1234567\nMore Body\n\n# Conflicts:\n#\tpath1\n\n"
+ "ChangeId: I123456789123456789123456789123456789\nBug:1234567\n", + "ChangeId: I123456789123456789123456789123456789\nBug:1234567\n",
message); message);
} }

View File

@ -183,7 +183,7 @@ public CherryPickResult call() throws GitAPIException, NoMessageException,
if (unmergedPaths != null) { if (unmergedPaths != null) {
message = new MergeMessageFormatter() message = new MergeMessageFormatter()
.formatWithConflicts(srcCommit.getFullMessage(), .formatWithConflicts(srcCommit.getFullMessage(),
unmergedPaths); unmergedPaths, '#');
} else { } else {
message = srcCommit.getFullMessage(); message = srcCommit.getFullMessage();
} }

View File

@ -405,7 +405,7 @@ public MergeResult call() throws GitAPIException, NoHeadException,
failingPaths, null); failingPaths, null);
} }
String mergeMessageWithConflicts = new MergeMessageFormatter() String mergeMessageWithConflicts = new MergeMessageFormatter()
.formatWithConflicts(mergeMessage, unmergedPaths); .formatWithConflicts(mergeMessage, unmergedPaths, '#');
repo.writeMergeCommitMsg(mergeMessageWithConflicts); repo.writeMergeCommitMsg(mergeMessageWithConflicts);
return new MergeResult(null, merger.getBaseCommitId(), return new MergeResult(null, merger.getBaseCommitId(),
new ObjectId[] { headCommit.getId(), new ObjectId[] { headCommit.getId(),

View File

@ -183,8 +183,8 @@ public RevCommit call() throws NoMessageException, UnmergedPathsException,
merger.getMergeResults(), failingPaths, null); merger.getMergeResults(), failingPaths, null);
if (!merger.failed() && !unmergedPaths.isEmpty()) { if (!merger.failed() && !unmergedPaths.isEmpty()) {
String message = new MergeMessageFormatter() String message = new MergeMessageFormatter()
.formatWithConflicts(newMessage, .formatWithConflicts(newMessage,
merger.getUnmergedPaths()); merger.getUnmergedPaths(), '#');
repo.writeRevertHead(srcCommit.getId()); repo.writeRevertHead(srcCommit.getId());
repo.writeMergeCommitMsg(message); repo.writeMergeCommitMsg(message);
} }

View File

@ -92,36 +92,62 @@ public String format(List<Ref> refsToMerge, Ref target) {
} }
/** /**
* Add section with conflicting paths to merge message. * Add section with conflicting paths to merge message. Lines are prefixed
* with a hash.
* *
* @param message * @param message
* the original merge message * the original merge message
* @param conflictingPaths * @param conflictingPaths
* the paths with conflicts * the paths with conflicts
* @return merge message with conflicting paths added * @return merge message with conflicting paths added
* @deprecated since 6.1; use
* {@link #formatWithConflicts(String, Iterable, char)} instead
*/ */
@Deprecated
public String formatWithConflicts(String message, public String formatWithConflicts(String message,
List<String> conflictingPaths) { List<String> conflictingPaths) {
return formatWithConflicts(message, conflictingPaths, '#');
}
/**
* Add section with conflicting paths to merge message.
*
* @param message
* the original merge message
* @param conflictingPaths
* the paths with conflicts
* @param commentChar
* comment character to use for prefixing the conflict lines
* @return merge message with conflicting paths added
* @since 6.1
*/
public String formatWithConflicts(String message,
Iterable<String> conflictingPaths, char commentChar) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
String[] lines = message.split("\n"); //$NON-NLS-1$ String[] lines = message.split("\n"); //$NON-NLS-1$
int firstFooterLine = ChangeIdUtil.indexOfFirstFooterLine(lines); int firstFooterLine = ChangeIdUtil.indexOfFirstFooterLine(lines);
for (int i = 0; i < firstFooterLine; i++) for (int i = 0; i < firstFooterLine; i++) {
sb.append(lines[i]).append('\n'); sb.append(lines[i]).append('\n');
if (firstFooterLine == lines.length && message.length() != 0) }
if (firstFooterLine == lines.length && message.length() != 0) {
sb.append('\n'); sb.append('\n');
addConflictsMessage(conflictingPaths, sb); }
if (firstFooterLine < lines.length) addConflictsMessage(conflictingPaths, sb, commentChar);
if (firstFooterLine < lines.length) {
sb.append('\n'); sb.append('\n');
for (int i = firstFooterLine; i < lines.length; i++) }
for (int i = firstFooterLine; i < lines.length; i++) {
sb.append(lines[i]).append('\n'); sb.append(lines[i]).append('\n');
}
return sb.toString(); return sb.toString();
} }
private static void addConflictsMessage(List<String> conflictingPaths, private static void addConflictsMessage(Iterable<String> conflictingPaths,
StringBuilder sb) { StringBuilder sb, char commentChar) {
sb.append("Conflicts:\n"); //$NON-NLS-1$ sb.append(commentChar).append(" Conflicts:\n"); //$NON-NLS-1$
for (String conflictingPath : conflictingPaths) { for (String conflictingPath : conflictingPaths) {
sb.append('\t').append(conflictingPath).append('\n'); sb.append(commentChar).append('\t').append(conflictingPath)
.append('\n');
} }
} }