git學習之jgit

1、簡介

jgit是存java實現的git版本控制,學習jgit能夠更好的理解學習git,其源代碼託管在github上JGit。主要的模塊以下:java

  • org.eclipse.jgit 核心實現,包括git命令、協議等
  • org.eclipse.jgit.archive 支持導出各類壓縮的格式
  • org.eclipse.jgit.http.server 支持http協議的服務器,主要提供GitServlet

使用JGit的軟件有:EGit(Eclipse git版本管理插件)、Gitblit等。其maven配置座標爲:git

<dependency>
        <groupId>org.eclipse.jgit</groupId>
        <artifactId>org.eclipse.jgit</artifactId>
        <version>4.11.0.201803080745-r</version>
</dependency>

2、API使用

1.基本概念

官方文檔github

  • Repository 包括全部的對象和引用,用來管理源碼
  • AnyObjectId 表示SHA1對象,能夠得到SHA1的值,進而能夠得到git對象
  • Ref 引用對象,表示.git/refs下面的文件引用 Ref HEAD = repository.getRef("refs/heads/master");
  • RevWalk 能夠遍歷提交對象,並按照順序返回提交對象
  • RevCommit 表明一個提交對象
  • RevTag 表明標籤對象
  • RevTree 表明樹對象api

    2. 建立本地倉庫

    Git.init().setGitDir(new File("D:\\source-code\\temp\\.git")).call();--------------不推薦,由於這樣新建出來在.git/config文件下面多了一個core.workTree屬性,其值爲user.dir屬性,而不是工做區爲temp目錄
    //推薦以下方式:
    File dir = new File("D:\\source-code\\temp\\.git");
            Git.init().setGitDir(dir).setDirectory(dir.getParentFile()).call();

    只須要簡單的一行代碼就能夠建立本地倉庫,能夠調用setBare方法來設置版本庫是否爲裸版本庫。
    注意org.eclipse.jgit.api.Git這個類,其方法返回全部支持的git命令
    git學習之jgit
    另外對於全部的命令,使用Builder模式。服務器

    3.配置本地倉庫

    Repository build = null;
        try {
            build = new RepositoryBuilder().setGitDir(new File("D:\\source-code\\temp\\.git")).setMustExist(true)
                    .build();
            build.getConfig().setString(ConfigConstants.CONFIG_USER_SECTION, null, ConfigConstants.CONFIG_KEY_NAME,
                    "xxxx");
            build.getConfig().save();
    
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            if (null != build) {              //爲了節省篇幅,後續代碼省略調Git對象和Repository對象的close方法
                build.close();
            }
        }

設置完之後能夠到.git/config目錄下面看到配置生效。版本庫api並無直接提供修改系統或者用戶級別的配置(--system、--global),若是用戶須要修改這兩個級別的,能夠參考FileRepository 的構造函數:eclipse

if (StringUtils.isEmptyOrNull(SystemReader.getInstance().getenv(
                Constants.GIT_CONFIG_NOSYSTEM_KEY)))
            systemConfig = SystemReader.getInstance().openSystemConfig(null,
                    getFS());
        else
            systemConfig = new FileBasedConfig(null, FS.DETECTED) {
                @Override
                public void load() {
                    // empty, do not load
                }

                @Override
                public boolean isOutdated() {
                    // regular class would bomb here
                    return false;
                }
            };
        userConfig = SystemReader.getInstance().openUserConfig(systemConfig,
                getFS());

        loadSystemConfig();        //load完之後,能夠直接修改config對象了,最後save一下就能夠了
        loadUserConfig();

4.修改本地倉庫

AddCommand能夠把工做區的內容添加到暫存區。maven

Git git = Git.open(new File("D:\\source-code\\temp\\.git"));
git.add().addFilepattern(".").call(); // 至關與git add -A添加全部的變動文件git.add().addFilepattern("*.java")這種形式是不支持的
git.add().addFilepattern("src/main/java/").call(); // 添加目錄,能夠把目錄下的文件都添加到暫存區
//jgit當前還不支持模式匹配的方式,例如*.java

CommitCommand用於提交操做ide

Git git =Git.open(new File("D:\\source-code\\temp\\user1\\.git"));
CommitCommand commitCommand = git.commit().setMessage("master 23 commit").setAllowEmpty(true);
commitCommand.call();

5.查看本地倉庫

StatusCommand命令等同於git status命令函數

