JGIT使用的常見問題

具體代碼詳見:https://gitee.com/RainyGao/DocSys

JGIT是非常好用的Java庫,通過JGIT的API可以新建、克隆倉庫、CheckOut和Commit文件,但使用JGIT時需要關注一些地方,否則會出現很多異常。

1. 關於倉庫的遍歷

JGIT通過treeWalk來實現對倉庫的遍歷,原理上是首先根據revision來獲取這個revision對應的revTree,換句話說就是這個版本上的文件節點樹(這些文件在該版本一定是存在的),然後獲取該revTree相應的入口文件(treeWalk)來實現遍歷。

默認情況下獲取的treeWalk是遞歸的(換句話說,就是會自動進入子目錄進行遍歷),所以如果只是遍歷所有文件那麼沒有問題,但實際上的應用場景而言,通常只需要獲取該目錄下的文件列表即可(尤其對於需要展示目錄結構的場景),如果這個時候需要將treeWalk設置爲不可遞歸。

treeWalk.setRecursive(true)

(1)獲取GIT根目錄的revTree的入口的方法如下:

treeWalk = new TreeWalk( repository )
treeWalk.reset(revTree)
需要注意的是如果是根目錄的treeWalk,那麼此時treeWalk指向的是根目錄下的第一個文件,而不是根目錄,換句話說根目錄本身是不會有treeWalk的,所以如果在這個revision上沒有文件的話,那麼treeWalk將會是Null值。

由於指向的是根目錄下的第一個文件,那麼設置非遞歸的話,調用treeWalk.next就可以遍歷根目錄下的文件列表。

(2)獲取指定的文件的treeWalk入口:

treeWalk = TreeWalk.forPath(repository, entryPath, revTree);

網上還有利用更底層的PathFilter接口來實現treeWalk的獲取,我也嘗試過,但似乎並不能達到我想要的效果,個人建議直接使用forPath接口即可,forPath返回的treeWalk的遞歸設置默認是不遞歸。

forPath返回的treeWalk可能是文件也可能是目錄,通過treeWalk.isSubTree可以判斷是不是目錄,該接口是通過FileMode的值來實現的,但某些情況下treeWalk的FileMode是個Null值(例如根目錄的treeWalk),所以直接對treeWalk進行判斷會導致異常,因此對於treeWalk的判斷需要區分是不是根目錄的treeWalk。

另外treeWalk指向的是revTree的某個節點,在不遞歸的情況下,要遍歷其子目錄需要調用 treeWalk.enterSubtree()來進入子目錄(treeWalk將指向該目錄下的第一個文件)

2、關於CheckOut

只要treeWalk搞定了,CheckOut是最簡單的,找到指定的文件節點的入口(即treeWalk),用如下代碼即可將文件下載下來:

                out = new FileOutputStream(localParentPath + targetName);
                ObjectId blobId = treeWalk.getObjectId(0);
                ObjectLoader loader = repository.open(blobId);
                loader.copyTo(out);

3、關於Commit

Commit目前的實現還是依賴於jgit提供的commit接口,原理根本地的git命令沒什麼區別,但是對本地WorkingCopy是有依賴的(也就是說必須本地CheckOut一個branch才能Commit),這並不是我想要的(我更傾向於直接利用文件數據流直接向Stash中寫入想要Commit的文件),但似乎還有點複製,所以會放在後面來實現。

以下是Commit和Push的實現代碼。

        RevCommit ret = null;
        try {
            ret = git.commit().setCommitter(commitUser, "").setMessage(commitMsg).call();
            System.out.println("doAutoCommmit() commitId:" + ret.getName());
        } catch (Exception e) {
            System.out.println("doAutoCommmit() commit error");
            e.printStackTrace();
            return null;
        }
        
        if(isRemote)
        {
            try {
                git.push().call();
            } catch (Exception e) {
                System.out.println("doAutoCommmit() Push Error");    
                e.printStackTrace();
                //Do roll back commit
                rollBackCommit(git, null);
                return null;
            }
        }

      rollBackCommit是用來將本地倉庫還原掉,因爲push失敗的原因,通常是遠程倉庫已經有更新了,那麼需要對本地倉庫先進行rebase以保證本地倉庫與遠程倉庫的同步。

4. 關於刪除

實際上刪除也是一個Commit操作,但有有些不同,因爲刪除實際上並沒有內容需要commit到倉庫中去,只是刪除了節點,那麼這時候的操作就需要一點點技巧了。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章