Skip to content

Closes #693: wrap libgit2's rebase API - #1483

Merged
jdavid merged 2 commits into
libgit2:masterfrom
ambv:rebase-api
Aug 5, 2026
Merged

Closes #693: wrap libgit2's rebase API#1483
jdavid merged 2 commits into
libgit2:masterfrom
ambv:rebase-api

Conversation

@ambv

@ambv ambv commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

This adds Repository.rebase_init() and Repository.rebase_open(), returning a Rebase object that you iterate over and call methods on like commit/finish/abort. The options expose in-memory, quiet, rewrite_notes_ref, the merge favor/flags/file_flags knobs, checkout strategy, and conflict marker labels.

Sorry the PR is pretty big, but it closes a major gap in pygit2 and I promised to implement it last year 😅

I extended the cffi bindings here, as I know the project is moving away from the manual C extension. I based the bindings on libgit2 1.9.6, but AFAICT there's been no changes to the rebase API in 2.x so far.

I also fixed enums.CheckoutStrategy.CONFLICT_STYLE_ZDIFF3, which was mistakenly bound to the DIFF3 constant.

The tests cover the native API, but I also added a "manual rebase" implementation built from pygit2 primitives that I was using before as a behavioral baseline to compare edge cases against. This might prove useful when you're adopting libgit2 2.x. Plus it's extra coverage for the library.

ambv added 2 commits August 5, 2026 09:05
Add Repository.rebase_init() and Repository.rebase_open(), returning a
Rebase object that drives git_rebase_next/commit/finish/abort through
the Python iterator protocol, plus RebaseOperation and
enums.RebaseOperationType.  The options expose inmemory, quiet,
rewrite_notes_ref, the merge favor/flags/file_flags knobs, checkout
strategy, and conflict marker labels.

Also fix enums.CheckoutStrategy.CONFLICT_STYLE_ZDIFF3, which was
mistakenly bound to the DIFF3 constant.

The tests cover the native API (clean replay, hunk-level conflict
markers, custom labels, diff3 style, unresolved-conflict and
already-applied errors, abort, in-memory rebase, fast-forward via
finish, resuming with rebase_open) and keep a "manual rebase"
implementation built from pygit2 primitives as a behavioral baseline
to compare edge cases against.

Assisted-by: Claude Fable 5
Callers previously could not tell GIT_EAPPLIED apart from any other
error: pygit2 exceptions don't carry the libgit2 error code, so driving
a rebase loop meant guessing which GitError is safe to skip.  Mirror
`git rebase`, which skips patches that are already present upstream,
by returning None from commit() in that case.  Unresolved conflicts
still raise GitError.

Also link the 1.20.0 changelog entries to the PR.

Assisted-by: Claude Fable 5
@jdavid
jdavid merged commit e5f6b42 into libgit2:master Aug 5, 2026
15 checks passed
@jdavid

jdavid commented Aug 5, 2026

Copy link
Copy Markdown
Member

Merged, thanks!

@webknjaz

webknjaz commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

@ambv hey, thanks for this! Do you have any public use examples of this API, anything to share?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants