Giter Club home page Giter Club logo

jgit-cookbook's Introduction

jgit-cookbook

Build Status Gradle Status Tag

Provides examples and code snippets for the JGit Java Git implementation.

The JGit framework is rich and diverse, it has two layers, a low-level api and a higher-level set of porcelain commands. This can be a bit intimidating at first as there are lots of classes, some of which are not relevant for most tasks.

This project tries to provide a collection of ready-to-run snippets which provide a quick start for building functionality using JGit.

Please make sure to take a look at the nicely written introduction and also use the existing JavaDoc and the User Guide as well, as they are well done and provide detailed information and a general overview of JGit respectively.

Note: Please use sites such as http://stackoverflow.com for general questions about JGit usage, not issues in this project. Issues should be used for problems with snippets and suggestions of missing snippets. Snippets from good answers on stackoverflow can then be included here, naturally.

Getting started

Grab it
git clone https://github.com/centic9/jgit-cookbook.git
Build it and create Eclipse project files
When using Maven
mvn dependency:sources eclipse:eclipse package
When using Gradle
./gradlew eclipse check

Run it

Each snippet is a small standalone Java application, so you can simply  
import the project into your favourite IDE and execute the snippets there.

Currently the following snippets are available

General Repository handling
Porcelain commands
Commands working with remote repositories
Low-level API
GitServlet
  • There is a standalone sub-project in directory httpserver which starts up a simple HTTP Git server based on the JGit GitServlet.

Just import the project in your IDE and start up the Main application, see the Comments in the code for more details.

Another simple way to start the sample-server is to run ./gradlew run in the httpserver-directory.

Useful code elsewhere

cf-ops-automation-broker

Missing snippets

Support this project

If you find these snippets useful and would like to support it, you can Sponsor the author

Sources

The following sources were used to build the snippets:

Other applications using JGit

Ruby Build

Contribute

Please note that the list of snippets is not yet complete, probably never will. If you are missing things or have suggestions how to improve or add snippets, please either send pull requests or create issues.

Licensing

Copyright 2013-2023 Dominik Stadler

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

jgit-cookbook's People

Contributors

bdw429s avatar blankspaceplus avatar bryce-anderson avatar centic9 avatar g-pechorin avatar gamerson avatar jlleitschuh avatar jmini avatar jordanmartinez avatar linwancen avatar rmoehn avatar sergekukharev avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jgit-cookbook's Issues

Show changed files between two commits without a local clone

Hello,

I've got a lot of help from your porcelain commands. I much appreciated.

Now I am in a situation where I need to get changed files between commits (similar to ShowChangedFilesBetweenCommits) but without a local clone. I need to check the commits across multiple git repositories and some of the repositories are so big like more than 1GB. I need to clean up my local repo once I get the information. So cloning the repository each time to get the changed file information is too costly. I wonder if there is any way to get the changed file information remotely, just like we can see the changed files on a commit on github.com online.

Thank you so much in advance!
Kevin

Conflict detection

I would like to detect conflicts ( by push and probably by pull ) . I mean situations when:

  • I try to commit and push a file which was already modified prior by another user in GIT
  • I try to do a pull and my file was modified.
    How can I list this files, and mark them as merged after I edited them?

using FileRepositoryBuilder with setGitDir() does not return valid submodule Repository

The approach to get a Repository object for a sub-repository on

try (Repository subRepo = builder.setGitDir(new File("testrepo/.git"))
.readEnvironment() // scan environment GIT_* variables
.findGitDir() // scan up the file system tree
.build()) {
if (subRepo.isBare()) {
throw new IllegalStateException("Repository at " + subRepo.getDirectory() + " should not be bare");
}
}

does not work.

I am aware this is under unfinished however it seems to be used out there and leads to confusion as illustrated on https://stackoverflow.com/questions/26090139/jgit-reading-commits-from-a-submodule

The suggestion below the SO answer is to use absolute path for the setGitDir() call however that does not help. The problem is that gitDir property is persistent w.r.t. findGitDir() and the resulting Repository object will have something like /tmp/gitinit9778898520347794239.test/testrepo/.git while it should have /tmp/gitinit9778898520347794239.test/.git/modules/testrepo. As a result, calls like subRepo.getBranch() will return null.

