Skip to content

Inconsistent Diff Results Between GitHub and JGit for Salesforce XML Metadata #232

@dhanushterala1509

Description

@dhanushterala1509

Version

7.3.0.202506031305-r

Operating System

MacOS

Bug description

I created a pull request in GitHub for a Salesforce metadata (XML) file. We noticed that the line-by-line differences shown in the .diff/.patch files generated by GitHub don’t match the output produced by JGit’s DiffFormatter.scan() or .diff() methods.

Actual behavior

Comparing: main...(merge-base) (4753e22) -> dhanushxxx-patch-12 (f1b500e)

diff --git a/force-app/main/default/permissionsets/Account_Object_Access.permissionset-meta.xml b/force-app/main/default/permissionsets/Account_Object_Access.permissionset-meta.xml
index 7748384..7b55172 100644
--- a/force-app/main/default/permissionsets/Account_Object_Access.permissionset-meta.xml
+++ b/force-app/main/default/permissionsets/Account_Object_Access.permissionset-meta.xml
@@ -38,6 +38,16 @@
         <allowEdit>true</allowEdit>
         <allowRead>true</allowRead>
         <modifyAllRecords>false</modifyAllRecords>
+        <object>Case</object>
+        <viewAllFields>false</viewAllFields>
+        <viewAllRecords>false</viewAllRecords>
+    </objectPermissions>
+    <objectPermissions>
+        <allowCreate>true</allowCreate>
+        <allowDelete>true</allowDelete>
+        <allowEdit>true</allowEdit>
+        <allowRead>true</allowRead>
+        <modifyAllRecords>false</modifyAllRecords>
         <object>Contact</object>
         <viewAllFields>false</viewAllFields>
         <viewAllRecords>false</viewAllRecords>

Expected behavior

.diff generated from github

diff --git a/force-app/main/default/permissionsets/Account_Object_Access.permissionset-meta.xml b/force-app/main/default/permissionsets/Account_Object_Access.permissionset-meta.xml
index 7748384..7b55172 100644
--- a/force-app/main/default/permissionsets/Account_Object_Access.permissionset-meta.xml
+++ b/force-app/main/default/permissionsets/Account_Object_Access.permissionset-meta.xml
@@ -32,6 +32,16 @@
         <viewAllFields>false</viewAllFields>
         <viewAllRecords>false</viewAllRecords>
     </objectPermissions>
+    <objectPermissions>
+        <allowCreate>true</allowCreate>
+        <allowDelete>true</allowDelete>
+        <allowEdit>true</allowEdit>
+        <allowRead>true</allowRead>
+        <modifyAllRecords>false</modifyAllRecords>
+        <object>Case</object>
+        <viewAllFields>false</viewAllFields>
+        <viewAllRecords>false</viewAllRecords>
+    </objectPermissions>
     <objectPermissions>
         <allowCreate>true</allowCreate>
         <allowDelete>true</allowDelete>

Relevant log output

Other information

I commited, rasied pr in github and cloned the repo into local. I ran this jgit diff code. I am executing below code with my local files .

import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.diff.DiffAlgorithm;
import org.eclipse.jgit.diff.DiffEntry;
import org.eclipse.jgit.diff.DiffFormatter;
import org.eclipse.jgit.diff.RawTextComparator;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.revwalk.filter.RevFilter;
import org.eclipse.jgit.treewalk.CanonicalTreeParser;

import java.io.File;
import java.util.List;

public class GitThreeDotDiffSimple {

public static void main(String[] args) throws Exception {
    String repoPath = "/Users/xxxx/Desktop/pr/switch-test";
    String baseRef  = "main";                       // A
    String headRef  = "dhanushxxx-patch-12"; // B

    try (Git git = Git.open(new File(repoPath))) {
        Repository repo = git.getRepository();

        ObjectId baseId = repo.resolve(baseRef);
        ObjectId headId = repo.resolve(headRef);

        if (baseId == null || headId == null) {
            System.err.println("Could not resolve: " + baseRef + " or " + headRef);
            return;
        }

        // 1) Find merge-base(A,B)  (this is what A...B uses)
        ObjectId mergeBase = findMergeBase(repo, baseId, headId);
        if (mergeBase == null) {
            System.err.println("No merge base, falling back to A vs B");
            mergeBase = baseId;
        }

        // 2) Do diff: mergeBase -> head (== git diff A...B)
        performDiff(repo, mergeBase, headId,
                baseRef + "...(merge-base)", headRef);
    }
}

private static void performDiff(
        Repository repo,
        ObjectId baseId,
        ObjectId headId,
        String baseName,
        String headName
) throws Exception {

    System.out.println("Comparing: " + baseName + " (" + baseId.abbreviate(7).name() +
            ") -> " + headName + " (" + headId.abbreviate(7).name() + ")");
    System.out.println("-".repeat(80));

    try (DiffFormatter formatter = new DiffFormatter(System.out)) {
        formatter.setRepository(repo);
        formatter.setDiffComparator(RawTextComparator.DEFAULT);
        formatter.setDetectRenames(true);
        formatter.setContext(3);
        formatter.setDiffAlgorithm(
                DiffAlgorithm.getAlgorithm(DiffAlgorithm.SupportedAlgorithm.MYERS));

        try (ObjectReader reader = repo.newObjectReader();
                RevWalk walk = new RevWalk(repo)) {

            RevCommit oldCommit = walk.parseCommit(baseId);
            RevCommit newCommit = walk.parseCommit(headId);

            CanonicalTreeParser oldTree = new CanonicalTreeParser();
            CanonicalTreeParser newTree = new CanonicalTreeParser();

            oldTree.reset(reader, oldCommit.getTree().getId());
            newTree.reset(reader, newCommit.getTree().getId());

            List<DiffEntry> diffs = formatter.scan(oldTree, newTree);

            for (DiffEntry diff : diffs) {
                // If you want *all* files, just do:
                // formatter.format(diff);
                // If you want to restrict to one file:
                if (diff.getNewPath().contains("Account_Object_Access.permissionset-meta.xml")) {
                    formatter.format(diff);
                }
            }
        }
    }
}

private static ObjectId findMergeBase(Repository repo, ObjectId a, ObjectId b) throws Exception {
    try (RevWalk walk = new RevWalk(repo)) {
        walk.setRevFilter(RevFilter.MERGE_BASE);

        RevCommit commitA = walk.parseCommit(a);
        RevCommit commitB = walk.parseCommit(b);

        walk.markStart(commitA);
        walk.markStart(commitB);

        RevCommit mergeBase = walk.next();
        return mergeBase != null ? mergeBase.getId() : null;
    }
}

}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions