I'm stuck trying to implement a method with pygit2
that removes a given commit.
With plain git, I could do something like:
git rebase --onto SHA^ SHA
but there is no such method in the library.
According to pygit2 documentation, merge_trees
can be used to this end. So far, I got:
def deleteCommit(repo, commitId):
delete_commit = repo[commitId]
head = repo.head
base = repo.merge_base(delete_commit.id, head.target)
delete_commit_tree = repo.get(delete_commit).tree
head_tree = repo.get(head.target).tree
base_tree = repo.get(base).tree
index = repo.merge_trees(base_tree, head_tree, delete_commit_tree)
tree_id = index.write_tree(repo)
From what I have looked up in the documentation this is probably the most straightforward way, aside from doing some repo.walk()
stuff which I couldn't really understand that well.
I came up with this new partial solution using repo.walk()
:
def deleteCommit(repo, commitId):
# Get the branch to be rewritten
branch = repo.lookup_branch(repo.head.shorthand)
branch_ref = repo.lookup_reference(branch.name)
# Get the commit history up to the branch tip
commits = list(repo.walk(branch.target, GIT_SORT_TOPOLOGICAL))
# Create a new tree with the desired changes
tree = repo.TreeBuilder().write()
for commit in commits:
if commitId != str(commit.id):
commitOid = git.Oid(hex=commitId)
if commitOid in commit.parent_ids:
commit.parent_ids.remove(commitOid)
repo.create_commit(
branch_ref.name, # no reflog message
commit.author, # use the default signature
commit.committer, # use the default signature
commit.message, # commit message
tree, # use the new tree
commit.parent_ids,
)
else:
repo.references.delete(f'refs/commits/{commit.hex}')
# Point the branch to the new commit
branch_ref.set_target(tree)
But that yields the error pygit2.GitError: failed to create commit: current tip is not the first parent