To fix this, replace the try-with-resources block with

Repository subRepo = SubmoduleWalk.getSubmoduleRepository(mainRepo, "testrepo");

and perhaps add some assert other than isBare().

LFS

Hello,

Thank you for this repository, very helpful!
I'm working with a repository setup using LFS. When cloning the repository with jgit, it doesn't however resolve the large files indexed with LFS.

With my local git client which has LFS installed & configured, when I clone, I have the large files cloned with it.

From my research, it looks like jgit supports LFS, but I can't seem to find any indicators as to how to setup it up / use it.

Would you have any pointers here?

Thank you,

Example using GitServlet?

It would be great if there was a snippet around using GitServlet.

It looks like JGit has support for serving up git repos over http but documentation on exactly how to do this is few and far between. There's some unit tests and other projects (eg gitblit) but a simple, short snippet would be great.

How to commit only files that have changed

Hello,

I have been trying to use the CommitCommand so that it only commits the files in the repo that have changed.
Every time I run "commit.setAll(true).setMessage(msg).call()" it logs a commit event if no files have changed...

This could be a nice addition to the list ;-)

fetch tags via commitId

Note: Please use sites such as http://stackoverflow.com for general questions about JGit usage, not issues in this project. Issues should be used for problems with snippets and suggestions of missing snippets. Snippets from good answers on stackoverflow can then be included here, naturally.

How to achieve fork function?

hi ,i want achieve git fork function base on java language,just like "git remote add upstream" to my remote repository,do you have any example? I did not find it

Illustrate support for JGit server in integration tests

Thanks for this great repo. This really helped me with using jgit. As I was trying to write integration tests for my code using jgit as a client, I struggled find the right syntax for starting an embedded jgit server without the burden of fetching a servlet container when using the gitservlet

If this can help, here is the syntax I ended up using
https://github.com/orange-cloudfoundry/cf-ops-automation-broker/blob/ac8650892a25409ba8d410fb5fad3b5c5a24938a/cf-ops-automation-broker-core/src/main/java/com/orange/oss/cloudfoundry/broker/opsautomation/ondemandbroker/git/GitServer.java#L36-L118

A simple example of starting the jgit server in an integration test
https://github.com/orange-cloudfoundry/cf-ops-automation-broker/blob/ac8650892a25409ba8d410fb5fad3b5c5a24938a/cf-ops-automation-cloudflare-broker/src/test/java/com/orange/oss/cloudfoundry/broker/opsautomation/ondemandbroker/cloudflare/CloudFlareServiceProvisionningTest.java#L60-L84

Please let me know if this could be useful for others and whether a PR would help.

How to manage ssh key?

Can I manage ssh key with JGit? We can manage users ssh key in github or gitlab ,But I don't know JGit to work.

I'm suspecting this is a dumb question, but however can't seem to find the answer...
Thanks.

When I want to submit an operation to delete a file, I find that I cannot submit

Thanks for this great repo. This really helped me with using jgit.
version:

org.eclipse.jgit
org.eclipse.jgit
5.5.0.201909110433-r

When I want to submit an operation to delete a file, I find that I cannot submit.
I found a change by executing 'git status'

`On branch master
Your branch is up to date with 'origin/master'.

Changes not staged for commit:
(use "git add/rm ..." to update what will be committed)
(use "git checkout -- ..." to discard changes in working directory)

deleted:    gitlab-ci/fdev-deploy.properties

no changes added to commit (use "git add" and/or "git commit -a")`

then; I execute code via jgit

        git.add().addFilepattern(".").call();
        git.commit().setMessage(filename).call();
        git.push().setRemote("origin").setCredentialsProvider(provider).call();

Finally, the operation of deleting my files was not submitted to the remote warehouse

countFiles or countLines?

In https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/ShowBlame.java

Is the method private static int countFiles(Repository repository, ObjectId commitID, String name) throws IOException counting lines or counting files? If lines then why is it called countFiles?

I'm trying to understand how to use BlameCommand and your examples are useful for my over all git and jgit understanding. Thank you. Just confused it this a typo or am I missing something?