Git git = Git.open(new File("D:\\source-code\\temp-1\\.git"));
    Status status = git.status().call();        //返回的值都是相對工做區的路徑,而不是絕對路徑
    status.getAdded().forEach(it -> System.out.println("Add File :" + it));      //git add命令後會看到變化
    status.getRemoved().forEach(it -> System.out.println("Remove File :" + it));  ///git rm命令會看到變化,從暫存區刪除的文件列表
    status.getModified().forEach(it -> System.out.println("Modified File :" + it));  //修改的文件列表
    status.getUntracked().forEach(it -> System.out.println("Untracked File :" + it)); //工做區新增的文件列表
    status.getConflicting().forEach(it -> System.out.println("Conflicting File :" + it)); //衝突的文件列表
    status.getMissing().forEach(it -> System.out.println("Missing File :" + it));    //工做區刪除的文件列表

LogCommand至關於git log命令學習

//提取某個做者的提交,並打印相關信息
Git git = Git.open(new File("D:\\source-code\\temp-1\\.git"));
DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Iterable<RevCommit> results = git.log().setRevFilter(new RevFilter() {
    @Override
    public boolean include(RevWalk walker, RevCommit cmit)
       throws StopWalkException, MissingObjectException, IncorrectObjectTypeException, IOException {
        return cmit.getAuthorIdent().getName().equals("xxxxx dsd");
    }

    @Override
    public RevFilter clone() {
    return this;
            }
        }).call();
results.forEach(commit -> {
    PersonIdent authoIdent = commit.getAuthorIdent();
    System.out.println("提交人:  " + authoIdent.getName() + "     <" + authoIdent.getEmailAddress() + ">");
    System.out.println("提交SHA1:  " + commit.getId().name());
    System.out.println("提交信息:  " + commit.getShortMessage());
    System.out.println("提交時間:  " + format.format(authoIdent.getWhen()));
});

5.遠程代碼庫命令

1.clone命令

CloneCommand等價與git clone命令

Git.cloneRepository().setURI("https://admin@localhost:8443/r/game-of-life.git")
                .setDirectory(new File("D:\\source-code\\temp-1")).call();

2.push、fetch命令

Repository rep = new FileRepository("D:\\source-code\\temp-1\\.git");
Git git = new Git(rep);
git.pull().setRemote("origin").call();
//fetch命令提供了setRefSpecs方法,而pull命令並無提供,全部pull命令只能fetch全部的分支
git.fetch().setRefSpecs("refs/heads/*:refs/heads/*").call();

而PushCommand和git push相同,通常都須要咱們提供用戶名和密碼,須要用到CredentialsProvider類

Repository rep = new FileRepository("D:\\source-code\\temp-1\\.git");
Git git = new Git(rep);
git.push().setCredentialsProvider(new UsernamePasswordCredentialsProvider("myname", "password")).call();

6.RevWalk API

RevWalk基本是jgit中使用最多的api了,不少jgit的命令就是使用該api實現的。
咱們當前實現這樣一個功能,查找某個文件的歷史記錄,並把每一個提交的文件內容打印出來。

DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Repository repository = new RepositoryBuilder().setGitDir(new File("D:\\source-code\\temp-1\\.git")).build();
        try (RevWalk walk = new RevWalk(repository)) {
            Ref head = repository.findRef("HEAD");
            walk.markStart(walk.parseCommit(head.getObjectId())); // 從HEAD開始遍歷,
            for (RevCommit commit : walk) {
                RevTree tree = commit.getTree();

                TreeWalk treeWalk = new TreeWalk(repository, repository.newObjectReader());
                PathFilter f = PathFilter.create("pom.xml");
                treeWalk.setFilter(f);
                treeWalk.reset(tree);
                treeWalk.setRecursive(false);
                while (treeWalk.next()) {
                    PersonIdent authoIdent = commit.getAuthorIdent();
                    System.out.println("提交人: " + authoIdent.getName() + " <" + authoIdent.getEmailAddress() + ">");
                    System.out.println("提交SHA1: " + commit.getId().name());
                    System.out.println("提交信息: " + commit.getShortMessage());
                    System.out.println("提交時間: " + format.format(authoIdent.getWhen()));

                    ObjectId objectId = treeWalk.getObjectId(0);
                    ObjectLoader loader = repository.open(objectId);
                    loader.copyTo(System.out);              //提取blob對象的內容
                }
            }
        }

7.參考資料

jgit-cookbook

相關文章
相關標籤/搜索