作者:匿蟒
鏈接:https://note.qidong.name/2018/01/gitPython
有時,需要做復雜的 Git 操作,并且有很多中間邏輯。用 Shell 做復雜的邏輯運算與流程控制就是一個災難。所以,用 Python 來實現是一個愉快的選擇。這時,就需要在 Python 中操作 Git 的庫。
0. GitPython 簡介
GitPython是一個與Git庫交互的Python庫,包括底層命令(Plumbing)與高層命令(Porcelain)。它可以實現絕大部分的Git讀寫操作,避免了頻繁與Shell交互的畸形代碼。它并非是一個純粹的Python實現,而是有一部分依賴于直接執行 git 命令,另一部分依賴于GitDB。
GitDB也是一個Python庫。它為 .git/objects 建立了一個數據庫模型,可以實現直接的讀寫。由于采用流式(stream)讀寫,所以運行高效、內存占用低。
1. GitPython安裝pipinstall GitPython
其依賴GitDB會自動安裝,不過可執行的 git 命令需要額外安裝。
2. 基本用法initimportgit
repo = git.Repo.init(path= '.')
這樣就在當前目錄創建了一個Git庫。當然,路徑可以自定義。
由于 git.Repo 實現了 __enter__ 與 __exit__ ,所以可以與 with 聯合使用。
withgit.Repo.init(path= '.') asrepo:
# dosth withrepo
不過,由于只是實現了一些清理操作,關閉后仍然可以讀寫,所以使用這種形式的必要性不高。詳見附錄。
clone
clone分兩種。一是從當前庫clone到另一個位置:
new_repo= repo.clone(path= '../new')
二是從某個URL那里clone到本地某個位置:
new_repo= git.Repo.clone_from(url= 'git@github.com:USER/REPO.git', to_path= '../new')
commitwithopen( 'test.file', 'w') asfobj:
fobj. write( '1st linen')
repo. index.add(items=[ 'test.file'])
repo. index.commit( 'write a line into test.file')
withopen( 'test.file', 'aw') asfobj:
fobj. write( '2nd linen')
repo. index.add(items=[ 'test.file'])
repo. index.commit( 'write another line into test.file')
status
GitPython并未實現原版 git status ,而是給出了部分的信息。
>>> repo.is_dirty
False
>>> with open( 'test.file', 'aw') as fobj:
>>> fobj.write( 'dirty linen')
>>> repo.is_dirty
True
>>> repo.untracked_files
[]
>>> with open( 'untracked.file', 'w') as fobj:
>>> fobj.write( '')
>>> repo.untracked_files
[ 'untracked.file']
checkout(清理所有修改)>>> repo.is_dirty
True
>>> repo.index.checkout(force=True)
<generator object <genexpr> at 0x7f2bf35e6b40>
>>> repo.is_dirty
False
branch
獲取當前分支:
head= repo.head
新建分支:
new_head= repo.create_head( 'new_head', 'HEAD^')
切換分支:
new_head.checkout
head.checkout
刪除分支:
git.Head. delete(repo, new_head)
# or
git.Head. delete(repo, 'new_head')
merge
以下演示如何在一個分支( other ),merge另一個分支( master )。
master = repo.heads.master
other = repo.create_head( 'other', 'HEAD^')
other.checkout
repo. index.merge_tree(master)
repo. index.commit( 'Merge from master to other')
remote, fetch, pull, push
創建remote:
remote= repo.create_remote(name= 'gitlab', url= 'git@gitlab.com:USER/REPO.git')
遠程交互操作:
remote = repo.remote
remote.fetch
remote.pull
remote.push
刪除remote:
repo.delete_remote(remote)
# or
repo.delete_remote( 'gitlab')
其它
其它還有Tag、Submodule等相關操作,不是很常用,這里就不介紹了。
GitPython的優點是在做讀操作時可以方便地獲取內部信息,缺點是在做寫操作時感覺很不順手,隔靴搔癢。當然,它還支持直接執行 git 操作。
git= repo.git
git.status
git.checkout( 'HEAD', b= "my_new_branch")
git.branch( 'another-new-one')
git.branch( '-D', 'another-new-one')
這……感覺又回到了老路,而且仍然感覺怪怪的。
3. 其它操作Git的方法subprocess
這就是所謂『老路』。在另一個進程,執行Shell命令,并通過stdio來解析返回結果。
importsubprocess
subprocess.call([ 'git', 'status'])
dulwich
dulwich是一個純Python實現的Git交互庫,以后有空再研究吧。
官方網站:https://www.dulwich.io/
pygit2
pygit2是基于libgit2實現的一個Python庫。底層是C,而上層Python只是接口,運行效率應該是最高的,然而孤還是放棄了。其缺點是,需要環境中預先安裝libgit2。相比之下,GitPython只需要環境預置Git,簡單多了。
官方網站:http://www.pygit2.org/