I'm trying to use jGit to tell me who is the author or authors of a set of lines of a file. Understanding your work would help.

.JAR File issue

Based on the example given, we have to import org.dstadler.jgit.helper.CookbookHelper in the project. But this will give me an error, I assumed that we need to include a specific .JAR file for CookbookHelper. However there is no specific file for this CookbookHelper in Google.
Is there any solution for this particular problem? Any help will be appreciated !

Can not located some files whose change type is RENAME.

Note: Please use sites such as http://stackoverflow.com for general questions about JGit usage, not issues in this project. Issues should be used for problems with snippets and suggestions of missing snippets. Snippets from good answers on stackoverflow can then be included here, naturally.
Excuse me!!!!
I followed the example file DiffRenamedFile.java to complete a method to determine whether a file is a renamed file. It works well mostly, however, sometimes it can not located a renamed file, and it also does not work when I use DiffRenamedFile.runDiff() method. But others could be located well.
Another world, the similarity index of the file that can not be located is only 56%.
Thanks :-)

ssh key connect?

Note: Please use sites such as http://stackoverflow.com for general questions about JGit usage, not issues in this project. Issues should be used for problems with snippets and suggestions of missing snippets. Snippets from good answers on stackoverflow can then be included here, naturally.

Git add not working through jgit

Hi
jgit version:compile group: 'org.eclipse.jgit', name: 'org.eclipse.jgit', version: '4.10.0.201712302008-r'

Trying to do:Rename .sql files in project structure before they are pushed to repo.To achieve this,I have written a pre commit hook where I am trigerring a gradle run task which invokes a java programme that by using JGIT API finds files ending with .sql (new modified)and renames them in proper naming format.

In this I am using git add API to add newly renamed file to git index and I expect that newly renamed and added file should also be commited when git commit runs.But this is not happening and newly renamed file is showing under untracked files.
https://stackoverflow.com/questions/48704380/git-pre-commit-hook-triggering-gradle-run-task-which-renamed-files-in-db-migrati

Stackover flow link where I have given full description.

SelfContainedExample.txt
GitStatusFileAndRename.txt

How to get the line number of a file diff

Hi All,
I would like to use jgit to operate my git. Now I meet a problem that, how could I get the changed line number using Jgti.
For now, the jgit return a string like this:

diff --git a/pom.xml b/pom.xml
index 5d79f75..6d223e2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -161,3 +161,5 @@

+ +test added here ==============================

can jgit return the line number before "+test added here" ?
Eg.

diff --git a/pom.xml b/pom.xml
index 5d79f75..6d223e2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -161,3 +161,5 @@

+ **line 98** + **line 99** test added here

The question about commit

Hello, is it possible to use jgit to commit local changes to another specified branch without switching to the specified branch?

delete remote branch

How to delete remote branch with JGit? I search over Google and text following code.

   git.branchDelete()
            .setBranchNames(fullBranch)
            .call();

    RefSpec refSpec = new RefSpec()
            .setSource(null)
            .setDestination(fullBranch);

    git.push()
            .setRefSpecs(refSpec)
            .setRemote("origin")
            .call();

but it does not work at all. It just deletes local branch.

Jgit+apche sshd ssh

I am using JGIT+Apache sshd ssh as the GIT hosting service, and I am currently encountering an issue.
How can I obtain the requested warehouse address in PublicickeyAuthenticator.authenticate.ServerSession? Or is there another way to obtain the warehouse address during authentication? This way, I can easily load the warehouse key based on the address

I had problems opening a existing repository and found the problem

I'm not that good at using forking, pull requests so i will comment this here

at
OpenRepository.java

FileRepositoryBuilder builder = new FileRepositoryBuilder();
Repository repository = builder.setGitDir(new File("/my/git/directory"))
            .readEnvironment() // scan environment GIT_* variables
            .findGitDir() // scan up the file system tree
            .build();

System.out.println("Having repository: " + repository.getDirectory());

repository.close();

this part doesn't work properly
i tried to get a status from my own repository but problems occured that my repository is bare but it isn't

if i try to get a status from this repository it assumes the repo bare
so this means it's not properly opened

It should be changed just a little

I think setGitDir() method is for making a new Repository and this occurs the problem

the source like this works properly(didn't tested a lot but status call works properly)

FileRepositoryBuilder builder = new FileRepositoryBuilder();
Repository repository = builder.findGitDir(new File("/my/git/directory"))
            .readEnvironment() // scan environment GIT_* variables
            .build();

System.out.println("Having repository: " + repository.getDirectory());

repository.close();

please respond and update the cook-book if this is right
sorry for bad english =)

bad code

Note: Please use sites such as http://stackoverflow.com for general questions about JGit usage, not issues in this project. Issues should be used for problems with snippets and suggestions of missing snippets. Snippets from good answers on stackoverflow can then be included here, naturally.

https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/OpenRepository.java
The last line "FileUtils.deleteDirectory(dir);" delete all my code!Thanks to I hava push to my git rep!

Could not push to Remote Repository on github pages

Dear JGit Cookbook Developers,
I am very happy with your guide when I found this!

I have done with some task like Clone Remote Repository, it works well.

But I could not push some new files on remote Repository to github,
I want to upload some file into my github repository here https://tranninhnhatgau:[email protected]/tranninhnhatgau/tranninhnhatgau.git

But it raise error as below:

Cloning from https://tranninhnhatgau:[email protected]/tranninhnhatgau/tranninhnhatgau.git to C:\Users\*~1.LOC\AppData\Local\Temp\TestGitRepository7048146356004889332
Cloning from file://C:\Users\*~1.LOC\AppData\Local\Temp\TestGitRepository7048146356004889332 to C:\Users\*~1.LOC\AppData\Local\Temp\TestGitRepository7018905737604261703
Result: Git[Repository[C:\Users\*~1.LOC\AppData\Local\Temp\TestGitRepository7018905737604261703\.git]]
Exception in thread "main" org.eclipse.jgit.api.errors.TransportException: origin: not found.
	at org.eclipse.jgit.api.PushCommand.call(PushCommand.java:191)
	at org.dstadler.jgit.unfinished.PushToRemoteRepository.main(PushToRemoteRepository.java:78)
Caused by: org.eclipse.jgit.errors.NoRemoteRepositoryException: origin: not found.
	at org.eclipse.jgit.transport.TransportLocal$1.open(TransportLocal.java:132)
	at org.eclipse.jgit.transport.TransportBundleFile$1.open(TransportBundleFile.java:107)
	at org.eclipse.jgit.transport.Transport.open(Transport.java:552)
	at org.eclipse.jgit.transport.Transport.openAll(Transport.java:368)
	at org.eclipse.jgit.api.PushCommand.call(PushCommand.java:155)
	... 1 more

Here is my code:

package org.dstadler.jgit.unfinished;

/*
   Copyright 2013, 2014 Dominik Stadler

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */

import org.apache.commons.io.FileUtils;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;

import java.io.File;
import java.io.IOException;



/**
 * Note: This snippet is not done and likely does not show anything useful yet
 *
 * @author dominik.stadler at gmx.at
 */
public class PushToRemoteRepository {

//    private static final String REMOTE_URL = "https://github.com/github/testrepo.git";
    private static final String REMOTE_URL = "https://tranninhnhatgau:[email protected]/tranninhnhatgau/tranninhnhatgau.git";
    //https:tranninhnhatgau:200213200213200213//github.com/tranninhnhatgau/tranninhnhatgau.git
    //git clone https://myusername:[email protected]/path_to/myRepo.git


    public static void main(String[] args) throws IOException, GitAPIException {
        // prepare a new folder for the cloned repository
        File localPath = File.createTempFile("TestGitRepository", "");
        if(!localPath.delete()) {
            throw new IOException("Could not delete temporary file " + localPath);
        }

        // then clone
        System.out.println("Cloning from " + REMOTE_URL + " to " + localPath);
        try (Git result = Git.cloneRepository()
                .setURI(REMOTE_URL)
                .setDirectory(localPath)
                .call()) {
            // prepare a second folder for the 2nd clone
            File localPath2 = File.createTempFile("TestGitRepository", "");
            if(!localPath2.delete()) {
                throw new IOException("Could not delete temporary file " + localPath2);
            }

            // then clone again
            System.out.println("Cloning from file://" + localPath + " to " + localPath2);
            try (Git result2 = Git.cloneRepository()
                    .setURI("file://" + localPath)
                    .setDirectory(localPath2)
                    .call()) {
                System.out.println("Result: " + result2);

                // now open the created repository
                FileRepositoryBuilder builder = new FileRepositoryBuilder();
                try (Repository repository = builder.setGitDir(localPath2)
                        .readEnvironment() // scan environment GIT_* variables
                        .findGitDir() // scan up the file system tree
                        .build()) {
                    try (Git git = new Git(repository)) {
                        git.push()
                                .call();
                    }

                    System.out.println("Pushed from repository: " + repository.getDirectory() + " to remote repository at " + REMOTE_URL);
                }
            }
        }

        // clean up here to not keep using more and more disk-space for these samples
        FileUtils.deleteDirectory(localPath);
    }
}

Can anybody help me!

Thank you and Best Regards,

What are the difference between the two ways of opening a Git repository besides the 'close' difference?

I've noticed in your code that you will often use these lines to open a git repository:

FileRepositoryBuilder builder = new FileRepositoryBuilder();
Repository repository = builder.setGitDir(repoDir)
                .readEnvironment() // scan environment GIT_* variables
                .findGitDir() // scan up the file system tree
                .build()
Git git = new Git(repository);

I've tried another way using the factory methods:

Git git = Git.init().setGitDir(repoDir).call();

In the first way, it seems you need to call repository.close() and git.close() in order to fully close the resources. In the second way, since it was initialized using the factory method, only git.close() needs to be called, right?

My question is, besides the note I mentioned above, are there any other differences between the two?

Missing Tree Exception being thrown while parsing the ObjectId

		try{
			def localGitDirectory = localRepoPath.toString()
			
			def localRepo = new File(localGitDirectory)
			
			FileRepositoryBuilder builder = new FileRepositoryBuilder();
			Repository repository = builder.setGitDir(localRepo).readEnvironment().findGitDir().build()
			
			ObjectId oldHead = repository.resolve("d573eba6495bc322eea56b66934a298a8d27ebd4");
			ObjectId head = repository.resolve("728c310b2766749f80a5454bacf5a286f7dce3bd");
			System.out.println("Printing diff between tree: " + oldHead + " and " + head);
			
			ObjectReader reader = repository.newObjectReader()
			CanonicalTreeParser oldTreeIter = new CanonicalTreeParser();
			oldTreeIter.reset(reader, oldHead);
			CanonicalTreeParser newTreeIter = new CanonicalTreeParser();
			newTreeIter.reset(reader, head);
			
			Git git = new Git(repository)
			
			List<DiffEntry> diffs= git.diff()
			.setNewTree(newTreeIter)
			.setOldTree(oldTreeIter)
			.call();
			for (DiffEntry entry : diffs) {
			  System.out.println("Entry: " + entry);
			}

		}
		catch(GitAPIException e){
				System.out.println(e)
		}
    }

The line of oldTreeIter.reset(reader, oldHead) is throwing an exception:
Message: Missing tree d573eba6495bc322eea56b66934a298a8d27ebd4

Can you please help me out regarding this ?

Convert project into Spock Test

Rather than writing a separate class for each of your tests (such as CleanUntrackedFiles.java), why not convert your tests into a Spock test?

This example code (taken from CleanUntrackedFiles.java):

try (Repository repository = CookbookHelper.createNewRepository()) {
            System.out.println("Repository at " + repository.getWorkTree());

            File untrackedFile = File.createTempFile("untracked", ".txt", repository.getWorkTree());
            File untrackedDir = File.createTempFile("untrackedDir", "", repository.getWorkTree());
            untrackedDir.delete();
            untrackedDir.mkdirs();

            System.out.println("Untracked exists: " + untrackedFile.exists() + " Dir: " + untrackedDir.exists() + "/" + untrackedDir.isDirectory());

            try (Git git = new Git(repository)) {
                Set<String> removed = git.clean().setCleanDirectories(true).call();
                for(String item : removed) {
                    System.out.println("Removed: " + item);
                }
                System.out.println("Removed " + removed.size() + " items");
            }

            System.out.println("Untracked after: " + untrackedFile.exists() + " Dir: " + untrackedDir.exists() + "/" + untrackedDir.isDirectory());
        }

