10

假设以下代码已提交到 Git 存储库:

int test(){
   int a = 3;
   int b = 4;
   int c = a + b;
   return c;
}

并稍后更新为

int test(){
  return 7;
}

我目前有一个方法使用 JGit API 来访问提交上述内容的 Git 存储库并输出类似于以下内容的字符串:

int test(){
-int a = 3;
-int b = 4;
-int c = a + b;
-return c;
+return 7;
}

现在,我的要求发生了变化,只想知道更改行的行号。所以我想要类似以下的东西:

2 -int a = 3;
3 -int b = 4;
4 -int c = a + b;
5 -return c;
2 +return 7;

基本上,与 GitHub 应用程序在进行更新时提供的信息相同。

任何帮助将不胜感激 :)

如何计算 -/+ 行的片段:

            String oldHash = "ee3e216ab5047748a22e9ec5ad3e92834704f0cc";
        Git git = null;
        try {
            //the path where the repo is.
            git = Git.open(new File("C:\\Users\\Administrator\\Documents\\GitHub\\Trial"));
        } catch (IOException e1) {
            e1.printStackTrace();
        }
        Repository repository = git.getRepository();
        ObjectId old = null;
        ObjectId head = null;
        //a new reader to read objects from getObjectDatabase()
        ObjectReader reader = repository.newObjectReader();
        //Create a new parser.
        CanonicalTreeParser oldTreeIter = new CanonicalTreeParser();
        CanonicalTreeParser newTreeIter = new CanonicalTreeParser();
        List<DiffEntry> diffs = null;

        try {
            //parse a git repository string and return an ObjectId
            old = repository.resolve(oldHash + "^{tree}");
            head = repository.resolve("HEAD^{tree}");
            //Reset this parser to walk through the given tree
            oldTreeIter.reset(reader, old);
            newTreeIter.reset(reader, head);
            diffs = git.diff()//Returns a command object to execute a diff command
                    .setNewTree(newTreeIter)
                    .setOldTree(oldTreeIter)
                    .call();//returns a DiffEntry for each path which is different

        } catch (RevisionSyntaxException | IOException | GitAPIException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        //DiffLineCountFilter d = new DiffLineCountFilter();
        //out is the stream the formatter will write to
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        //Create a new formatter with a default level of context.
        DiffFormatter df = new DiffFormatter(out);
        //Set the repository the formatter can load object contents from.
        df.setRepository(git.getRepository());
        ArrayList<String> diffText = new ArrayList<String>();
        //A DiffEntry is 'A value class representing a change to a file' therefore for each file you have a diff entry
        for(DiffEntry diff : diffs)
        {
           try {
                 //Format a patch script for one file entry.
                df.format(diff);
                RawText r = new RawText(out.toByteArray());
                r.getLineDelimiter();


                diffText.add(out.toString());
                out.reset();
            } catch (IOException e) {
                e.printStackTrace();
            }

         }
4

3 回答 3

6

您需要从 diff 结果中区分 A 行索引和 B 行索引:

int linesAdded = 0;
int linesDeleted = 0;
int filesChanged = 0;
try {
    repo = new FileRepository(new File("repo/.git"));
    RevWalk rw = new RevWalk(repo);
    RevCommit commit = rw.parseCommit(repo.resolve("486817d67b")); // Any ref will work here (HEAD, a sha1, tag, branch)
    RevCommit parent = rw.parseCommit(commit.getParent(0).getId());
    DiffFormatter df = new DiffFormatter(DisabledOutputStream.INSTANCE);
    df.setRepository(repo);
    df.setDiffComparator(RawTextComparator.DEFAULT);
    df.setDetectRenames(true);
    List<DiffEntry> diffs;
    diffs = df.scan(parent.getTree(), commit.getTree());
    filesChanged = diffs.size();
    for (DiffEntry diff : diffs) {
        for (Edit edit : df.toFileHeader(diff).toEditList()) {
            linesDeleted += edit.getEndA() - edit.getBeginA();
            linesAdded += edit.getEndB() - edit.getBeginB();
        }
    }
} catch (IOException e1) {
    throw new RuntimeException(e1);
}
于 2016-08-14T22:04:31.187 回答
5

只是给任何可能遇到此问题的人的提示。我没有设法获得添加和删除行的行号,但我确实设法获得了一个字符串,该字符串仅包含添加和删除的行而没有其他未更改的行。

这只是通过添加以下行来完成:

   df.setContext(0);

在我在上面提供的代码段中,就在该行之前

   df.format(diff);
于 2013-12-01T16:57:32.897 回答
0

我是这样做的,但我不知道它是否正确

public void linesChangeInFile(Git git, List<RevCommit> commits, String fileName, String pathRepository) {
        try {
            List<RevCommit> commitsComparer = new ArrayList<>();
            List<String> linesChange = new ArrayList<>();

            for (int i = 0; i < commits.size() - 1; i++) {

                ObjectId commitIDOld = commits.get(i).getId();

                if (Validador.isFileExistInCommit(commits.get(i), getRepository(), fileName)) {

                    if (i != commits.size() - 1 && !commitsComparer.contains(commits.get(i))) {
                        ObjectId commitIDNew = commits.get(i + 1);
                        commitsComparer.add(commits.get(i));
                        linesChange.add(diff(git, commitIDOld.getName(), commitIDNew.getName(), fileName));
                    }

                    try (final FileInputStream input = new FileInputStream(pathRepository + "\\" + fileName)) {
                        currentLines = IOUtils.readLines(input, "UTF-8").size();
                    }
                }

            }

            Integer sumLinesAdd = 0;
            Integer sumLinesDel = 0;
            for (String lineChange : linesChange) {
                String[] lChange = lineChange.split(";");
                sumLinesAdd += Integer.parseInt(lChange[0]);
                sumLinesDel += Integer.parseInt(lChange[1]);
            }

            System.out.println("Lines Add total:" + sumLinesAdd);
            System.out.println("Lines Del total:" + sumLinesDel);
            System.out.println("Total lines change:" + (sumLinesAdd + sumLinesDel));

        } catch (RevisionSyntaxException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

private String diff(Git git, String commitIDOld, String commitIDNew, String fileName) {
        int linesAdded = 0;
        int linesDeleted = 0;
        DiffFormatter df = null;
        try {
            AbstractTreeIterator oldTreeParser = prepareTreeParser(getRepository(), commitIDOld);
            AbstractTreeIterator newTreeParser = prepareTreeParser(getRepository(), commitIDNew);

            List<DiffEntry> diffs = git.diff().setOldTree(oldTreeParser).setNewTree(newTreeParser)
                    .setPathFilter(PathFilter.create(fileName)).call();

            df = new DiffFormatter(DisabledOutputStream.INSTANCE);
            df.setRepository(getRepository());
            df.setDiffComparator(RawTextComparator.DEFAULT);
            df.setDetectRenames(true);

            for (DiffEntry entry : diffs) {
                // System.out.println("Entry: " + entry + ", from: " + entry.getOldId() + ", to:
                // " + entry.getNewId());
                // try (DiffFormatter formatter = new DiffFormatter(System.out)) {
                // formatter.setContext(0);
                // formatter.setRepository(repository);
                // formatter.format(entry);
                // }
                for (Edit edit : df.toFileHeader(entry).toEditList()) {
                    linesDeleted += edit.getEndA() - edit.getBeginA();
                    linesAdded += edit.getEndB() - edit.getBeginB();
                }
            }
        } catch (IOException | GitAPIException e) {
            System.err.println("Error:" + e.getMessage());
        }

        return linesAdded + ";" + linesDeleted;

    }
于 2018-05-10T13:41:53.280 回答