Programmatically `git checkout .` with dulwich

2019-02-05 06:56发布

Having this code

from dulwich.objects import Blob, Tree, Commit, parse_timezone
from dulwich.repo import Repo
from time import time

repo = Repo.init("myrepo", mkdir=True)
blob = Blob.from_string("my file content\n")
tree = Tree()
tree.add("spam", 0100644, blob.id)
commit = Commit()
commit.tree = tree.id


author = "Flav <foo@bar.com>"
commit.author = commit.committer = author
commit.commit_time = commit.author_time = int(time())
tz = parse_timezone('+0200')[0]
commit.commit_timezone = commit.author_timezone = tz
commit.encoding = "UTF-8"
commit.message = "initial commit"

o_sto = repo.object_store
o_sto.add_object(blob)
o_sto.add_object(tree)
o_sto.add_object(commit)

repo.refs["HEAD"] = commit.id

I end up with the commit in the history, BUT the created file is pending for deletion (git status says so).

A git checkout . fixes it.

My question is: how to do git checkout . programmatically with dulwich?

3条回答
家丑人穷心不美
2楼-- · 2019-02-05 07:34
from dulwich.repo import Repo

repo = Repo.init('myrepo', mkdir=True)
f = open('myrepo/spam', 'w+')
f.write('my file content\n')
f.close()
repo.stage(['spam'])
repo.do_commit('initial commit', 'Flav <foo@bar.com>')

Found by looking at dulwich/tests/test_repository.py:371. dulwich is powerful but the docs are a bit lacking, unfortunately.

May also want to consider using GitFile instead.

查看更多
做个烂人
3楼-- · 2019-02-05 07:37

Git status says it's deleted because the file doesn't exist in the working copy, that's why checking it out fixes the status.

It looks like there's no support for high-level working copy classes and functions in dulwich yet. You'd have to deal with trees and blobs and unpacking objects.

OK, took the challenge: I could make a basic checkout with Dulwich :

#get repository object of current directory
repo = Repo('.')
#get tree corresponding to the head commit
tree_id = repo["HEAD"].tree
#iterate over tree content, giving path and blob sha.
for entry in repo.object_store.iter_tree_contents(tree_id):
  path = entry.in_path(repo.path).path
  dulwich.file.ensure_dir_exists(os.path.split(path)[0])
  with open(path, 'wb') as file:
    #write blob's content to file
    file.write(repo[entry.sha].as_raw_string()) 

It won't delete files that must be deleted, won't care about your index, etc.
See also Mark Mikofski's github project for more complete code based on this.

查看更多
看我几分像从前
4楼-- · 2019-02-05 07:43

It is now possible since release 0.8.4, with the method dulwich.index.build_index_from_tree().

It writes a tree to both the index file and the filesystem (working copy), which is a very basic form of checkout.

See the note

existing index is wiped and contents are not merged in a working dir. Suiteable only for fresh clones

I could get it work with the following code

from dulwich import index, repo
#get repository object of current directory
repo = repo.Repo('.')
indexfile = repo.index_path()
#we want to checkout HEAD
tree = repo["HEAD"].tree

index.build_index_from_tree(repo.path, indexfile, repo.object_store, tree)
查看更多
登录 后发表回答