might then look a little like this:

class JGitExamples extends Specification {

    public static final LOCAL_PATH = Paths.get("TestGitRepository")

    @Shared
    Repository repository

    @Shared
    Git git

    def setup() {
        // prepare a new folder
        Files.createDirectory(LOCAL_PATH)

        // create the directory
        repository = FileRepositoryBuilder.create(LOCAL_PATH.resolve(".git").toFile()).create();

        git = new Git(repository)
    }

    def "clean untracked files example"() {
        given: "an untracked file..."
        File untrackedFile = File.createTempFile("untracked", ".txt", repository.getWorkTree());

        and: "...and an untracked directory..."
        File untrackedDir = File.createTempFile("untrackedDir", "", repository.getWorkTree());
        untrackedDir.mkdirs();

        and: "... that exist"
        untrackedFile.exists()
        untrackedDir.exists()

        when: "The repo is cleaned (including directories)"
        Set<String> removed = git.clean().setCleanDirectories(true).call();

        and: "some helpful println statements that show what was removed"
        removed.each { println "Removed: $it" }
        println "Removed ${removed.size()} items"

        then: "the untracked file and directory should no longer exist"
        !untrackedFile.exists()
        !untrackedDir.exists()
    }

    def cleanup() {
        git.close()
        repository.close()
        Files.deleteIfExists(LOCAL_PATH)
    }

}

Snippet for tracking accross Renames ie. log --follow

I'm dying trying to figure this one out,
I'm going to share my progress, just in case it helps you make a snippet for it - it's very difficult for me to keep track of which methods/datatypes to use with the jGit Api

Please excuse the doubling of this function, I made a second function (overloading for second parameter is almost the only difference) to try to walk through commits related to the file i'm targeting but after a file is moved, its history is still not tracked, I feel i've taken it too far but I can't stop now

`
package org.xxx.xxx.common;
import java.util.ArrayList;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.sql.Timestamp;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.adeptnet.guardian.ex.GitException;
import org.apache.commons.io.FileUtils;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.diff.DiffEntry;
import org.eclipse.jgit.diff.DiffFormatter;
import org.eclipse.jgit.diff.RenameDetector;
import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.NoWorkTreeException;
import org.eclipse.jgit.errors.RevisionSyntaxException;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectLoader;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
import org.eclipse.jgit.treewalk.CanonicalTreeParser;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.FileTreeIterator;
import org.eclipse.jgit.treewalk.filter.AndTreeFilter;
import org.eclipse.jgit.treewalk.filter.PathFilter;
import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
import org.eclipse.jgit.treewalk.filter.TreeFilter;
import org.gitective.core.CommitUtils;

public List<FileVersion> getHistoryByFilename(String dir) throws FileException {
    List<RevCommit> commitsList = new ArrayList<>();
    List<FileVersion> fileList = new ArrayList<>();
    try {
        LOG.log(Level.INFO, dir);
        RevWalk revWalk = new RevWalk(repo);
        revWalk.setTreeFilter(
                AndTreeFilter.create(
                        //a possibility could be to add the 'old path' here and get those commits too
                        PathFilterGroup.createFromStrings(dir),
                        TreeFilter.ALL
                )
        );
        LogFollowCommand betterLogCommand = new LogFollowCommand(repo, dir);
        ArrayList<String> oldPaths = betterLogCommand.getOldPaths();
        oldPaths.forEach((t) -> {
            try {
                fileList.addAll(getHistoryByFilename(t, fileList));
            } catch (FileException ex) {
                LOG.log(Level.WARNING, "Epic fail on inner rename recursion loop", ex);
            }
        });

        for (RevCommit revCommit : betterLogCommand.call()) {
            LOG.log(Level.INFO, revCommit.getFullMessage());

            RevTree tree = revCommit.getTree();
            try (TreeWalk treeWalk = new TreeWalk(repo)) {
                treeWalk.addTree(tree);
                treeWalk.setRecursive(true);
                treeWalk.setFilter(PathFilter.create(dir)); 

                while (treeWalk.next()) {

                    ObjectId objectId = treeWalk.getObjectId(0); 
                    ObjectLoader loader = repo.open(objectId);
                    InputStream is = loader.openStream();
                    FileVersion pew = new FileVersion(convertStreamToString(is), String.valueOf(loader.getType()), new Timestamp(revCommit.getCommitTime() * 1000L));
                    fileList.add(pew);
                    // LOG.info("found a file at " + treeWalk.getPathString() + ": with commit type of" + tree.);
                    is.close();
                }
            }
        }
    } catch (IncorrectObjectTypeException ex) {
        LOG.log(Level.SEVERE, "Found a broken object while attempting to find history of File ", ex);
    } catch (IOException | GitAPIException ex) {
        LOG.log(Level.SEVERE, "Failed to read from disk or jGit broke", ex);
    }
    fileList.sort((o1, o2) -> {
        return o2.getVersionDate().compareTo(o1.getVersionDate());
    });
    return fileList;
}

public List<FileVersion> getHistoryByFilename(String dir, List<FileVersion> fileList) throws FileException {

    try {

        RevWalk revWalk = new RevWalk(repo);
        revWalk.setTreeFilter(
                AndTreeFilter.create(
                        //a possibility could be to add the 'old path' here and get those commits too
                        PathFilterGroup.createFromStrings(dir),
                        TreeFilter.ALL
                )
        );
        //+"^1"

        LogFollowCommand betterLogCommand = new LogFollowCommand(repo, dir);
        ArrayList<String> oldPaths = betterLogCommand.getOldPaths();
        oldPaths.forEach((t) -> {
            try {
                fileList.addAll(getHistoryByFilename(t, fileList));
            } catch (FileException ex) {
                LOG.log(Level.WARNING, "Epic fail on inner rename recursion loop", ex);
            }
        });
        for (RevCommit revCommit : betterLogCommand.call()) {
            LOG.log(Level.INFO, revCommit.getFullMessage());

            RevTree tree = revCommit.getTree();
            try (TreeWalk treeWalk = new TreeWalk(repo)) {
                treeWalk.addTree(tree);
                treeWalk.setRecursive(true);
                treeWalk.setFilter(PathFilter.create(dir));   //WHY DID I DO THIS

                while (treeWalk.next()) {

                    ObjectId objectId = treeWalk.getObjectId(0);  //WHY DID I DO THIS
                    ObjectLoader loader = repo.open(objectId);

                    InputStream is = loader.openStream();

                    // and then one can the loader to read the file
                    //System.out.println(loader.toString());
                    //loader.copyTo(System.out);
                    FileVersion pew = new FileVersion(convertStreamToString(is), String.valueOf(loader.getType()), new Timestamp(revCommit.getCommitTime() * 1000L));
                    //LOG.info(pew.toString());
                    fileList.add(pew);
                    LOG.info("found a file at " + treeWalk.getPathString() + ": \n" + pew.getConfig());
                    is.close();
                }
            }
        }
    } catch (IncorrectObjectTypeException ex) {
        LOG.log(Level.SEVERE, "Incorrect object type found in Git, search failed.", ex);
    } catch (IOException | GitAPIException ex) {
        LOG.log(Level.SEVERE, "IO failure or Git Exception.", ex);
    }
    return configList;
}

static String convertStreamToString(InputStream is) {
    java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
    return s.hasNext() ? s.next() : "";
}

`

I tried modifying the LogCommand to track renames for use in the above code:
`
package org.xxx.xxx.common;

import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.diff.DiffEntry;
import org.eclipse.jgit.diff.RenameDetector;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.lib.ObjectLoader;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import org.eclipse.jgit.treewalk.filter.PathFilter;

/**
*

/
/
*

  • Create a Log command that enables the follow option: git log --follow -- < path

  • User: OneWorld Example for usage: ArrayList commits = new

  • LogFollowCommand(repo,"src/com/mycompany/myfile.java").call();
    */
    public class LogFollowCommand {

    private static final Logger LOG = Logger.getLogger(LogFollowCommand.class.getName());
    private final Repository repository;
    private String path;
    private Git git;
    private ArrayList oldPaths;

    /**

    • Create a Log command that enables the follow option: git log --follow -- < path
    • @param repository
    • @param path
      */
      public LogFollowCommand(Repository repository, String path) {
      this.repository = repository;
      this.path = path;
      oldPaths = new ArrayList();
      }

    /**

    • Returns the result of a git log --follow -- < path >

    • @return

    • @throws IOException

    • @throws MissingObjectException

    • @throws GitAPIException
      */
      public ArrayList call() throws IOException, MissingObjectException, GitAPIException {
      oldPaths.add(path);
      ArrayList commits = new ArrayList();
      git = new Git(repository);
      RevCommit start = null;
      do {
      Iterable log = git.log().addPath(path).call();
      //tip from stackoverflow question, not sure how to implement this
      //But I think you should also add the start ObjectId (if !=null) to the log command in call(). What now happens is that when the file with the old name is being added again AFTER the rename, it will show up in the log of the new file.
      for (RevCommit commit : log) {
      if (commits.contains(commit)) {
      start = null;
      } else {
      start = commit;
      commits.add(commit);
      }
      }
      if (start == null) {
      return commits;
      }
      } while ((path = getRenamedPath(start)) != null);

      return commits;
      }

    /**

    • Checks for renames in history of a certain file. Returns null, if no

    • rename was found. Can take some seconds, especially if nothing is

    • found... Here might be some tweaking necessary or the LogFollowCommand

    • must be run in a thread.

    • @param start

    • @return String or null

    • @throws IOException

    • @throws MissingObjectException

    • @throws GitAPIException
      */
      private String getRenamedPath(RevCommit start) throws IOException, MissingObjectException, GitAPIException {
      Iterable allCommitsLater = git.log().add(start).call();
      for (RevCommit commit : allCommitsLater) {

       TreeWalk tw = new TreeWalk(repository);
       //have to split off path to config and only search for filename, or file moves are lost
       tw.setFilter(PathFilter.create(path.split("/")[path.split("/").length - 1]));
       tw.addTree(commit.getTree());
       tw.addTree(start.getTree());
       tw.setRecursive(true);
       RenameDetector rd = new RenameDetector(repository);
       rd.addAll(DiffEntry.scan(tw));
       List<DiffEntry> files = rd.compute();
       for (DiffEntry diffEntry : files) {
      
           if ((diffEntry.getChangeType() == DiffEntry.ChangeType.RENAME || diffEntry.getChangeType() == DiffEntry.ChangeType.COPY) && diffEntry.getNewPath().contains(path)) {
               LOG.info("Found: " + diffEntry.toString() + " return " + diffEntry.getOldPath());
               oldPaths.add(diffEntry.getOldPath());
               ObjectLoader miniloader = repository.open(diffEntry.getId(DiffEntry.Side.OLD).toObjectId());
               InputStream mini_in = miniloader.openStream();
               LOG.info(convertStreamToString(mini_in));
      
               return diffEntry.getOldPath();
           }
       }
      

      }
      return null;
      }

    public ArrayList getOldPaths() {

     return oldPaths;
    

    }

    static String convertStreamToString(InputStream is) {
    java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\A");
    return s.hasNext() ? s.next() : "";
    }
    }
    `
    and finally, for ease of use, here's the class I created for storing the different versions (to loop over and display on an interface)

`
package org.adeptnet.guardian.entity;

import java.sql.Timestamp;

/**
*

  • @author AJ
    */
    public class FileVersion implements FileVersionInterface {

    private final String fileText;
    private final int userId = 0;
    private final Timestamp versionDate;
    private final String changeType;

    public FileVersion(String fileText, String changeType, Timestamp versionDate) {
    this.fileText= fileText;
    this.versionDate = versionDate;
    this.changeType = changeType;
    }

    @OverRide
    public String toString() {
    return "@" + versionDate.toString() + " file length:" + fileText.length() + " change type: " + changeType;
    }

    @OverRide
    public int getUserId() {
    return userId;
    }

    @OverRide
    public Timestamp getVersionDate() {
    return versionDate;
    }

    @OverRide
    public String getFile() {
    return fileText;
    }

}

`

I'm very sorry, i'm struggling to get the markdown to work correctly with these code blocks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.