Compare commits

..

No commits in common. "master" and "0.23.0" have entirely different histories.

110 changed files with 1410 additions and 3564 deletions

1
.gitignore vendored

@ -3,7 +3,6 @@ build
dist
pygit2.so
_pygit2.so
.tox/
test/*.pyc
test/__pycache__
pygit2/*.pyc

@ -18,11 +18,3 @@ Vlad Temian <vladtemian@gmail.com>
Matthew Gamble <git@matthewgamble.net>
Kaarel Kitsemets <kitsemets@gmail.com>
Matthias Bartelmeß <mba@fourplusone.de>
Robert Hölzl <robert.hoelzl@posteo.de>
Anatoly Techtonik <techtonik@gmail.com>
Guillermo Pérez <bisho@fb.com> <bisho@freedreams.org>
Matthew Duggan <mduggan@qti.qualcomm.com> <mgithub@guarana.org>
Alexander Bayandin <a.bayandin@gmail.com> <bayandin@users.noreply.github.com>

@ -2,7 +2,7 @@
cd ~
git clone --depth=1 -b maint/v0.26 https://github.com/libgit2/libgit2.git
git clone --depth=1 -b maint/v0.23 https://github.com/libgit2/libgit2.git
cd libgit2/
mkdir build && cd build

@ -2,12 +2,11 @@ language: python
python:
- "2.7"
- "3.2"
- "3.3"
- "3.4"
- "3.5"
- "3.6"
- "pypy"
# - "pypy3"
- "pypy3"
env: LIBGIT2=~/libgit2/_install/ LD_LIBRARY_PATH=~/libgit2/_install/lib

@ -1,859 +0,0 @@
0.26.0 (2017-07-06)
-------------------------
- Update to libgit2 v0.26
`#713 <https://github.com/libgit2/pygit2/pull/713>`_
- Drop support for Python 3.2, add support for cffi 1.10
`#706 <https://github.com/libgit2/pygit2/pull/706>`_
`#694 <https://github.com/libgit2/pygit2/issues/694>`_
- New ``Repository.revert_commit(...)``
`#711 <https://github.com/libgit2/pygit2/pull/711>`_
`#710 <https://github.com/libgit2/pygit2/issues/710>`_
- New ``Branch.is_checked_out()``
`#696 <https://github.com/libgit2/pygit2/pull/696>`_
- Various fixes
`#706 <https://github.com/libgit2/pygit2/pull/706>`_
`#707 <https://github.com/libgit2/pygit2/pull/707>`_
`#708 <https://github.com/libgit2/pygit2/pull/708>`_
0.25.1 (2017-04-25)
-------------------------
- Add suport for Python 3.6
- New support for stash: repository methods ``stash``, ``stash_apply``,
``stash_drop`` and ``stash_pop``
`#695 <https://github.com/libgit2/pygit2/pull/695>`_
- Improved support for submodules: new repository methods ``init_submodules``
and ``update_submodules``
`#692 <https://github.com/libgit2/pygit2/pull/692>`_
- New friendlier API for branches & references: ``Repository.branches`` and
``Repository.references``
`#700 <https://github.com/libgit2/pygit2/pull/700>`_
`#701 <https://github.com/libgit2/pygit2/pull/701>`_
- New support for custom backends
`#690 <https://github.com/libgit2/pygit2/pull/690>`_
- Fix ``init_repository`` crash on None input
`#688 <https://github.com/libgit2/pygit2/issues/688>`_
`#697 <https://github.com/libgit2/pygit2/pull/697>`_
- Fix checkout with an orphan master branch
`#669 <https://github.com/libgit2/pygit2/issues/669>`_
`#685 <https://github.com/libgit2/pygit2/pull/685>`_
- Better error messages for opening repositories
`#645 <https://github.com/libgit2/pygit2/issues/645>`_
`#698 <https://github.com/libgit2/pygit2/pull/698>`_
0.25.0 (2016-12-26)
-------------------------
- Upgrade to libgit2 0.25
`#670 <https://github.com/libgit2/pygit2/pull/670>`_
- Now Commit.tree raises an error if tree is not found
`#682 <https://github.com/libgit2/pygit2/pull/682>`_
- New settings.mwindow_mapped_limit, cached_memory, enable_caching,
cache_max_size and cache_object_limit
`#677 <https://github.com/libgit2/pygit2/pull/677>`_
0.24.2 (2016-11-01)
-------------------------
- Unit tests pass on Windows, integration with AppVeyor
`#641 <https://github.com/libgit2/pygit2/pull/641>`_
`#655 <https://github.com/libgit2/pygit2/issues/655>`_
`#657 <https://github.com/libgit2/pygit2/pull/657>`_
`#659 <https://github.com/libgit2/pygit2/pull/659>`_
`#660 <https://github.com/libgit2/pygit2/pull/660>`_
`#661 <https://github.com/libgit2/pygit2/pull/661>`_
`#667 <https://github.com/libgit2/pygit2/pull/667>`_
- Fix when libgit2 error messages have non-ascii chars
`#651 <https://github.com/libgit2/pygit2/pull/651>`_
- Documentation improvements
`#643 <https://github.com/libgit2/pygit2/pull/643>`_
`#653 <https://github.com/libgit2/pygit2/pull/653>`_
`#663 <https://github.com/libgit2/pygit2/pull/663>`_
0.24.1 (2016-06-21)
-------------------------
- New ``Repository.listall_reference_objects()``
`#634 <https://github.com/libgit2/pygit2/pull/634>`_
- Fix ``Repository.write_archive(...)``
`#619 <https://github.com/libgit2/pygit2/pull/619>`_
`#621 <https://github.com/libgit2/pygit2/pull/621>`_
- Reproducible builds
`#636 <https://github.com/libgit2/pygit2/pull/636>`_
- Documentation fixes
`#606 <https://github.com/libgit2/pygit2/pull/606>`_
`#607 <https://github.com/libgit2/pygit2/pull/607>`_
`#609 <https://github.com/libgit2/pygit2/pull/609>`_
`#623 <https://github.com/libgit2/pygit2/pull/623>`_
- Test updates
`#629 <https://github.com/libgit2/pygit2/pull/629>`_
0.24.0 (2016-03-05)
-------------------------
- Update to libgit2 v0.24
`#594 <https://github.com/libgit2/pygit2/pull/594>`_
- Support Python 3.5
- New dependency, `six <https://pypi.python.org/pypi/six/>`_
- New ``Repository.path_is_ignored(path)``
`#589 <https://github.com/libgit2/pygit2/pull/589>`_
- Fix error in ``Repository(path)`` when path is a bytes string
`#588 <https://github.com/libgit2/pygit2/issues/588>`_
`#593 <https://github.com/libgit2/pygit2/pull/593>`_
- Fix memory issue in ``Repository.describe(...)``
`#592 <https://github.com/libgit2/pygit2/issues/592>`_
`#597 <https://github.com/libgit2/pygit2/issues/597>`_
`#599 <https://github.com/libgit2/pygit2/pull/599>`_
- Allow testing with `tox <https://pypi.python.org/pypi/tox/>`_
`#600 <https://github.com/libgit2/pygit2/pull/600>`_
0.23.3 (2016-01-01)
-------------------------
- New ``Repository.create_blob_fromiobase(...)``
`#490 <https://github.com/libgit2/pygit2/pull/490>`_
`#577 <https://github.com/libgit2/pygit2/pull/577>`_
- New ``Repository.describe(...)``
`#585 <https://github.com/libgit2/pygit2/pull/585>`_
- Fix ``Signature`` default encoding, UTF-8 now
`#581 <https://github.com/libgit2/pygit2/issues/581>`_
- Fixing ``pip install pygit2``, should install cffi first
- Unit tests, fix binary diff test
`#586 <https://github.com/libgit2/pygit2/pull/586>`_
- Document that ``Diff.patch`` can be ``None``
`#587 <https://github.com/libgit2/pygit2/pull/587>`_
0.23.2 (2015-10-11)
-------------------------
- Unify callbacks system for remotes and clone
`#568 <https://github.com/libgit2/pygit2/pull/568>`_
- New ``TreeEntry._name``
`#570 <https://github.com/libgit2/pygit2/pull/570>`_
- Fix segfault in ``Tag._message``
`#572 <https://github.com/libgit2/pygit2/pull/572>`_
- Documentation improvements
`#569 <https://github.com/libgit2/pygit2/pull/569>`_
`#574 <https://github.com/libgit2/pygit2/pull/574>`_
API changes to clone::
# Before
clone_repository(..., credentials, certificate)
# Now
callbacks = RemoteCallbacks(credentials, certificate)
clone_repository(..., callbacks)
API changes to remote::
# Before
def transfer_progress(stats):
...
remote.credentials = credentials
remote.transfer_progress = transfer_progress
remote.fetch()
remote.push(specs)
# Now
class MyCallbacks(RemoteCallbacks):
def transfer_progress(self, stats):
...
callbacks = MyCallbacks(credentials)
remote.fetch(callbacks=callbacks)
remote.push(specs, callbacks=callbacks)
0.23.1 (2015-09-26)
-------------------------
- Improve support for cffi 1.0+
`#529 <https://github.com/libgit2/pygit2/pull/529>`_
`#561 <https://github.com/libgit2/pygit2/pull/561>`_
- Fix ``Remote.push``
`#557 <https://github.com/libgit2/pygit2/pull/557>`_
- New ``TreeEntry.type``
`#560 <https://github.com/libgit2/pygit2/pull/560>`_
- New ``pygit2.GIT_DIFF_SHOW_BINARY``
`#566 <https://github.com/libgit2/pygit2/pull/566>`_
0.23.0 (2015-08-14)
-------------------------
- Update to libgit2 v0.23
`#540 <https://github.com/libgit2/pygit2/pull/540>`_
- Now ``Repository.merge_base(...)`` returns ``None`` if no merge base is found
`#550 <https://github.com/libgit2/pygit2/pull/550>`_
- Documentation updates
`#547 <https://github.com/libgit2/pygit2/pull/547>`_
API changes:
- How to set identity (aka signature) in a reflog has changed::
# Before
signature = Signature('foo', 'bar')
...
reference.set_target(target, signature=signature, message=message)
repo.set_head(target, signature=signature)
remote.fetch(signature=signature)
remote.push(signature=signature)
# Now
repo.set_ident('foo', 'bar')
...
reference.set_target(target, message=message)
repo.set_head(target)
remote.push()
# The current identity can be get with
repo.ident
- Some remote setters have been replaced by methods::
# Before # Now
Remote.url = url Repository.remotes.set_url(name, url)
Remote.push_url = url Repository.remotes.set_push_url(name, url)
Remote.add_fetch(refspec) Repository.remotes.add_fetch(name, refspec)
Remote.add_push(refspec) Repository.remotes.add_push(name, refspec)
Remote.fetch_refspecs = [...] removed, use the config API instead
Remote.push_refspecs = [...] removed, use the config API instead
0.22.1 (2015-07-12)
-------------------------
Diff interface refactoring
`#346 <https://github.com/libgit2/pygit2/pull/346>`_
(in progress):
- New ``iter(pygit2.Blame)``
- New ``pygit2.DiffDelta``, ``pygit2.DiffFile`` and ``pygit.DiffLine``
- API changes, translation table::
Hunk => DiffHunk
Patch.old_file_path => Patch.delta.old_file.path
Patch.new_file_path => Patch.delta.new_file.path
Patch.old_id => Patch.delta.old_file.id
Patch.new_id => Patch.delta.new_file.id
Patch.status => Patch.delta.status
Patch.similarity => Patch.delta.similarity
Patch.is_binary => Patch.delta.is_binary
Patch.additions => Patch.line_stats[1]
Patch.deletions => Patch.line_stats[2]
- ``DiffHunk.lines`` is now a list of ``DiffLine`` objects, not tuples
New features:
- New ``Repository.expand_id(...)`` and ``Repository.ahead_behind(...)``
`#448 <https://github.com/libgit2/pygit2/pull/448>`_
- New ``prefix`` parameter in ``Repository.write_archive``
`#481 <https://github.com/libgit2/pygit2/pull/481>`_
- New ``Repository.merge_trees(...)``
`#489 <https://github.com/libgit2/pygit2/pull/489>`_
- New ``Repository.cherrypick(...)``
`#436 <https://github.com/libgit2/pygit2/issues/436>`_
`#492 <https://github.com/libgit2/pygit2/pull/492>`_
- New support for submodules
`#499 <https://github.com/libgit2/pygit2/pull/499>`_
`#514 <https://github.com/libgit2/pygit2/pull/514>`_
- New ``Repository.merge_file_from_index(...)``
`#503 <https://github.com/libgit2/pygit2/pull/503>`_
- Now ``Repository.diff`` supports diffing two blobs
`#508 <https://github.com/libgit2/pygit2/pull/508>`_
- New optional ``fetch`` parameter in ``Remote.create``
`#526 <https://github.com/libgit2/pygit2/pull/526>`_
- New ``pygit2.DiffStats``
`#406 <https://github.com/libgit2/pygit2/issues/406>`_
`#525 <https://github.com/libgit2/pygit2/pull/525>`_
- New ``Repository.get_attr(...)``
`#528 <https://github.com/libgit2/pygit2/pull/528>`_
- New ``level`` optional parameter in ``Index.remove``
`#533 <https://github.com/libgit2/pygit2/pull/533>`_
- New ``repr(TreeEntry)``
`#543 <https://github.com/libgit2/pygit2/pull/543>`_
Build and install improvements:
- Make pygit work in a frozen environment
`#453 <https://github.com/libgit2/pygit2/pull/453>`_
- Make pygit2 work with pyinstaller
`#510 <https://github.com/libgit2/pygit2/pull/510>`_
Bugs fixed:
- Fix memory issues
`#477 <https://github.com/libgit2/pygit2/issues/477>`_
`#487 <https://github.com/libgit2/pygit2/pull/487>`_
`#520 <https://github.com/libgit2/pygit2/pull/520>`_
- Fix TreeEntry equality testing
`#458 <https://github.com/libgit2/pygit2/issues/458>`_
`#488 <https://github.com/libgit2/pygit2/pull/488>`_
- ``Repository.write_archive`` fix handling of symlinks
`#480 <https://github.com/libgit2/pygit2/pull/480>`_
- Fix type check in ``Diff[...]``
`#495 <https://github.com/libgit2/pygit2/issues/495>`_
- Fix error when merging files with unicode content
`#505 <https://github.com/libgit2/pygit2/pull/505>`_
Other:
- Documentation improvements and fixes
`#448 <https://github.com/libgit2/pygit2/pull/448>`_
`#491 <https://github.com/libgit2/pygit2/pull/491>`_
`#497 <https://github.com/libgit2/pygit2/pull/497>`_
`#507 <https://github.com/libgit2/pygit2/pull/507>`_
`#517 <https://github.com/libgit2/pygit2/pull/517>`_
`#518 <https://github.com/libgit2/pygit2/pull/518>`_
`#519 <https://github.com/libgit2/pygit2/pull/519>`_
`#521 <https://github.com/libgit2/pygit2/pull/521>`_
`#523 <https://github.com/libgit2/pygit2/pull/523>`_
`#527 <https://github.com/libgit2/pygit2/pull/527>`_
`#536 <https://github.com/libgit2/pygit2/pull/536>`_
- Expose the ``pygit2.GIT_REPOSITORY_INIT_*`` constants
`#483 <https://github.com/libgit2/pygit2/issues/483>`_
0.22.0 (2015-01-16)
-------------------
New:
- Update to libgit2 v0.22
`#459 <https://github.com/libgit2/pygit2/pull/459>`_
- Add support for libgit2 feature detection
(new ``pygit2.features`` and ``pygit2.GIT_FEATURE_*``)
`#475 <https://github.com/libgit2/pygit2/pull/475>`_
- New ``Repository.remotes`` (``RemoteCollection``)
`#447 <https://github.com/libgit2/pygit2/pull/447>`_
API Changes:
- Prototype of ``clone_repository`` changed, check documentation
- Removed ``clone_into``, use ``clone_repository`` with callbacks instead
- Use ``Repository.remotes.rename(name, new_name)`` instead of
``Remote.rename(new_name)``
- Use ``Repository.remotes.delete(name)`` instead of ``Remote.delete()``
- Now ``Remote.push(...)`` takes a list of refspecs instead of just one
- Change ``Patch.old_id``, ``Patch.new_id``, ``Note.annotated_id``,
``RefLogEntry.oid_old`` and ``RefLogEntry.oid_new`` to be ``Oid`` objects
instead of strings
`#449 <https://github.com/libgit2/pygit2/pull/449>`_
Other:
- Fix ``init_repository`` when passing optional parameters ``workdir_path``,
``description``, ``template_path``, ``initial_head`` or ``origin_url``
`#466 <https://github.com/libgit2/pygit2/issues/466>`_
`#471 <https://github.com/libgit2/pygit2/pull/471>`_
- Fix use-after-free when patch outlives diff
`#457 <https://github.com/libgit2/pygit2/issues/457>`_
`#461 <https://github.com/libgit2/pygit2/pull/461>`_
`#474 <https://github.com/libgit2/pygit2/pull/474>`_
- Documentation improvements
`#456 <https://github.com/libgit2/pygit2/issues/456>`_
`#462 <https://github.com/libgit2/pygit2/pull/462>`_
`#465 <https://github.com/libgit2/pygit2/pull/465>`_
`#472 <https://github.com/libgit2/pygit2/pull/472>`_
`#473 <https://github.com/libgit2/pygit2/pull/473>`_
- Make the GPL exception explicit in setup.py
`#450 <https://github.com/libgit2/pygit2/pull/450>`_
0.21.4 (2014-11-04)
-------------------
- Fix credentials callback not set when pushing
`#431 <https://github.com/libgit2/pygit2/pull/431>`_
`#435 <https://github.com/libgit2/pygit2/issues/435>`_
`#437 <https://github.com/libgit2/pygit2/issues/437>`_
`#438 <https://github.com/libgit2/pygit2/pull/438>`_
- Fix ``Repository.diff(...)`` when treeish is "empty"
`#432 <https://github.com/libgit2/pygit2/issues/432>`_
- New ``Reference.peel(...)`` renders ``Reference.get_object()`` obsolete
`#434 <https://github.com/libgit2/pygit2/pull/434>`_
- New, authenticate using ssh agent
`#424 <https://github.com/libgit2/pygit2/pull/424>`_
- New ``Repository.merge_commits(...)``
`#445 <https://github.com/libgit2/pygit2/pull/445>`_
- Make it easier to run when libgit2 not in a standard location
`#441 <https://github.com/libgit2/pygit2/issues/441>`_
- Documentation: review install chapter
- Documentation: many corrections
`#427 <https://github.com/libgit2/pygit2/pull/427>`_
`#429 <https://github.com/libgit2/pygit2/pull/429>`_
`#439 <https://github.com/libgit2/pygit2/pull/439>`_
`#440 <https://github.com/libgit2/pygit2/pull/440>`_
`#442 <https://github.com/libgit2/pygit2/pull/442>`_
`#443 <https://github.com/libgit2/pygit2/pull/443>`_
`#444 <https://github.com/libgit2/pygit2/pull/444>`_
0.21.3 (2014-09-15)
-------------------
Breaking changes:
- Now ``Repository.blame(...)`` returns ``Oid`` instead of string
`#413 <https://github.com/libgit2/pygit2/pull/413>`_
- New ``Reference.set_target(...)`` replaces the ``Reference.target`` setter
and ``Reference.log_append(...)``
`#414 <https://github.com/libgit2/pygit2/pull/414>`_
- New ``Repository.set_head(...)`` replaces the ``Repository.head`` setter
`#414 <https://github.com/libgit2/pygit2/pull/414>`_
- ``Repository.merge(...)`` now uses the ``SAFE_CREATE`` strategy by default
`#417 <https://github.com/libgit2/pygit2/pull/417>`_
Other changes:
- New ``Remote.delete()``
`#418 <https://github.com/libgit2/pygit2/issues/418>`_
`#420 <https://github.com/libgit2/pygit2/pull/420>`_
- New ``Repository.write_archive(...)``
`#421 <https://github.com/libgit2/pygit2/pull/421>`_
- Now ``Repository.checkout(...)`` accepts branch objects
`#408 <https://github.com/libgit2/pygit2/pull/408>`_
- Fix refcount leak in remotes
`#403 <https://github.com/libgit2/pygit2/issues/403>`_
`#404 <https://github.com/libgit2/pygit2/pull/404>`_
`#419 <https://github.com/libgit2/pygit2/pull/419>`_
- Various fixes to ``clone_repository(...)``
`#399 <https://github.com/libgit2/pygit2/issues/399>`_
`#411 <https://github.com/libgit2/pygit2/pull/411>`_
`#425 <https://github.com/libgit2/pygit2/issues/425>`_
`#426 <https://github.com/libgit2/pygit2/pull/426>`_
- Fix build error in Python 3
`#401 <https://github.com/libgit2/pygit2/pull/401>`_
- Now ``pip install pygit2`` installs cffi first
`#380 <https://github.com/libgit2/pygit2/issues/380>`_
`#407 <https://github.com/libgit2/pygit2/pull/407>`_
- Add support for PyPy3
`#422 <https://github.com/libgit2/pygit2/pull/422>`_
- Documentation improvements
`#398 <https://github.com/libgit2/pygit2/pull/398>`_
`#409 <https://github.com/libgit2/pygit2/pull/409>`_
0.21.2 (2014-08-09)
-------------------
- Fix regression with Python 2, ``IndexEntry.path`` returns str
(bytes in Python 2 and unicode in Python 3)
- Get back ``IndexEntry.oid`` for backwards compatibility
- Config, iterate over the keys (instead of the key/value pairs)
`#395 <https://github.com/libgit2/pygit2/pull/395>`_
- ``Diff.find_similar`` supports new threshold arguments
`#396 <https://github.com/libgit2/pygit2/pull/396>`_
- Optimization, do not load the object when expanding an oid prefix
`#397 <https://github.com/libgit2/pygit2/pull/397>`_
0.21.1 (2014-07-22)
-------------------
- Install fix
`#382 <https://github.com/libgit2/pygit2/pull/382>`_
- Documentation improved, including
`#383 <https://github.com/libgit2/pygit2/pull/383>`_
`#385 <https://github.com/libgit2/pygit2/pull/385>`_
`#388 <https://github.com/libgit2/pygit2/pull/388>`_
- Documentation, use the read-the-docs theme
`#387 <https://github.com/libgit2/pygit2/pull/387>`_
- Coding style improvements
`#392 <https://github.com/libgit2/pygit2/pull/392>`_
- New ``Repository.state_cleanup()``
`#386 <https://github.com/libgit2/pygit2/pull/386>`_
- New ``Index.conflicts``
`#345 <https://github.com/libgit2/pygit2/issues/345>`_
`#389 <https://github.com/libgit2/pygit2/pull/389>`_
- New checkout option to define the target directory
`#390 <https://github.com/libgit2/pygit2/pull/390>`_
Backward incompatible changes:
- Now the checkout strategy must be a keyword argument.
Change ``Repository.checkout(refname, strategy)`` to
``Repository.checkout(refname, strategy=strategy)``
Idem for ``checkout_head``, ``checkout_index`` and ``checkout_tree``
0.21.0 (2014-06-27)
-------------------
Highlights:
- Drop official support for Python 2.6, and add support for Python 3.4
`#376 <https://github.com/libgit2/pygit2/pull/376>`_
- Upgrade to libgit2 v0.21.0
`#374 <https://github.com/libgit2/pygit2/pull/374>`_
- Start using cffi
`#360 <https://github.com/libgit2/pygit2/pull/360>`_
`#361 <https://github.com/libgit2/pygit2/pull/361>`_
Backward incompatible changes:
- Replace ``oid`` by ``id`` through the API to follow libgit2 conventions.
- Merge API overhaul following changes in libgit2.
- New ``Remote.rename(...)`` replaces ``Remote.name = ...``
- Now ``Remote.fetch()`` returns a ``TransferProgress`` object.
- Now ``Config.get_multivar(...)`` returns an iterator instead of a list.
New features:
- New ``Config.snapshot()`` and ``Repository.config_snapshot()``
- New ``Config`` methods: ``get_bool(...)``, ``get_int(...)``,
``parse_bool(...)`` and ``parse_int(...)``
`#357 <https://github.com/libgit2/pygit2/pull/357>`_
- Blob: implement the memory buffer interface
`#362 <https://github.com/libgit2/pygit2/pull/362>`_
- New ``clone_into(...)`` function
`#368 <https://github.com/libgit2/pygit2/pull/368>`_
- Now ``Index`` can be used alone, without a repository
`#372 <https://github.com/libgit2/pygit2/pull/372>`_
- Add more options to ``init_repository``
`#347 <https://github.com/libgit2/pygit2/pull/347>`_
- Support ``Repository.workdir = ...`` and
support setting detached heads ``Repository.head = <Oid>``
`#377 <https://github.com/libgit2/pygit2/pull/377>`_
Other:
- Fix again build with VS2008
`#364 <https://github.com/libgit2/pygit2/pull/364>`_
- Fix ``Blob.diff(...)`` and ``Blob.diff_to_buffer(...)`` arguments passing
`#366 <https://github.com/libgit2/pygit2/pull/366>`_
- Fail gracefully when compiling against the wrong version of libgit2
`#365 <https://github.com/libgit2/pygit2/pull/365>`_
- Several documentation improvements and updates
`#359 <https://github.com/libgit2/pygit2/pull/359>`_
`#375 <https://github.com/libgit2/pygit2/pull/375>`_
`#378 <https://github.com/libgit2/pygit2/pull/378>`_
0.20.3 (2014-04-02)
-------------------
- A number of memory issues fixed
`#328 <https://github.com/libgit2/pygit2/pull/328>`_
`#348 <https://github.com/libgit2/pygit2/pull/348>`_
`#353 <https://github.com/libgit2/pygit2/pull/353>`_
`#355 <https://github.com/libgit2/pygit2/pull/355>`_
`#356 <https://github.com/libgit2/pygit2/pull/356>`_
- Compatibility fixes for
PyPy (`#338 <https://github.com/libgit2/pygit2/pull/338>`_),
Visual Studio 2008 (`#343 <https://github.com/libgit2/pygit2/pull/343>`_)
and Python 3.3 (`#351 <https://github.com/libgit2/pygit2/pull/351>`_)
- Make the sort mode parameter in ``Repository.walk(...)`` optional
`#337 <https://github.com/libgit2/pygit2/pull/337>`_
- New ``Object.peel(...)``
`#342 <https://github.com/libgit2/pygit2/pull/342>`_
- New ``Index.add_all(...)``
`#344 <https://github.com/libgit2/pygit2/pull/344>`_
- Introduce support for libgit2 options
`#350 <https://github.com/libgit2/pygit2/pull/350>`_
- More informative repr for ``Repository`` objects
`#352 <https://github.com/libgit2/pygit2/pull/352>`_
- Introduce support for credentials
`#354 <https://github.com/libgit2/pygit2/pull/354>`_
- Several documentation fixes
`#302 <https://github.com/libgit2/pygit2/issues/302>`_
`#336 <https://github.com/libgit2/pygit2/issues/336>`_
- Tests, remove temporary files
`#341 <https://github.com/libgit2/pygit2/pull/341>`_
0.20.2 (2014-02-04)
-------------------
- Support PyPy
`#209 <https://github.com/libgit2/pygit2/issues/209>`_
`#327 <https://github.com/libgit2/pygit2/pull/327>`_
`#333 <https://github.com/libgit2/pygit2/pull/333>`_
Repository:
- New ``Repository.default_signature``
`#310 <https://github.com/libgit2/pygit2/pull/310>`_
Oid:
- New ``str(Oid)`` deprecates ``Oid.hex``
`#322 <https://github.com/libgit2/pygit2/pull/322>`_
Object:
- New ``Object.id`` deprecates ``Object.oid``
`#322 <https://github.com/libgit2/pygit2/pull/322>`_
- New ``TreeEntry.id`` deprecates ``TreeEntry.oid``
`#322 <https://github.com/libgit2/pygit2/pull/322>`_
- New ``Blob.diff(...)`` and ``Blob.diff_to_buffer(...)``
`#307 <https://github.com/libgit2/pygit2/pull/307>`_
- New ``Commit.tree_id`` and ``Commit.parent_ids``
`#73 <https://github.com/libgit2/pygit2/issues/73>`_
`#311 <https://github.com/libgit2/pygit2/pull/311>`_
- New rich comparison between tree entries
`#305 <https://github.com/libgit2/pygit2/issues/305>`_
`#313 <https://github.com/libgit2/pygit2/pull/313>`_
- Now ``Tree.__contains__(key)`` supports paths
`#306 <https://github.com/libgit2/pygit2/issues/306>`_
`#316 <https://github.com/libgit2/pygit2/pull/316>`_
Index:
- Now possible to create ``IndexEntry(...)``
`#325 <https://github.com/libgit2/pygit2/pull/325>`_
- Now ``IndexEntry.path``, ``IndexEntry.oid`` and ``IndexEntry.mode`` are
writable
`#325 <https://github.com/libgit2/pygit2/pull/325>`_
- Now ``Index.add(...)`` accepts an ``IndexEntry`` too
`#325 <https://github.com/libgit2/pygit2/pull/325>`_
- Now ``Index.write_tree(...)`` is able to write to a different repository
`#325 <https://github.com/libgit2/pygit2/pull/325>`_
- Fix memory leak in ``IndexEntry.path`` setter
`#335 <https://github.com/libgit2/pygit2/pull/335>`_
Config:
- New ``Config`` iterator replaces ``Config.foreach``
`#183 <https://github.com/libgit2/pygit2/issues/183>`_
`#312 <https://github.com/libgit2/pygit2/pull/312>`_
Remote:
- New type ``Refspec``
`#314 <https://github.com/libgit2/pygit2/pull/314>`_
- New ``Remote.push_url``
`#315 <https://github.com/libgit2/pygit2/pull/314>`_
- New ``Remote.add_push`` and ``Remote.add_fetch``
`#255 <https://github.com/libgit2/pygit2/issues/255>`_
`#318 <https://github.com/libgit2/pygit2/pull/318>`_
- New ``Remote.fetch_refspecs`` replaces ``Remote.get_fetch_refspecs()`` and
``Remote.set_fetch_refspecs(...)``
`#319 <https://github.com/libgit2/pygit2/pull/319>`_
- New ``Remote.push_refspecs`` replaces ``Remote.get_push_refspecs()`` and
``Remote.set_push_refspecs(...)``
`#319 <https://github.com/libgit2/pygit2/pull/319>`_
- New ``Remote.progress``, ``Remote.transfer_progress`` and
``Remote.update_tips``
`#274 <https://github.com/libgit2/pygit2/issues/274>`_
`#324 <https://github.com/libgit2/pygit2/pull/324>`_
- New type ``TransferProgress``
`#274 <https://github.com/libgit2/pygit2/issues/274>`_
`#324 <https://github.com/libgit2/pygit2/pull/324>`_
- Fix refcount leak in ``Repository.remotes``
`#321 <https://github.com/libgit2/pygit2/issues/321>`_
`#332 <https://github.com/libgit2/pygit2/pull/332>`_
Other: `#331 <https://github.com/libgit2/pygit2/pull/331>`_
0.20.1 (2013-12-24)
-------------------
- New remote ref-specs API:
`#290 <https://github.com/libgit2/pygit2/pull/290>`_
- New ``Repository.reset(...)``:
`#292 <https://github.com/libgit2/pygit2/pull/292>`_,
`#294 <https://github.com/libgit2/pygit2/pull/294>`_
- Export ``GIT_DIFF_MINIMAL``:
`#293 <https://github.com/libgit2/pygit2/pull/293>`_
- New ``Repository.merge(...)``:
`#295 <https://github.com/libgit2/pygit2/pull/295>`_
- Fix ``Repository.blame`` argument handling:
`#297 <https://github.com/libgit2/pygit2/pull/297>`_
- Fix build error on Windows:
`#298 <https://github.com/libgit2/pygit2/pull/298>`_
- Fix typo in the README file, Blog → Blob:
`#301 <https://github.com/libgit2/pygit2/pull/301>`_
- Now ``Diff.patch`` returns ``None`` if no patch:
`#232 <https://github.com/libgit2/pygit2/pull/232>`_,
`#303 <https://github.com/libgit2/pygit2/pull/303>`_
- New ``Walker.simplify_first_parent()``:
`#304 <https://github.com/libgit2/pygit2/pull/304>`_
0.20.0 (2013-11-24)
-------------------
- Upgrade to libgit2 v0.20.0:
`#288 <https://github.com/libgit2/pygit2/pull/288>`_
- New ``Repository.head_is_unborn`` replaces ``Repository.head_is_orphaned``
- Changed ``pygit2.clone_repository(...)``. Drop ``push_url``, ``fetch_spec``
and ``push_spec`` parameters. Add ``ignore_cert_errors``.
- New ``Patch.additions`` and ``Patch.deletions``:
`#275 <https://github.com/libgit2/pygit2/pull/275>`_
- New ``Patch.is_binary``:
`#276 <https://github.com/libgit2/pygit2/pull/276>`_
- New ``Reference.log_append(...)``:
`#277 <https://github.com/libgit2/pygit2/pull/277>`_
- New ``Blob.is_binary``:
`#278 <https://github.com/libgit2/pygit2/pull/278>`_
- New ``len(Diff)`` shows the number of patches:
`#281 <https://github.com/libgit2/pygit2/pull/281>`_
- Rewrite ``Repository.status()``:
`#283 <https://github.com/libgit2/pygit2/pull/283>`_
- New ``Reference.shorthand``:
`#284 <https://github.com/libgit2/pygit2/pull/284>`_
- New ``Repository.blame(...)``:
`#285 <https://github.com/libgit2/pygit2/pull/285>`_
- Now ``Repository.listall_references()`` and
``Repository.listall_branches()`` return a list, not a tuple:
`#289 <https://github.com/libgit2/pygit2/pull/289>`_

@ -5,19 +5,16 @@ pygit2 - libgit2 bindings in Python
.. image:: https://travis-ci.org/libgit2/pygit2.svg?branch=master
:target: http://travis-ci.org/libgit2/pygit2
.. image:: https://ci.appveyor.com/api/projects/status/edmwc0dctk5nacx0/branch/master?svg=true
:target: https://ci.appveyor.com/project/jdavid/pygit2/branch/master
Pygit2 is a set of Python bindings to the libgit2 shared library, libgit2
implements Git plumbing. Pygit2 works with Python 2.7, 3.3, 3.4, 3.5, 3.6
and PyPy 2.6
implements the core of Git. Pygit2 works with Python 2.7, 3.2, 3.3, 3.4 and
pypy.
Links:
- https://github.com/libgit2/pygit2 -- Source code and issue tracker
- http://github.com/libgit2/pygit2 -- Source code and issue tracker
- http://www.pygit2.org/ -- Documentation
- https://pypi.python.org/pypi/pygit2 -- Download
- https://github.com/libgit2/pygit2/blob/master/CHANGELOG.rst -- Changelog
- http://pypi.python.org/pypi/pygit2 -- Download
How to install
==============
@ -25,50 +22,680 @@ How to install
- Check http://www.pygit2.org/install.html
Changelog
==============
0.23.0 (2015-08-14)
-------------------------
- Update to libgit2 v0.23
`#540 <https://github.com/libgit2/pygit2/pull/540>`_
- Now ``Repository.merge_base(...)`` returns ``None`` if no merge base is found
`#550 <https://github.com/libgit2/pygit2/pull/550>`_
- Documentation updates
`#547 <https://github.com/libgit2/pygit2/pull/547>`_
API changes:
- How to set identity (aka signature) in a reflog has changed::
# Before
signature = Signature('foo', 'bar')
...
reference.set_target(target, signature=signature, message=message)
repo.set_head(target, signature=signature)
remote.fetch(signature=signature)
remote.push(signature=signature)
# Now
repo.set_ident('foo', 'bar')
...
reference.set_target(target, message=message)
repo.set_head(target)
remote.push()
# The current identity can be get with
repo.ident
- Some remote setters have been replaced by methods::
# Before # Now
Remote.url = url Repository.remotes.set_url(name, url)
Remote.push_url = url Repository.remotes.set_push_url(name, url)
Remote.add_fetch(refspec) Repository.remotes.add_fetch(name, refspec)
Remote.add_push(refspec) Repository.remotes.add_push(name, refspec)
Remote.fetch_refspecs = [...] removed, use the config API instead
Remote.push_refspecs = [...] removed, use the config API instead
0.22.1 (2015-07-12)
-------------------------
Diff interface refactoring
`#346 <https://github.com/libgit2/pygit2/pull/346>`_
(in progress):
- New ``iter(pygit2.Blame)``
- New ``pygit2.DiffDelta``, ``pygit2.DiffFile`` and ``pygit.DiffLine``
- API changes, translation table::
Hunk => DiffHunk
Patch.old_file_path => Patch.delta.old_file.path
Patch.new_file_path => Patch.delta.new_file.path
Patch.old_id => Patch.delta.old_file.id
Patch.new_id => Patch.delta.new_file.id
Patch.status => Patch.delta.status
Patch.similarity => Patch.delta.similarity
Patch.is_binary => Patch.delta.is_binary
Patch.additions => Patch.line_stats[1]
Patch.deletions => Patch.line_stats[2]
- ``DiffHunk.lines`` is now a list of ``DiffLine`` objects, not tuples
New features:
- New ``Repository.expand_id(...)`` and ``Repository.ahead_behind(...)``
`#448 <https://github.com/libgit2/pygit2/pull/448>`_
- New ``prefix`` parameter in ``Repository.write_archive``
`#481 <https://github.com/libgit2/pygit2/pull/481>`_
- New ``Repository.merge_trees(...)``
`#489 <https://github.com/libgit2/pygit2/pull/489>`_
- New ``Repository.cherrypick(...)``
`#436 <https://github.com/libgit2/pygit2/issues/436>`_
`#492 <https://github.com/libgit2/pygit2/pull/492>`_
- New support for submodules
`#499 <https://github.com/libgit2/pygit2/pull/499>`_
`#514 <https://github.com/libgit2/pygit2/pull/514>`_
- New ``Repository.merge_file_from_index(...)``
`#503 <https://github.com/libgit2/pygit2/pull/503>`_
- Now ``Repository.diff`` supports diffing two blobs
`#508 <https://github.com/libgit2/pygit2/pull/508>`_
- New optional ``fetch`` parameter in ``Remote.create``
`#526 <https://github.com/libgit2/pygit2/pull/526>`_
- New ``pygit2.DiffStats``
`#406 <https://github.com/libgit2/pygit2/issues/406>`_
`#525 <https://github.com/libgit2/pygit2/pull/525>`_
- New ``Repository.get_attr(...)``
`#528 <https://github.com/libgit2/pygit2/pull/528>`_
- New ``level`` optional parameter in ``Index.remove``
`#533 <https://github.com/libgit2/pygit2/pull/533>`_
- New ``repr(TreeEntry)``
`#543 <https://github.com/libgit2/pygit2/pull/543>`_
Build and install improvements:
- Make pygit work in a frozen environment
`#453 <https://github.com/libgit2/pygit2/pull/453>`_
- Make pygit2 work with pyinstaller
`#510 <https://github.com/libgit2/pygit2/pull/510>`_
Bugs fixed:
- Fix memory issues
`#477 <https://github.com/libgit2/pygit2/issues/477>`_
`#487 <https://github.com/libgit2/pygit2/pull/487>`_
`#520 <https://github.com/libgit2/pygit2/pull/520>`_
- Fix TreeEntry equality testing
`#458 <https://github.com/libgit2/pygit2/issues/458>`_
`#488 <https://github.com/libgit2/pygit2/pull/488>`_
- ``Repository.write_archive`` fix handling of symlinks
`#480 <https://github.com/libgit2/pygit2/pull/480>`_
- Fix type check in ``Diff[...]``
`#495 <https://github.com/libgit2/pygit2/issues/495>`_
- Fix error when merging files with unicode content
`#505 <https://github.com/libgit2/pygit2/pull/505>`_
Other:
- Documentation improvements and fixes
`#448 <https://github.com/libgit2/pygit2/pull/448>`_
`#491 <https://github.com/libgit2/pygit2/pull/491>`_
`#497 <https://github.com/libgit2/pygit2/pull/497>`_
`#507 <https://github.com/libgit2/pygit2/pull/507>`_
`#517 <https://github.com/libgit2/pygit2/pull/517>`_
`#518 <https://github.com/libgit2/pygit2/pull/518>`_
`#519 <https://github.com/libgit2/pygit2/pull/519>`_
`#521 <https://github.com/libgit2/pygit2/pull/521>`_
`#523 <https://github.com/libgit2/pygit2/pull/523>`_
`#527 <https://github.com/libgit2/pygit2/pull/527>`_
`#536 <https://github.com/libgit2/pygit2/pull/536>`_
- Expose the ``pygit2.GIT_REPOSITORY_INIT_*`` constants
`#483 <https://github.com/libgit2/pygit2/issues/483>`_
0.22.0 (2015-01-16)
-------------------
New:
- Update to libgit2 v0.22
`#459 <https://github.com/libgit2/pygit2/pull/459>`_
- Add support for libgit2 feature detection
(new ``pygit2.features`` and ``pygit2.GIT_FEATURE_*``)
`#475 <https://github.com/libgit2/pygit2/pull/475>`_
- New ``Repository.remotes`` (``RemoteCollection``)
`#447 <https://github.com/libgit2/pygit2/pull/447>`_
API Changes:
- Prototype of ``clone_repository`` changed, check documentation
- Removed ``clone_into``, use ``clone_repository`` with callbacks instead
- Use ``Repository.remotes.rename(name, new_name)`` instead of
``Remote.rename(new_name)``
- Use ``Repository.remotes.delete(name)`` instead of ``Remote.delete()``
- Now ``Remote.push(...)`` takes a list of refspecs instead of just one
- Change ``Patch.old_id``, ``Patch.new_id``, ``Note.annotated_id``,
``RefLogEntry.oid_old`` and ``RefLogEntry.oid_new`` to be ``Oid`` objects
instead of strings
`#449 <https://github.com/libgit2/pygit2/pull/449>`_
Other:
- Fix ``init_repository`` when passing optional parameters ``workdir_path``,
``description``, ``template_path``, ``initial_head`` or ``origin_url``
`#466 <https://github.com/libgit2/pygit2/issues/466>`_
`#471 <https://github.com/libgit2/pygit2/pull/471>`_
- Fix use-after-free when patch outlives diff
`#457 <https://github.com/libgit2/pygit2/issues/457>`_
`#461 <https://github.com/libgit2/pygit2/pull/461>`_
`#474 <https://github.com/libgit2/pygit2/pull/474>`_
- Documentation improvements
`#456 <https://github.com/libgit2/pygit2/issues/456>`_
`#462 <https://github.com/libgit2/pygit2/pull/462>`_
`#465 <https://github.com/libgit2/pygit2/pull/465>`_
`#472 <https://github.com/libgit2/pygit2/pull/472>`_
`#473 <https://github.com/libgit2/pygit2/pull/473>`_
- Make the GPL exception explicit in setup.py
`#450 <https://github.com/libgit2/pygit2/pull/450>`_
0.21.4 (2014-11-04)
-------------------
- Fix credentials callback not set when pushing
`#431 <https://github.com/libgit2/pygit2/pull/431>`_
`#435 <https://github.com/libgit2/pygit2/issues/435>`_
`#437 <https://github.com/libgit2/pygit2/issues/437>`_
`#438 <https://github.com/libgit2/pygit2/pull/438>`_
- Fix ``Repository.diff(...)`` when treeish is "empty"
`#432 <https://github.com/libgit2/pygit2/issues/432>`_
- New ``Reference.peel(...)`` renders ``Reference.get_object()`` obsolete
`#434 <https://github.com/libgit2/pygit2/pull/434>`_
- New, authenticate using ssh agent
`#424 <https://github.com/libgit2/pygit2/pull/424>`_
- New ``Repository.merge_commits(...)``
`#445 <https://github.com/libgit2/pygit2/pull/445>`_
- Make it easier to run when libgit2 not in a standard location
`#441 <https://github.com/libgit2/pygit2/issues/441>`_
- Documentation: review install chapter
- Documentation: many corrections
`#427 <https://github.com/libgit2/pygit2/pull/427>`_
`#429 <https://github.com/libgit2/pygit2/pull/429>`_
`#439 <https://github.com/libgit2/pygit2/pull/439>`_
`#440 <https://github.com/libgit2/pygit2/pull/440>`_
`#442 <https://github.com/libgit2/pygit2/pull/442>`_
`#443 <https://github.com/libgit2/pygit2/pull/443>`_
`#444 <https://github.com/libgit2/pygit2/pull/444>`_
0.21.3 (2014-09-15)
-------------------
Breaking changes:
- Now ``Repository.blame(...)`` returns ``Oid`` instead of string
`#413 <https://github.com/libgit2/pygit2/pull/413>`_
- New ``Reference.set_target(...)`` replaces the ``Reference.target`` setter
and ``Reference.log_append(...)``
`#414 <https://github.com/libgit2/pygit2/pull/414>`_
- New ``Repository.set_head(...)`` replaces the ``Repository.head`` setter
`#414 <https://github.com/libgit2/pygit2/pull/414>`_
- ``Repository.merge(...)`` now uses the ``SAFE_CREATE`` strategy by default
`#417 <https://github.com/libgit2/pygit2/pull/417>`_
Other changes:
- New ``Remote.delete()``
`#418 <https://github.com/libgit2/pygit2/issues/418>`_
`#420 <https://github.com/libgit2/pygit2/pull/420>`_
- New ``Repository.write_archive(...)``
`#421 <https://github.com/libgit2/pygit2/pull/421>`_
- Now ``Repository.checkout(...)`` accepts branch objects
`#408 <https://github.com/libgit2/pygit2/pull/408>`_
- Fix refcount leak in remotes
`#403 <https://github.com/libgit2/pygit2/issues/403>`_
`#404 <https://github.com/libgit2/pygit2/pull/404>`_
`#419 <https://github.com/libgit2/pygit2/pull/419>`_
- Various fixes to ``clone_repository(...)``
`#399 <https://github.com/libgit2/pygit2/issues/399>`_
`#411 <https://github.com/libgit2/pygit2/pull/411>`_
`#425 <https://github.com/libgit2/pygit2/issues/425>`_
`#426 <https://github.com/libgit2/pygit2/pull/426>`_
- Fix build error in Python 3
`#401 <https://github.com/libgit2/pygit2/pull/401>`_
- Now ``pip install pygit2`` installs cffi first
`#380 <https://github.com/libgit2/pygit2/issues/380>`_
`#407 <https://github.com/libgit2/pygit2/pull/407>`_
- Add support for pypy3
`#422 <https://github.com/libgit2/pygit2/pull/422>`_
- Documentation improvements
`#398 <https://github.com/libgit2/pygit2/pull/398>`_
`#409 <https://github.com/libgit2/pygit2/pull/409>`_
0.21.2 (2014-08-09)
-------------------
- Fix regression with Python 2, ``IndexEntry.path`` returns str
(bytes in Python 2 and unicode in Python 3)
- Get back ``IndexEntry.oid`` for backwards compatibility
- Config, iterate over the keys (instead of the key/value pairs)
`#395 <https://github.com/libgit2/pygit2/pull/395>`_
- ``Diff.find_similar`` supports new threshold arguments
`#396 <https://github.com/libgit2/pygit2/pull/396>`_
- Optimization, do not load the object when expanding an oid prefix
`#397 <https://github.com/libgit2/pygit2/pull/397>`_
0.21.1 (2014-07-22)
-------------------
- Install fix
`#382 <https://github.com/libgit2/pygit2/pull/382>`_
- Documentation improved, including
`#383 <https://github.com/libgit2/pygit2/pull/383>`_
`#385 <https://github.com/libgit2/pygit2/pull/385>`_
`#388 <https://github.com/libgit2/pygit2/pull/388>`_
- Documentation, use the read-the-docs theme
`#387 <https://github.com/libgit2/pygit2/pull/387>`_
- Coding style improvements
`#392 <https://github.com/libgit2/pygit2/pull/392>`_
- New ``Repository.state_cleanup()``
`#386 <https://github.com/libgit2/pygit2/pull/386>`_
- New ``Index.conflicts``
`#345 <https://github.com/libgit2/pygit2/issues/345>`_
`#389 <https://github.com/libgit2/pygit2/pull/389>`_
- New checkout option to define the target directory
`#390 <https://github.com/libgit2/pygit2/pull/390>`_
Backward incompatible changes:
- Now the checkout strategy must be a keyword argument.
Change ``Repository.checkout(refname, strategy)`` to
``Repository.checkout(refname, strategy=strategy)``
Idem for ``checkout_head``, ``checkout_index`` and ``checkout_tree``
0.21.0 (2014-06-27)
-------------------
Highlights:
- Drop official support for Python 2.6, and add support for Python 3.4
`#376 <https://github.com/libgit2/pygit2/pull/376>`_
- Upgrade to libgit2 v0.21.0
`#374 <https://github.com/libgit2/pygit2/pull/374>`_
- Start using cffi
`#360 <https://github.com/libgit2/pygit2/pull/360>`_
`#361 <https://github.com/libgit2/pygit2/pull/361>`_
Backward incompatible changes:
- Replace ``oid`` by ``id`` through the API to follow libgit2 conventions.
- Merge API overhaul following changes in libgit2.
- New ``Remote.rename(...)`` replaces ``Remote.name = ...``
- Now ``Remote.fetch()`` returns a ``TransferProgress`` object.
- Now ``Config.get_multivar(...)`` returns an iterator instead of a list.
New features:
- New ``Config.snapshot()`` and ``Repository.config_snapshot()``
- New ``Config`` methods: ``get_bool(...)``, ``get_int(...)``,
``parse_bool(...)`` and ``parse_int(...)``
`#357 <https://github.com/libgit2/pygit2/pull/357>`_
- Blob: implement the memory buffer interface
`#362 <https://github.com/libgit2/pygit2/pull/362>`_
- New ``clone_into(...)`` function
`#368 <https://github.com/libgit2/pygit2/pull/368>`_
- Now ``Index`` can be used alone, without a repository
`#372 <https://github.com/libgit2/pygit2/pull/372>`_
- Add more options to ``init_repository``
`#347 <https://github.com/libgit2/pygit2/pull/347>`_
- Support ``Repository.workdir = ...`` and
support setting detached heads ``Repository.head = <Oid>``
`#377 <https://github.com/libgit2/pygit2/pull/377>`_
Other:
- Fix again build with VS2008
`#364 <https://github.com/libgit2/pygit2/pull/364>`_
- Fix ``Blob.diff(...)`` and ``Blob.diff_to_buffer(...)`` arguments passing
`#366 <https://github.com/libgit2/pygit2/pull/366>`_
- Fail gracefully when compiling against the wrong version of libgit2
`#365 <https://github.com/libgit2/pygit2/pull/365>`_
- Several documentation improvements and updates
`#359 <https://github.com/libgit2/pygit2/pull/359>`_
`#375 <https://github.com/libgit2/pygit2/pull/375>`_
`#378 <https://github.com/libgit2/pygit2/pull/378>`_
0.20.3 (2014-04-02)
-------------------
- A number of memory issues fixed
`#328 <https://github.com/libgit2/pygit2/pull/328>`_
`#348 <https://github.com/libgit2/pygit2/pull/348>`_
`#353 <https://github.com/libgit2/pygit2/pull/353>`_
`#355 <https://github.com/libgit2/pygit2/pull/355>`_
`#356 <https://github.com/libgit2/pygit2/pull/356>`_
- Compatibility fixes for
PyPy (`#338 <https://github.com/libgit2/pygit2/pull/338>`_),
Visual Studio 2008 (`#343 <https://github.com/libgit2/pygit2/pull/343>`_)
and Python 3.3 (`#351 <https://github.com/libgit2/pygit2/pull/351>`_)
- Make the sort mode parameter in ``Repository.walk(...)`` optional
`#337 <https://github.com/libgit2/pygit2/pull/337>`_
- New ``Object.peel(...)``
`#342 <https://github.com/libgit2/pygit2/pull/342>`_
- New ``Index.add_all(...)``
`#344 <https://github.com/libgit2/pygit2/pull/344>`_
- Introduce support for libgit2 options
`#350 <https://github.com/libgit2/pygit2/pull/350>`_
- More informative repr for ``Repository`` objects
`#352 <https://github.com/libgit2/pygit2/pull/352>`_
- Introduce support for credentials
`#354 <https://github.com/libgit2/pygit2/pull/354>`_
- Several documentation fixes
`#302 <https://github.com/libgit2/pygit2/issues/302>`_
`#336 <https://github.com/libgit2/pygit2/issues/336>`_
- Tests, remove temporary files
`#341 <https://github.com/libgit2/pygit2/pull/341>`_
0.20.2 (2014-02-04)
-------------------
- Support pypy
`#209 <https://github.com/libgit2/pygit2/issues/209>`_
`#327 <https://github.com/libgit2/pygit2/pull/327>`_
`#333 <https://github.com/libgit2/pygit2/pull/333>`_
Repository:
- New ``Repository.default_signature``
`#310 <https://github.com/libgit2/pygit2/pull/310>`_
Oid:
- New ``str(Oid)`` deprecates ``Oid.hex``
`#322 <https://github.com/libgit2/pygit2/pull/322>`_
Object:
- New ``Object.id`` deprecates ``Object.oid``
`#322 <https://github.com/libgit2/pygit2/pull/322>`_
- New ``TreeEntry.id`` deprecates ``TreeEntry.oid``
`#322 <https://github.com/libgit2/pygit2/pull/322>`_
- New ``Blob.diff(...)`` and ``Blob.diff_to_buffer(...)``
`#307 <https://github.com/libgit2/pygit2/pull/307>`_
- New ``Commit.tree_id`` and ``Commit.parent_ids``
`#73 <https://github.com/libgit2/pygit2/issues/73>`_
`#311 <https://github.com/libgit2/pygit2/pull/311>`_
- New rich comparison between tree entries
`#305 <https://github.com/libgit2/pygit2/issues/305>`_
`#313 <https://github.com/libgit2/pygit2/pull/313>`_
- Now ``Tree.__contains__(key)`` supports paths
`#306 <https://github.com/libgit2/pygit2/issues/306>`_
`#316 <https://github.com/libgit2/pygit2/pull/316>`_
Index:
- Now possible to create ``IndexEntry(...)``
`#325 <https://github.com/libgit2/pygit2/pull/325>`_
- Now ``IndexEntry.path``, ``IndexEntry.oid`` and ``IndexEntry.mode`` are
writable
`#325 <https://github.com/libgit2/pygit2/pull/325>`_
- Now ``Index.add(...)`` accepts an ``IndexEntry`` too
`#325 <https://github.com/libgit2/pygit2/pull/325>`_
- Now ``Index.write_tree(...)`` is able to write to a different repository
`#325 <https://github.com/libgit2/pygit2/pull/325>`_
- Fix memory leak in ``IndexEntry.path`` setter
`#335 <https://github.com/libgit2/pygit2/pull/335>`_
Config:
- New ``Config`` iterator replaces ``Config.foreach``
`#183 <https://github.com/libgit2/pygit2/issues/183>`_
`#312 <https://github.com/libgit2/pygit2/pull/312>`_
Remote:
- New type ``Refspec``
`#314 <https://github.com/libgit2/pygit2/pull/314>`_
- New ``Remote.push_url``
`#315 <https://github.com/libgit2/pygit2/pull/314>`_
- New ``Remote.add_push`` and ``Remote.add_fetch``
`#255 <https://github.com/libgit2/pygit2/issues/255>`_
`#318 <https://github.com/libgit2/pygit2/pull/318>`_
- New ``Remote.fetch_refspecs`` replaces ``Remote.get_fetch_refspecs()`` and
``Remote.set_fetch_refspecs(...)``
`#319 <https://github.com/libgit2/pygit2/pull/319>`_
- New ``Remote.push_refspecs`` replaces ``Remote.get_push_refspecs()`` and
``Remote.set_push_refspecs(...)``
`#319 <https://github.com/libgit2/pygit2/pull/319>`_
- New ``Remote.progress``, ``Remote.transfer_progress`` and
``Remote.update_tips``
`#274 <https://github.com/libgit2/pygit2/issues/274>`_
`#324 <https://github.com/libgit2/pygit2/pull/324>`_
- New type ``TransferProgress``
`#274 <https://github.com/libgit2/pygit2/issues/274>`_
`#324 <https://github.com/libgit2/pygit2/pull/324>`_
- Fix refcount leak in ``Repository.remotes``
`#321 <https://github.com/libgit2/pygit2/issues/321>`_
`#332 <https://github.com/libgit2/pygit2/pull/332>`_
Other: `#331 <https://github.com/libgit2/pygit2/pull/331>`_
0.20.1 (2013-12-24)
-------------------
- New remote ref-specs API:
`#290 <https://github.com/libgit2/pygit2/pull/290>`_
- New ``Repository.reset(...)``:
`#292 <https://github.com/libgit2/pygit2/pull/292>`_,
`#294 <https://github.com/libgit2/pygit2/pull/294>`_
- Export ``GIT_DIFF_MINIMAL``:
`#293 <https://github.com/libgit2/pygit2/pull/293>`_
- New ``Repository.merge(...)``:
`#295 <https://github.com/libgit2/pygit2/pull/295>`_
- Fix ``Repository.blame`` argument handling:
`#297 <https://github.com/libgit2/pygit2/pull/297>`_
- Fix build error on Windows:
`#298 <https://github.com/libgit2/pygit2/pull/298>`_
- Fix typo in the README file, Blog → Blob:
`#301 <https://github.com/libgit2/pygit2/pull/301>`_
- Now ``Diff.patch`` returns ``None`` if no patch:
`#232 <https://github.com/libgit2/pygit2/pull/232>`_,
`#303 <https://github.com/libgit2/pygit2/pull/303>`_
- New ``Walker.simplify_first_parent()``:
`#304 <https://github.com/libgit2/pygit2/pull/304>`_
0.20.0 (2013-11-24)
-------------------
- Upgrade to libgit2 v0.20.0:
`#288 <https://github.com/libgit2/pygit2/pull/288>`_
- New ``Repository.head_is_unborn`` replaces ``Repository.head_is_orphaned``
- Changed ``pygit2.clone_repository(...)``. Drop ``push_url``, ``fetch_spec``
and ``push_spec`` parameters. Add ``ignore_cert_errors``.
- New ``Patch.additions`` and ``Patch.deletions``:
`#275 <https://github.com/libgit2/pygit2/pull/275>`_
- New ``Patch.is_binary``:
`#276 <https://github.com/libgit2/pygit2/pull/276>`_
- New ``Reference.log_append(...)``:
`#277 <https://github.com/libgit2/pygit2/pull/277>`_
- New ``Blob.is_binary``:
`#278 <https://github.com/libgit2/pygit2/pull/278>`_
- New ``len(Diff)`` shows the number of patches:
`#281 <https://github.com/libgit2/pygit2/pull/281>`_
- Rewrite ``Repository.status()``:
`#283 <https://github.com/libgit2/pygit2/pull/283>`_
- New ``Reference.shorthand``:
`#284 <https://github.com/libgit2/pygit2/pull/284>`_
- New ``Repository.blame(...)``:
`#285 <https://github.com/libgit2/pygit2/pull/285>`_
- Now ``Repository.listall_references()`` and
``Repository.listall_branches()`` return a list, not a tuple:
`#289 <https://github.com/libgit2/pygit2/pull/289>`_
Authors
==============
117 developers have contributed at least 1 commit to pygit2::
93 developers have contributed at least 1 commit to pygit2::
J. David Ibáñez Carlos Martín Nieto Nico von Geyso
W. Trevor King Dave Borowitz Matthias Bartelmeß
Daniel Rodríguez Troitiño Richo Healey Christian Boos
Julien Miotte Richard Möhn Xu Tao
Jose Plana Matthew Duggan Matthew Gamble
Martin Lenders Nick Hynes Petr Hosek
Victor Garcia Xavier Delannoy Yonggang Luo
Patrick Steinhardt Tamir Bahar Valentin Haenel
Michael Jones Bernardo Heynemann Brodie Rao
John Szakmeister Vlad Temian Lukas Fleischer
Nicolas Dandrimont David Versmisse Rémi Duraffort
Santiago Perez De Rosso Sebastian Thiel Thom Wiggers
Alok Singhal Anatoly Techtonik Fraser Tweedale
Han-Wen Nienhuys Jason Ziglar Leonardo Rhodes
Petr Viktorin Robert Hölzl Ron Cohen
W. Trevor King Dave Borowitz Daniel Rodríguez Troitiño
Richo Healey Christian Boos Julien Miotte
Richard Möhn Xu Tao Jose Plana
Matthew Duggan Matthew Gamble Martin Lenders
Petr Hosek Victor Garcia Xavier Delannoy
Yonggang Luo Patrick Steinhardt Valentin Haenel
Michael Jones Bernardo Heynemann John Szakmeister
Vlad Temian Brodie Rao David Versmisse
Rémi Duraffort Sebastian Thiel Alok Singhal
Fraser Tweedale Han-Wen Nienhuys Leonardo Rhodes
Petr Viktorin Ron Cohen Santiago Perez De Rosso
Thomas Kluyver Alex Chamberlain Alexander Bayandin
Amit Bakshi Andrey Devyatkin Arno van Lumig
Ben Davis Dustin Raimondi Eric Schrijver
Greg Fitzgerald Guillermo Pérez Hervé Cauwelier
Huang Huang Ian P. McCullough Igor Gnatenko
Ben Davis Eric Schrijver Greg Fitzgerald
Hervé Cauwelier Huang Huang Ian P. McCullough
Jack O'Connor Jared Flatow Jiunn Haur Lim
Jun Omae Kaarel Kitsemets Kevin KIN-FOO
Mark Adams Masud Rahman Michael Sondergaard
Ondřej Nový Sarath Lakshman Szucs Krisztian
Vicent Marti Zoran Zaric Adam Spiers
Andrew Chin András Veres-Szentkirályi Ash Berlin
Benjamin Kircher Benjamin Pollack Bryan O'Sullivan
Cam Cope Chason Chaffin Chris Rebert
Colin Watson Daniel Bruce David Fischer
David Sanders David Six Devaev Maxim
Sarath Lakshman Vicent Marti Zoran Zaric
Adam Spiers Andrew Chin András Veres-Szentkirályi
Ash Berlin Benjamin Kircher Benjamin Pollack
Bryan O'Sullivan Colin Watson Daniel Bruce
David Fischer David Sanders Devaev Maxim
Eric Davis Erik Meusel Erik van Zijst
Ferengee Gustavo Di Pietrou Holger Frey
Hugh Cole-Baker Jasper Lievisse Adriaanse Josh Bleecher Snyder
Justin Clift Kyriakos Oikonomakos Mathieu Bridon
Matthaus Woolard Nicolás Sanguinetti Noah Fontes
Óscar San José Peter Dave Hello Philippe Ombredanne
Ridge Kennedy Ross Nicoll Rui Abreu Ferreira
Sheeo Soasme Vladimir Rutsky
Yu Jianjian chengyuhang earl
Ferengee Gustavo Di Pietro Holger Frey
Hugh Cole-Baker Jasper Lievisse Josh Bleecher Snyder
Justin Clift Kyriakos Oikonomakos Lukas Fleischer
Mathieu Bridon Michael Sondergaard Óscar San José
Peter Dave Hello Philippe Ombredanne Ridge Kennedy
Ross Nicoll Rui Abreu Ferreira Soasme
Vladimir Rutsky chengyuhang earl
License

@ -1,53 +0,0 @@
version: 1.0.{build}
image: Visual Studio 2015
configuration: Release
environment:
matrix:
- GENERATOR: 'Visual Studio 10'
PYTHON: 'C:\Python27\python.exe'
- GENERATOR: 'Visual Studio 10 Win64'
PYTHON: 'C:\Python27-x64\python.exe'
- GENERATOR: 'Visual Studio 10'
PYTHON: 'C:\Python33\python.exe'
- GENERATOR: 'Visual Studio 10 Win64'
PYTHON: 'C:\Python33-x64\python.exe'
- GENERATOR: 'Visual Studio 10'
PYTHON: 'C:\Python34\python.exe'
- GENERATOR: 'Visual Studio 10 Win64'
PYTHON: 'C:\Python34-x64\python.exe'
- GENERATOR: 'Visual Studio 14'
PYTHON: 'C:\Python35\python.exe'
- GENERATOR: 'Visual Studio 14 Win64'
PYTHON: 'C:\Python35-x64\python.exe'
- GENERATOR: 'Visual Studio 14'
PYTHON: 'C:\Python36\python.exe'
- GENERATOR: 'Visual Studio 14 Win64'
PYTHON: 'C:\Python36-x64\python.exe'
init:
- cmd: '%PYTHON% -m pip install -U nose wheel'
build_script:
- cmd: |
set LIBGIT2=%APPVEYOR_BUILD_FOLDER%\build\libgit2
git clone --depth=1 -b maint/v0.26 https://github.com/libgit2/libgit2.git libgit2
mkdir build
cd build
cmake -DSTDCALL=OFF -DBUILD_CLAR=OFF -DCMAKE_INSTALL_PREFIX="%LIBGIT2%" ../libgit2 -G "%GENERATOR%"
cmake --build . --config Release --target install
cd ..
IF "%GENERATOR%"=="Visual Studio 10 Win64" ( call "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" )
"%PYTHON%" setup.py bdist_wheel
test_script:
- ps: |
cp build\Release\git2.dll .
&$env:PYTHON setup.py nosetests --with-xunit
if ($LastExitCode -ne 0) { $host.SetShouldExit($LastExitCode) }
# upload results to AppVeyor
$wc = New-Object 'System.Net.WebClient'
$wc.UploadFile("https://ci.appveyor.com/api/testresults/junit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path .\nosetests.xml))
artifacts:
- path: dist\*.whl

@ -1,8 +0,0 @@
**********************************************************************
Custom backends
**********************************************************************
There is some support for custom backends, but undocumented. See
`<https://github.com/libgit2/pygit2/pull/690/commits>`_
Documentation contributions are very welcome.

@ -43,16 +43,16 @@ master_doc = 'index'
# General information about the project.
project = u'pygit2'
copyright = u'2010-2015 The pygit2 contributors'
copyright = u'2010-2014 The pygit2 contributors'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '0.26'
version = '0.23'
# The full version, including alpha/beta/rc tags.
release = '0.26.0'
release = '0.23.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.

@ -5,9 +5,6 @@ The development version
.. image:: https://travis-ci.org/libgit2/pygit2.svg?branch=master
:target: http://travis-ci.org/libgit2/pygit2
.. image:: https://ci.appveyor.com/api/projects/status/edmwc0dctk5nacx0/branch/master?svg=true
:target: https://ci.appveyor.com/project/jdavid/pygit2/branch/master
.. code-block:: sh
$ git clone git://github.com/libgit2/pygit2.git

@ -83,9 +83,6 @@ Attributes:
.. autoattribute:: pygit2.DiffFile.path
.. autoattribute:: pygit2.DiffFile.id
.. autoattribute:: pygit2.DiffFile.size
.. autoattribute:: pygit2.DiffFile.flags
.. autoattribute:: pygit2.DiffFile.mode
The DiffHunk type
@ -111,5 +108,5 @@ The DiffLine type
.. autoattribute :: pygit2.DiffLine.origin
.. autoattribute :: pygit2.DiffLine.content
.. autoattribute :: pygit2.DiffLine.old_lineno
.. autoattribute :: pygit2.DiffLine.new_lineno
.. autoattribute :: pygit2.DiffLine.old_lineno
.. autoattribute :: pygit2.DiffLine.num_lines

@ -18,7 +18,7 @@ library that has been built against. The version number has a
.. py:data:: LIBGIT2_VER_MAJOR
Integer value of the major version number. For example, for the version
``0.26.0``::
``0.23.0``::
>>> print LIBGIT2_VER_MAJOR
0
@ -26,15 +26,15 @@ library that has been built against. The version number has a
.. py:data:: LIBGIT2_VER_MINOR
Integer value of the minor version number. For example, for the version
``0.26.0``::
``0.23.0``::
>>> print LIBGIT2_VER_MINOR
26
22
.. py:data:: LIBGIT2_VER_REVISION
Integer value of the revision version number. For example, for the version
``0.26.0``::
``0.23.0``::
>>> print LIBGIT2_VER_REVISION
0
@ -44,7 +44,7 @@ library that has been built against. The version number has a
The libgit2 version number as a string::
>>> print LIBGIT2_VERSION
'0.26.0'
'0.23.0'
Errors
======

@ -7,18 +7,17 @@ Welcome to pygit2's documentation!
==================================
Pygit2 is a set of Python bindings to the libgit2 shared library, libgit2
implements the core of Git. Pygit2 works with Python 2.7, 3.3, 3.4, 3.5,
3.6 and pypy.
implements the core of Git. Pygit2 works with Python 2.7, 3.2, 3.3, 3.4 and
pypy.
It is likely to work with Python 2.6 and 3.1, but these versions are not
officially supported.
Links:
Pygit2 links:
- https://github.com/libgit2/pygit2 -- Source code and issue tracker
- http://github.com/libgit2/pygit2 -- Source code and issue tracker
- http://www.pygit2.org/ -- Documentation
- https://pypi.python.org/pypi/pygit2 -- Download
- https://github.com/libgit2/pygit2/blob/master/CHANGELOG.rst -- Changelog
- http://pypi.python.org/pypi/pygit2 -- Download
Start:
@ -50,7 +49,6 @@ Usage guide:
blame
settings
features
backends
Indices and tables

@ -13,19 +13,11 @@ Installation
Requirements
============
- Python 2.7, 3.3+ or PyPy 2.6+ (including the development headers)
- Libgit2 v0.26.x
- cffi 1.0+
- six
- tox (optional)
Optional libgit2 dependecies to support ssh and https:
- https: WinHTTP (Windows), SecureTransport (OS X) or OpenSSL.
- ssh: libssh2, pkg-config
It should work with older versions of cffi and PyPy, but using cffi 1.0+
(and PyPy 2.6+) is strongly encouraged.
- Python 2.7, 3.2+ or pypy (including the development headers)
- Libgit2 v0.23.x
- cffi 0.8.1+
- Libssh2, optional, used for SSH network operations.
- pkg-config, optional, used for SSH network operations.
.. warning::
@ -43,11 +35,11 @@ while the last number |lq| *.micro* |rq| auto-increments independently.
As illustration see this table of compatible releases:
+-----------+--------+----------------+------------------------+
|**libgit2**| 0.26.0 | 0.25.0, 0.25.1 | 0.24.0, 0.24.1, 0.24.2 |
+-----------+--------+----------------+------------------------+
|**pygit2** | 0.26.0 | 0.25.0, 0.25.1 | 0.24.0, 0.24.1, 0.24.2 |
+-----------+--------+----------------+------------------------+
+-----------+--------+----------------+----------------------------------------+
|**libgit2**| 0.23.0 | 0.22.0, 0.22.1 | 0.21.1, 0.21.2 |
+-----------+--------+----------------+----------------------------------------+
|**pygit2** | 0.23.0 | 0.22.0 | 0.21.0, 0.21.1, 0.21.2, 0.21.3, 0.21.4 |
+-----------+--------+----------------+----------------------------------------+
.. warning::
@ -64,9 +56,9 @@ directory, do:
.. code-block:: sh
$ wget https://github.com/libgit2/libgit2/archive/v0.26.0.tar.gz
$ tar xzf v0.26.0.tar.gz
$ cd libgit2-0.26.0/
$ wget https://github.com/libgit2/libgit2/archive/v0.23.0.tar.gz
$ tar xzf v0.23.0.tar.gz
$ cd libgit2-0.23.0/
$ cmake .
$ make
$ sudo make install
@ -148,9 +140,9 @@ Install libgit2 (see we define the installation prefix):
.. code-block:: sh
$ wget https://github.com/libgit2/libgit2/archive/v0.26.0.tar.gz
$ tar xzf v0.26.0.tar.gz
$ cd libgit2-0.26.0/
$ wget https://github.com/libgit2/libgit2/archive/v0.23.0.tar.gz
$ tar xzf v0.23.0.tar.gz
$ cd libgit2-0.23.0/
$ cmake . -DCMAKE_INSTALL_PREFIX=$LIBGIT2
$ make
$ make install
@ -186,34 +178,32 @@ everytime. Verify yourself if curious:
.. code-block:: sh
$ readelf --dynamic lib/python2.7/site-packages/pygit2-0.26.0-py2.7-linux-x86_64.egg/_pygit2.so | grep PATH
$ readelf --dynamic lib/python2.7/site-packages/pygit2-0.23.0-py2.7-linux-x86_64.egg/_pygit2.so | grep PATH
0x000000000000001d (RUNPATH) Library runpath: [/tmp/venv/lib]
Installing on Windows
===================================
`pygit2` for Windows is packaged into wheels and can be easily
installed with `pip`:
pygit2 expects to find the libgit2 installed files in the directory specified
in the ``LIBGIT2`` environment variable.
pip install pygit2
For development it is also possible to build `pygit2` with `libgit2`
from sources. `libgit2` location is specified by the ``LIBGIT2``
environment variable. `libgit2` should be built in "__cdecl" mode.
The following recipe shows you how to do it from a bash shell:
In addition, make sure that libgit2 is build in "__cdecl" mode.
The following recipe shows you how to do it, assuming you're working
from a bash shell:
.. code-block:: sh
$ export LIBGIT2=C:/Dev/libgit2
$ git clone --depth=1 -b maint/v0.26 https://github.com/libgit2/libgit2.git
$ cd libgit2
$ wget https://github.com/libgit2/libgit2/archive/v0.23.0.tar.gz
$ tar xzf v0.23.0.tar.gz
$ cd libgit2-0.23.0/
$ cmake . -DSTDCALL=OFF -DCMAKE_INSTALL_PREFIX=$LIBGIT2 -G "Visual Studio 9 2008"
$ cmake --build . --config release --target install
$ ctest -v
At this point, you're ready to execute the generic `pygit2`
installation steps described at the start of this page.
At this point, you're ready to execute the generic pygit2 installation
steps described above.
Installing on OS X

@ -132,7 +132,6 @@ them to the Git object database:
.. automethod:: pygit2.Repository.create_blob_fromworkdir
.. automethod:: pygit2.Repository.create_blob_fromdisk
.. automethod:: pygit2.Repository.create_blob_fromiobase
There are also some functions to calculate the id for a byte string without
creating the blob object:
@ -177,7 +176,6 @@ Tree entries
.. autoattribute:: pygit2.TreeEntry.id
.. autoattribute:: pygit2.TreeEntry.hex
.. autoattribute:: pygit2.TreeEntry.filemode
.. autoattribute:: pygit2.TreeEntry.type
.. method:: TreeEntry.__cmp__(TreeEntry)
@ -190,14 +188,14 @@ Example::
6
>>> for entry in tree: # Iteration
... print(entry.id, entry.type, entry.name)
... print(entry.id, entry.name)
...
7151ca7cd3e59f3eab19c485cfbf3cb30928d7fa blob .gitignore
c36f4cf1e38ec1bb9d9ad146ed572b89ecfc9f18 blob COPYING
32b30b90b062f66957d6790c3c155c289c34424e blob README.md
c87dae4094b3a6d10e08bc6c5ef1f55a7e448659 blob pygit2.c
85a67270a49ef16cdd3d328f06a3e4b459f09b27 blob setup.py
3d8985bbec338eb4d47c5b01b863ee89d044bd53 tree test
7151ca7cd3e59f3eab19c485cfbf3cb30928d7fa .gitignore
c36f4cf1e38ec1bb9d9ad146ed572b89ecfc9f18 COPYING
32b30b90b062f66957d6790c3c155c289c34424e README.md
c87dae4094b3a6d10e08bc6c5ef1f55a7e448659 pygit2.c
85a67270a49ef16cdd3d328f06a3e4b459f09b27 setup.py
3d8985bbec338eb4d47c5b01b863ee89d044bd53 test
>>> entry = tree['pygit2.c'] # Get an entry by name
>>> entry

@ -49,7 +49,7 @@ example `three-argument rebases`_.
repo = pygit2.Repository('/path/to/repo')
cherry = repo.revparse_single('9e044d03c')
basket = repo.branches.get('basket')
basket = repo.lookup_branch('basket')
base = repo.merge_base(cherry.oid, basket.target)
base_tree = cherry.parents[0].tree

@ -4,25 +4,15 @@ References
.. contents::
.. autoclass:: pygit2.repository.References
:members:
:undoc-members:
:special-members: __getitem__, __iter__, __contains__
.. automethod:: pygit2.Repository.listall_references
.. automethod:: pygit2.Repository.lookup_reference
Example::
>>> all_refs = list(repo.references)
>>> all_refs = repo.listall_references()
>>> master_ref = repo.lookup_reference("refs/heads/master")
>>> commit = master_ref.get_object() # or repo[master_ref.target]
# Create a reference
>>> ref = repo.references.create('refs/tags/version1', LAST_COMMIT)
# Delete a reference
>>> repo.references.delete('refs/tags/version1')
The Reference type
====================
@ -78,33 +68,28 @@ Branches
Branches inherit from References, and additionally provide specialized
accessors for some unique features.
.. autoclass:: pygit2.repository.Branches
:members:
:undoc-members:
:special-members: __getitem__, __iter__, __contains__
.. automethod:: pygit2.Repository.listall_branches
.. automethod:: pygit2.Repository.lookup_branch
.. automethod:: pygit2.Repository.create_branch
Example::
>>> # Listing all branches
>>> branches_list = list(repo.branches)
>>> # Local only
>>> local_branches = list(repo.branches.local)
>>> # Remote only
>>> remote_branches = list(repo.branches.remote)
>>> local_branches = repo.listall_branches()
>>> # equivalent to
>>> local_branches = repo.listall_branches(pygit2.GIT_BRANCH_LOCAL)
>>> # Get a branch
>>> branch = repo.branches['master']
>>> other_branch = repo.branches['does-not-exist'] # Will raise a KeyError
>>> other_branch = repo.branches.get('does-not-exist') # Returns None
>>> remote_branches = repo.listall_branches(pygit2.GIT_BRANCH_REMOTE)
>>> remote_branch = repo.branches.remote['upstream/feature']
>>> all_branches = repo.listall_branches(pygit2.GIT_BRANCH_REMOTE |
pygit2.GIT_BRANCH_LOCAL)
>>> # Create a local branch
>>> new_branch = repo.branches.local.create('new-branch')
>>> And delete it
>>> repo.branches.delete('new-branch')
>>> master_branch = repo.lookup_branch('master')
>>> # equivalent to
>>> master_branch = repo.lookup_branch('master',
pygit2.GIT_BRANCH_LOCAL)
>>> remote_branch = repo.lookup_branch('upstream/feature',
pygit2.GIT_BRANCH_REMOTE)
The Branch type
====================
@ -113,19 +98,17 @@ The Branch type
.. autoattribute:: pygit2.Branch.remote_name
.. autoattribute:: pygit2.Branch.upstream
.. autoattribute:: pygit2.Branch.upstream_name
.. automethod:: pygit2.Branch.rename
.. automethod:: pygit2.Branch.delete
.. automethod:: pygit2.Branch.is_head
.. automethod:: pygit2.Branch.is_checked_out
The reference log
====================
Example::
>>> head = repo.references.get('refs/heads/master') # Returns None if not found
>>> # Almost equivalent to
>>> head = repo.references['refs/heads/master'] # Raises KeyError if not found
>>> head = repo.lookup_reference('refs/heads/master')
>>> for entry in head.log():
... print(entry.message)

@ -21,12 +21,6 @@ The Remote type
.. autoclass:: pygit2.Remote
:members:
The RemoteCallbacks type
========================
.. autoclass:: pygit2.RemoteCallbacks
:members:
The TransferProgress type
===========================
@ -48,6 +42,8 @@ Refspecs objects are not constructed directly, but returned by
Credentials
================
.. automethod:: pygit2.Remote.credentials
There are two types of credentials: username/password and SSH key
pairs. Both :py:class:`pygit2.UserPass` and :py:class:`pygit2.Keypair`
are callable objects, with the appropriate signature for the

@ -67,11 +67,7 @@ Below there are some general attributes and methods:
.. autoattribute:: pygit2.Repository.default_signature
.. automethod:: pygit2.Repository.read
.. automethod:: pygit2.Repository.write
.. automethod:: pygit2.Repository.ahead_behind
.. automethod:: pygit2.Repository.create_reference
.. automethod:: pygit2.Repository.describe
.. automethod:: pygit2.Repository.path_is_ignored
.. automethod:: pygit2.Repository.reset
.. automethod:: pygit2.Repository.revert_commit
.. automethod:: pygit2.Repository.state_cleanup
.. automethod:: pygit2.Repository.write_archive
.. automethod:: pygit2.Repository.ahead_behind

@ -1,12 +1,10 @@
**********************************************************************
Submodules
The submodule
**********************************************************************
A submodule is a foreign repository that is embedded within a
dedicated subdirectory of the repositories tree.
.. automethod:: pygit2.Repository.init_submodules
.. automethod:: pygit2.Repository.update_submodules
.. automethod:: pygit2.Repository.lookup_submodule
.. automethod:: pygit2.Repository.listall_submodules

@ -71,11 +71,3 @@ Lower level API:
.. automethod:: pygit2.Repository.checkout_head
.. automethod:: pygit2.Repository.checkout_tree
.. automethod:: pygit2.Repository.checkout_index
Stash
====================
.. automethod:: pygit2.Repository.stash
.. automethod:: pygit2.Repository.stash_apply
.. automethod:: pygit2.Repository.stash_drop
.. automethod:: pygit2.Repository.stash_pop

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright 2010-2017 The pygit2 contributors
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,
@ -35,15 +35,15 @@ from _pygit2 import *
from .blame import Blame, BlameHunk
from .config import Config
from .credentials import *
from .errors import check_error, Passthrough
from .errors import check_error
from .ffi import ffi, C
from .index import Index, IndexEntry
from .remote import Remote, RemoteCallbacks, get_credentials
from .remote import Remote, get_credentials
from .repository import Repository
from .settings import Settings
from .submodule import Submodule
from .utils import to_bytes, to_str
from ._build import __version__
from ._utils import __version__
# Features
@ -105,9 +105,6 @@ def init_repository(path, bare=False,
See libgit2's documentation on git_repository_init_ext for further details.
"""
# Pre-process input parameters
if path is None:
raise TypeError('Expected string type for path, found None.')
if bare:
flags |= GIT_REPOSITORY_INIT_BARE
@ -146,6 +143,22 @@ def init_repository(path, bare=False,
# Ok
return Repository(to_str(path))
@ffi.callback('int (*credentials)(git_cred **cred, const char *url,'
'const char *username_from_url, unsigned int allowed_types,'
'void *data)')
def _credentials_cb(cred_out, url, username_from_url, allowed, data):
d = ffi.from_handle(data)
try:
ccred = get_credentials(d['credentials_cb'], url, username_from_url, allowed)
cred_out[0] = ccred[0]
except Exception as e:
d['exception'] = e
return C.GIT_EUSER
return 0
@ffi.callback('int (*git_repository_create_cb)(git_repository **out,'
'const char *path, int bare, void *payload)')
def _repository_create_cb(repo_out, path, bare, data):
@ -176,9 +189,24 @@ def _remote_create_cb(remote_out, repo, name, url, data):
return 0
@ffi.callback('int (*git_transport_certificate_check_cb)'
'(git_cert *cert, int valid, const char *host, void *payload)')
def _certificate_cb(cert_i, valid, host, data):
d = ffi.from_handle(data)
try:
# python's parting is deep in the libraries and assumes an OpenSSL-owned cert
val = d['certificate_cb'](None, bool(valid), ffi.string(host))
if not val:
return C.GIT_ECERTIFICATE
except Exception as e:
d['exception'] = e
return C.GIT_EUSER
return 0
def clone_repository(
url, path, bare=False, repository=None, remote=None,
checkout_branch=None, callbacks=None):
checkout_branch=None, credentials=None, certificate=None):
"""Clones a new Git repository from *url* in the given *path*.
Returns a Repository class pointing to the newly cloned repository.
@ -196,8 +224,11 @@ def clone_repository(
:param str checkout_branch: Branch to checkout after the
clone. The default is to use the remote's default branch.
:param RemoteCallbacks callbacks: object which implements the
callbacks as methods.
:param callable credentials: authentication to use if the remote
requires it
:param callable certificate: callback to verify the host's
certificate or fingerprint.
:rtype: Repository
@ -209,8 +240,8 @@ def clone_repository(
signature. The Remote it returns will be used instead of the default
one.
The callbacks should be an object which inherits from
`pyclass:RemoteCallbacks`.
The certificate callback has `(cert, valid, hostname) -> bool` as
a signature. Return True to accept the connection, False to abort.
"""
@ -221,8 +252,10 @@ def clone_repository(
# Data, let's use a dict as we don't really want much more
d = {}
d['credentials_cb'] = credentials
d['repository_cb'] = repository
d['remote_cb'] = remote
d['certificate_cb'] = certificate
d_handle = ffi.new_handle(d)
# Perform the initialization with the version we compiled
@ -244,11 +277,13 @@ def clone_repository(
opts.bare = bare
if credentials:
opts.fetch_opts.callbacks.credentials = _credentials_cb
opts.fetch_opts.callbacks.payload = d_handle
if callbacks is None:
callbacks = RemoteCallbacks()
callbacks._fill_fetch_options(opts.fetch_opts)
if certificate:
opts.fetch_opts.callbacks.certificate_check = _certificate_cb
opts.fetch_opts.callbacks.payload = d_handle
err = C.git_clone(crepo, to_bytes(url), to_bytes(path), opts)

@ -1,76 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright 2010-2017 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,
# as published by the Free Software Foundation.
#
# In addition to the permissions in the GNU General Public License,
# the authors give you unlimited permission to link the compiled
# version of this file into combinations with other programs,
# and to distribute those combinations without any restriction
# coming from the use of this file. (The General Public License
# restrictions do apply in other respects; for example, they cover
# modification of the file, and distribution when not linked into
# a combined executable.)
#
# This file is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING. If not, write to
# the Free Software Foundation, 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301, USA.
"""
This is an special module, it provides stuff used by by pygit2 at run-time.
"""
# Import from the Standard Library
import codecs
import os
from os.path import abspath, dirname
import sys
# Import from cffi
from cffi import FFI
# Import from pygit2
from _build import get_libgit2_paths
# C_HEADER_SRC
if getattr(sys, 'frozen', False):
dir_path = getattr(sys, '_MEIPASS', None)
if dir_path is None:
dir_path = dirname(abspath(sys.executable))
else:
dir_path = dirname(abspath(__file__))
decl_path = os.path.join(dir_path, 'decl.h')
with codecs.open(decl_path, 'r', 'utf-8') as header:
C_HEADER_SRC = header.read()
# C_KEYWORDS
libgit2_bin, libgit2_include, libgit2_lib = get_libgit2_paths()
C_KEYWORDS = dict(libraries=['git2'],
library_dirs=[libgit2_lib],
include_dirs=[libgit2_include])
# preamble
preamble = "#include <git2.h>"
# ffi
ffi = FFI()
set_source = getattr(ffi, 'set_source', None)
if set_source is not None:
set_source("pygit2._libgit2", preamble, **C_KEYWORDS)
ffi.cdef(C_HEADER_SRC)
if __name__ == '__main__':
ffi.compile()

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright 2010-2017 The pygit2 contributors
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,
@ -26,18 +26,23 @@
# Boston, MA 02110-1301, USA.
"""
This is an special module, it provides stuff used by setup.py at build time.
But also used by pygit2 at run time.
This is an special module, it provides stuff used by setup.py and by
pygit2 at run-time.
"""
# Import from the Standard Library
from binascii import crc32
import codecs
import os
from os import getenv
from os.path import abspath, dirname
import sys
#
# The version number of pygit2
#
__version__ = '0.26.0'
__version__ = '0.23.0'
#
@ -62,3 +67,44 @@ def get_libgit2_paths():
os.path.join(libgit2_path, 'include'),
getenv('LIBGIT2_LIB', os.path.join(libgit2_path, 'lib')),
)
#
# Loads the cffi extension
#
def get_ffi():
import cffi
ffi = cffi.FFI()
# Load C definitions
if getattr(sys, 'frozen', False):
if hasattr(sys, '_MEIPASS'):
dir_path = sys._MEIPASS
else:
dir_path = dirname(abspath(sys.executable))
else:
dir_path = dirname(abspath(__file__))
decl_path = os.path.join(dir_path, 'decl.h')
with codecs.open(decl_path, 'r', 'utf-8') as header:
ffi.cdef(header.read())
# The modulename
# Simplified version of what cffi does: remove kwargs and vengine
preamble = "#include <git2.h>"
key = [sys.version[:3], cffi.__version__, preamble] + ffi._cdefsources
key = '\x00'.join(key)
if sys.version_info >= (3,):
key = key.encode('utf-8')
k1 = hex(crc32(key[0::2]) & 0xffffffff).lstrip('0x').rstrip('L')
k2 = hex(crc32(key[1::2]) & 0xffffffff).lstrip('0').rstrip('L')
modulename = 'pygit2_cffi_%s%s' % (k1, k2)
# Load extension module
libgit2_bin, libgit2_include, libgit2_lib = get_libgit2_paths()
C = ffi.verify(preamble, modulename=modulename, libraries=["git2"],
include_dirs=[libgit2_include], library_dirs=[libgit2_lib])
# Ok
return ffi, C

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright 2010-2017 The pygit2 contributors
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright 2010-2017 The pygit2 contributors
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright 2010-2017 The pygit2 contributors
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,

@ -54,16 +54,6 @@ typedef enum {
GIT_EINVALIDSPEC = -12,
GIT_ECONFLICT = -13,
GIT_ELOCKED = -14,
GIT_EMODIFIED = -15,
GIT_EAUTH = -16,
GIT_ECERTIFICATE = -17,
GIT_EAPPLIED = -18,
GIT_EPEEL = -19,
GIT_EEOF = -20,
GIT_EINVALID = -21,
GIT_EUNCOMMITTED = -22,
GIT_EDIRECTORY = -23,
GIT_EMERGECONFLICT = -24,
GIT_PASSTHROUGH = -30,
GIT_ITEROVER = -31,
@ -141,21 +131,21 @@ typedef enum {
typedef struct {
git_cert_t cert_type;
} git_cert;
typedef struct {
git_cert parent;
git_cert_ssh_t type;
unsigned char hash_md5[16];
unsigned char hash_sha1[20];
} git_cert_hostkey;
typedef struct {
git_cert parent;
git_cert_t cert_type;
void *data;
size_t len;
} git_cert_x509;
typedef struct {
git_cert_t cert_type;
} git_cert;
typedef int (*git_transport_message_cb)(const char *str, int len, void *data);
typedef int (*git_cred_acquire_cb)(
git_cred **cred,
@ -207,30 +197,10 @@ struct git_remote_callbacks {
typedef struct git_remote_callbacks git_remote_callbacks;
typedef enum {
GIT_PROXY_NONE,
GIT_PROXY_AUTO,
GIT_PROXY_SPECIFIED,
} git_proxy_t;
typedef struct {
unsigned int version;
git_proxy_t type;
const char *url;
git_cred_acquire_cb credentials;
git_transport_certificate_check_cb certificate_check;
void *payload;
} git_proxy_options;
#define GIT_PROXY_OPTIONS_VERSION ...
int git_proxy_init_options(git_proxy_options *opts, unsigned int version);
typedef struct {
unsigned int version;
unsigned int pb_parallelism;
git_remote_callbacks callbacks;
git_proxy_options proxy_opts;
git_strarray custom_headers;
} git_push_options;
#define GIT_PUSH_OPTIONS_VERSION ...
@ -255,8 +225,6 @@ typedef struct {
git_fetch_prune_t prune;
int update_fetchhead;
git_remote_autotag_option_t download_tags;
git_proxy_options proxy_opts;
git_strarray custom_headers;
} git_fetch_options;
#define GIT_FETCH_OPTIONS_VERSION ...
@ -368,20 +336,13 @@ typedef int (*git_diff_notify_cb)(
const char *matched_pathspec,
void *payload);
typedef int (*git_diff_progress_cb)(
const git_diff *diff_so_far,
const char *old_path,
const char *new_path,
void *payload);
typedef struct {
unsigned int version;
uint32_t flags;
git_submodule_ignore_t ignore_submodules;
git_strarray pathspec;
git_diff_notify_cb notify_cb;
git_diff_progress_cb progress_cb;
void *payload;
git_diff_notify_cb notify_cb;
void *notify_payload;
uint32_t context_lines;
uint32_t interhunk_lines;
uint16_t id_abbrev;
@ -410,16 +371,7 @@ int git_diff_tree_to_index(git_diff **diff, git_repository *repo, git_tree *old_
* git_checkout
*/
typedef enum {
GIT_CHECKOUT_NOTIFY_NONE = 0,
GIT_CHECKOUT_NOTIFY_CONFLICT = 1,
GIT_CHECKOUT_NOTIFY_DIRTY = 2,
GIT_CHECKOUT_NOTIFY_UPDATED = 4,
GIT_CHECKOUT_NOTIFY_UNTRACKED = 8,
GIT_CHECKOUT_NOTIFY_IGNORED = 16,
GIT_CHECKOUT_NOTIFY_ALL = 0x0FFFF
} git_checkout_notify_t;
typedef enum { ... } git_checkout_notify_t;
typedef int (*git_checkout_notify_cb)(
git_checkout_notify_t why,
@ -526,12 +478,11 @@ typedef ... git_config;
typedef ... git_config_iterator;
typedef enum {
GIT_CONFIG_LEVEL_PROGRAMDATA = 1,
GIT_CONFIG_LEVEL_SYSTEM = 2,
GIT_CONFIG_LEVEL_XDG = 3,
GIT_CONFIG_LEVEL_GLOBAL = 4,
GIT_CONFIG_LEVEL_LOCAL = 5,
GIT_CONFIG_LEVEL_APP = 6,
GIT_CONFIG_LEVEL_SYSTEM = 1,
GIT_CONFIG_LEVEL_XDG = 2,
GIT_CONFIG_LEVEL_GLOBAL = 3,
GIT_CONFIG_LEVEL_LOCAL = 4,
GIT_CONFIG_LEVEL_APP = 5,
GIT_CONFIG_HIGHEST_LEVEL = -1,
} git_config_level_t;
@ -720,22 +671,22 @@ typedef struct git_blame_options {
uint16_t min_match_characters;
git_oid newest_commit;
git_oid oldest_commit;
size_t min_line;
size_t max_line;
uint32_t min_line;
uint32_t max_line;
} git_blame_options;
#define GIT_BLAME_OPTIONS_VERSION ...
typedef struct git_blame_hunk {
size_t lines_in_hunk;
uint16_t lines_in_hunk;
git_oid final_commit_id;
size_t final_start_line_number;
uint16_t final_start_line_number;
git_signature *final_signature;
git_oid orig_commit_id;
const char *orig_path;
size_t orig_start_line_number;
uint16_t orig_start_line_number;
git_signature *orig_signature;
char boundary;
@ -744,7 +695,7 @@ typedef struct git_blame_hunk {
int git_blame_init_options(git_blame_options *opts, unsigned int version);
uint32_t git_blame_get_hunk_count(git_blame *blame);
const git_blame_hunk *git_blame_get_hunk_byindex(git_blame *blame, uint32_t index);
const git_blame_hunk *git_blame_get_hunk_byline(git_blame *blame, size_t lineno);
const git_blame_hunk *git_blame_get_hunk_byline(git_blame *blame, uint32_t lineno);
int git_blame_file(git_blame **out, git_repository *repo, const char *path, git_blame_options *options);
void git_blame_free(git_blame *blame);
@ -752,12 +703,7 @@ void git_blame_free(git_blame *blame);
* Merging
*/
typedef enum {
GIT_MERGE_FIND_RENAMES = 1,
GIT_MERGE_FAIL_ON_CONFLICT = 2,
GIT_MERGE_SKIP_REUC = 4,
GIT_MERGE_NO_RECURSIVE = 8,
} git_merge_flag_t;
typedef enum { ... } git_merge_tree_flag_t;
typedef enum {
GIT_MERGE_FILE_FAVOR_NORMAL = 0,
@ -768,12 +714,10 @@ typedef enum {
typedef struct {
unsigned int version;
git_merge_flag_t flags;
git_merge_tree_flag_t tree_flags;
unsigned int rename_threshold;
unsigned int target_limit;
git_diff_similarity_metric *metric;
unsigned int recursion_limit;
const char *default_driver;
git_merge_file_favor_t file_favor;
unsigned int file_flags;
} git_merge_options;
@ -793,12 +737,7 @@ typedef enum {
GIT_MERGE_FILE_STYLE_MERGE = 1,
GIT_MERGE_FILE_STYLE_DIFF3 = 2,
GIT_MERGE_FILE_SIMPLIFY_ALNUM = 4,
GIT_MERGE_FILE_IGNORE_WHITESPACE = 8,
GIT_MERGE_FILE_IGNORE_WHITESPACE_CHANGE = 16,
GIT_MERGE_FILE_IGNORE_WHITESPACE_EOL = 32,
GIT_MERGE_FILE_DIFF_PATIENCE = 64,
GIT_MERGE_FILE_DIFF_MINIMAL = 128,
} git_merge_file_flag_t;
} git_merge_file_flags_t;
typedef struct {
unsigned int version;
@ -806,7 +745,7 @@ typedef struct {
const char *our_label;
const char *their_label;
git_merge_file_favor_t favor;
git_merge_file_flag_t flags;
git_merge_file_flags_t flags;
} git_merge_file_options;
#define GIT_MERGE_OPTIONS_VERSION ...
@ -817,97 +756,6 @@ int git_merge_trees(git_index **out, git_repository *repo, const git_tree *ances
int git_merge_file_from_index(git_merge_file_result *out, git_repository *repo, const git_index_entry *ancestor, const git_index_entry *ours, const git_index_entry *theirs, const git_merge_file_options *opts);
void git_merge_file_result_free(git_merge_file_result *result);
/*
* git_stash
*/
typedef int (*git_stash_cb)(
size_t index, const char* message, const git_oid *stash_id, void *payload);
typedef enum {
GIT_STASH_APPLY_PROGRESS_NONE = 0,
GIT_STASH_APPLY_PROGRESS_LOADING_STASH = 1,
GIT_STASH_APPLY_PROGRESS_ANALYZE_INDEX = 2,
GIT_STASH_APPLY_PROGRESS_ANALYZE_MODIFIED = 3,
GIT_STASH_APPLY_PROGRESS_ANALYZE_UNTRACKED = 4,
GIT_STASH_APPLY_PROGRESS_CHECKOUT_UNTRACKED = 5,
GIT_STASH_APPLY_PROGRESS_CHECKOUT_MODIFIED = 6,
GIT_STASH_APPLY_PROGRESS_DONE = 7,
} git_stash_apply_progress_t;
typedef int (*git_stash_apply_progress_cb)(
git_stash_apply_progress_t progress, void *payload);
typedef enum {
GIT_STASH_DEFAULT = 0,
GIT_STASH_KEEP_INDEX = 1,
GIT_STASH_INCLUDE_UNTRACKED = 2,
GIT_STASH_INCLUDE_IGNORED = 4,
} git_stash_flags;
typedef enum {
GIT_STASH_APPLY_DEFAULT = 0,
GIT_STASH_APPLY_REINSTATE_INDEX = 1,
} git_stash_apply_flags;
typedef struct git_stash_apply_options {
unsigned int version;
git_stash_apply_flags flags;
git_checkout_options checkout_options;
git_stash_apply_progress_cb progress_cb;
void *progress_payload;
} git_stash_apply_options;
#define GIT_STASH_APPLY_OPTIONS_VERSION ...
int git_stash_save(git_oid *out, git_repository *repo, const git_signature *stasher, const char *message, uint32_t flags);
int git_stash_apply_init_options(git_stash_apply_options *opts, unsigned int version);
int git_stash_apply(git_repository *repo, size_t index, const git_stash_apply_options *options);
int git_stash_foreach(git_repository *repo, git_stash_cb callback, void *payload);
int git_stash_drop(git_repository *repo, size_t index);
int git_stash_pop(git_repository *repo, size_t index, const git_stash_apply_options *options);
/*
* Describe
*/
typedef enum {
GIT_DESCRIBE_DEFAULT,
GIT_DESCRIBE_TAGS,
GIT_DESCRIBE_ALL,
} git_describe_strategy_t;
typedef struct git_describe_options {
unsigned int version;
unsigned int max_candidates_tags;
unsigned int describe_strategy;
const char *pattern;
int only_follow_first_parent;
int show_commit_oid_as_fallback;
} git_describe_options;
#define GIT_DESCRIBE_OPTIONS_VERSION ...
int git_describe_init_options(git_describe_options *opts, unsigned int version);
typedef struct {
unsigned int version;
unsigned int abbreviated_size;
int always_use_long_format;
const char *dirty_suffix;
} git_describe_format_options;
#define GIT_DESCRIBE_FORMAT_OPTIONS_VERSION ...
int git_describe_init_format_options(git_describe_format_options *opts, unsigned int version);
typedef ... git_describe_result;
int git_describe_commit(git_describe_result **result, git_object *committish, git_describe_options *opts);
int git_describe_workdir(git_describe_result **out, git_repository *repo, git_describe_options *opts);
int git_describe_format(git_buf *out, const git_describe_result *result, const git_describe_format_options *opts);
void git_describe_result_free(git_describe_result *result);
#define GIT_ATTR_CHECK_FILE_THEN_INDEX ...
#define GIT_ATTR_CHECK_INDEX_THEN_FILE ...
#define GIT_ATTR_CHECK_INDEX_ONLY ...
@ -922,5 +770,3 @@ typedef enum {
int git_attr_get(const char **value_out, git_repository *repo, uint32_t flags, const char *path, const char *name);
git_attr_t git_attr_value(const char *attr);
int git_revert_commit(git_index **out, git_repository *repo, git_commit *revert_commit, git_commit *our_commit, unsigned int mainline, const git_merge_options *merge_options);

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright 2010-2017 The pygit2 contributors
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,
@ -40,7 +40,7 @@ def check_error(err, io=False):
# Error message
giterr = C.giterr_last()
if giterr != ffi.NULL:
message = ffi.string(giterr.message).decode('utf8')
message = ffi.string(giterr.message).decode()
else:
message = "err %d (no message provided)" % err
@ -62,8 +62,3 @@ def check_error(err, io=False):
# Generic Git error
raise GitError(message)
# Indicate that we want libgit2 to pretend a function was not set
class Passthrough(Exception):
def __init__(self):
super(Passthrough, self).__init__( "The function asked for pass-through")

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright 2010-2017 The pygit2 contributors
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,
@ -29,8 +29,7 @@
from __future__ import absolute_import
# Import from pygit2
try:
from ._libgit2 import ffi, lib as C
except ImportError:
from ._run import ffi, preamble, C_KEYWORDS
C = ffi.verify(preamble, **C_KEYWORDS)
from ._utils import get_ffi
ffi, C = get_ffi()

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright 2010-2017 The pygit2 contributors
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,
@ -28,8 +28,6 @@
# Import from the future
from __future__ import absolute_import, unicode_literals
import weakref
# Import from pygit2
from _pygit2 import Oid, Tree, Diff
from .errors import check_error
@ -50,7 +48,6 @@ class Index(object):
err = C.git_index_open(cindex, to_bytes(path))
check_error(err)
self._repo = None
self._index = cindex[0]
self._cindex = cindex
@ -128,15 +125,14 @@ class Index(object):
The tree will be read recursively and all its children will also be
inserted into the Index.
"""
repo = self._repo
if is_string(tree):
tree = repo[tree]
tree = self._repo[tree]
if isinstance(tree, Oid):
if repo is None:
if not hasattr(self, '_repo'):
raise TypeError("id given but no associated repository")
tree = repo[tree]
tree = self._repo[tree]
elif not isinstance(tree, Tree):
raise TypeError("argument must be Oid or Tree")
@ -157,9 +153,6 @@ class Index(object):
It returns the id of the resulting tree.
"""
coid = ffi.new('git_oid *')
repo = repo or self._repo
if repo:
err = C.git_index_write_tree_to(coid, self._index, repo._repo)
else:
@ -221,8 +214,7 @@ class Index(object):
interhunk_lines: the maximum number of unchanged lines between hunk
boundaries before the hunks will be merged into a one
"""
repo = self._repo
if repo is None:
if not hasattr(self, '_repo'):
raise ValueError('diff needs an associated repository')
copts = ffi.new('git_diff_options *')
@ -234,11 +226,11 @@ class Index(object):
copts.interhunk_lines = interhunk_lines
cdiff = ffi.new('git_diff **')
err = C.git_diff_index_to_workdir(cdiff, repo._repo, self._index,
copts)
err = C.git_diff_index_to_workdir(cdiff, self._repo._repo,
self._index, copts)
check_error(err)
return Diff.from_c(bytes(ffi.buffer(cdiff)[:]), repo)
return Diff.from_c(bytes(ffi.buffer(cdiff)[:]), self._repo)
def diff_to_tree(self, tree, flags=0, context_lines=3, interhunk_lines=0):
"""Diff the index against a tree. Return a <Diff> object with the
@ -256,8 +248,8 @@ class Index(object):
interhunk_lines: the maximum number of unchanged lines between hunk
boundaries before the hunks will be merged into a one.
"""
repo = self._repo
if repo is None:
if not hasattr(self, '_repo'):
raise ValueError('diff needs an associated repository')
if not isinstance(tree, Tree):
@ -275,11 +267,11 @@ class Index(object):
ffi.buffer(ctree)[:] = tree._pointer[:]
cdiff = ffi.new('git_diff **')
err = C.git_diff_tree_to_index(cdiff, repo._repo, ctree[0],
err = C.git_diff_tree_to_index(cdiff, self._repo._repo, ctree[0],
self._index, copts)
check_error(err)
return Diff.from_c(bytes(ffi.buffer(cdiff)[:]), repo)
return Diff.from_c(bytes(ffi.buffer(cdiff)[:]), self._repo)
#
@ -310,12 +302,10 @@ class Index(object):
self._conflicts = None
return None
if self._conflicts is None or self._conflicts() is None:
conflicts = ConflictCollection(self)
self._conflicts = weakref.ref(conflicts)
return conflicts
if self._conflicts is None:
self._conflicts = ConflictCollection(self)
return self._conflicts()
return self._conflicts
class IndexEntry(object):

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright 2010-2017 The pygit2 contributors
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright 2010-2017 The pygit2 contributors
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright 2010-2017 The pygit2 contributors
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright 2010-2017 The pygit2 contributors
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,
@ -30,8 +30,9 @@ from __future__ import absolute_import
# Import from pygit2
from _pygit2 import Oid
from .errors import check_error, Passthrough
from .errors import check_error, GitError
from .ffi import ffi, C
from .credentials import KeypairFromAgent
from .refspec import Refspec
from .utils import to_bytes, strarray_to_strings, StrArray
@ -70,27 +71,7 @@ class TransferProgress(object):
""""Number of bytes received up to now"""
class RemoteCallbacks(object):
"""Base class for pygit2 remote callbacks.
Inherit from this class and override the callbacks which you want to use
in your class, which you can then pass to the network operations.
"""
def __init__(self, credentials=None, certificate=None):
"""Initialize some callbacks in-line
Use this constructor to provide credentials and certificate
callbacks in-line, instead of defining your own class for these ones.
You can e.g. also pass in one of the credential objects as 'credentials'
instead of creating a function which returns a hard-coded object.
"""
if credentials is not None:
self.credentials = credentials
if certificate is not None:
self.certificate = certificate
class Remote(object):
def sideband_progress(self, string):
"""Progress output callback
@ -99,6 +80,7 @@ class RemoteCallbacks(object):
:param str string: Progress output from the remote
"""
pass
def credentials(self, url, username_from_url, allowed_types):
"""Credentials callback
@ -118,26 +100,7 @@ class RemoteCallbacks(object):
Return value: credential
"""
raise Passthrough
def certificate_check(self, certificate, valid, host):
"""Certificate callback
Override with your own function to determine whether the accept
the server's certificate.
:param None certificate: The certificate. It is currently always None
while we figure out how to represent it cross-platform
:param bool valid: Whether the TLS/SSH library thinks the certificate
is valid
:param str host: The hostname we want to connect to
Return value: True to connect, False to abort
"""
raise Passthrough
pass
def transfer_progress(self, stats):
"""Transfer progress callback
@ -146,6 +109,7 @@ class RemoteCallbacks(object):
:param TransferProgress stats: The progress up to now
"""
pass
def update_tips(self, refname, old, new):
"""Update tips callabck
@ -167,159 +131,6 @@ class RemoteCallbacks(object):
:param str messsage: rejection message from the remote. If None, the update was accepted.
"""
def _fill_fetch_options(self, fetch_opts):
fetch_opts.callbacks.sideband_progress = self._sideband_progress_cb
fetch_opts.callbacks.transfer_progress = self._transfer_progress_cb
fetch_opts.callbacks.update_tips = self._update_tips_cb
fetch_opts.callbacks.credentials = self._credentials_cb
fetch_opts.callbacks.certificate_check = self._certificate_cb
# We need to make sure that this handle stays alive
self._self_handle = ffi.new_handle(self)
fetch_opts.callbacks.payload = self._self_handle
self._stored_exception = None
def _fill_push_options(self, push_opts):
push_opts.callbacks.sideband_progress = self._sideband_progress_cb
push_opts.callbacks.transfer_progress = self._transfer_progress_cb
push_opts.callbacks.update_tips = self._update_tips_cb
push_opts.callbacks.credentials = self._credentials_cb
push_opts.callbacks.certificate_check = self._certificate_cb
push_opts.callbacks.push_update_reference = self._push_update_reference_cb
# We need to make sure that this handle stays alive
self._self_handle = ffi.new_handle(self)
push_opts.callbacks.payload = self._self_handle
# These functions exist to be called by the git_remote as
# callbacks. They proxy the call to whatever the user set
@ffi.callback('git_transfer_progress_cb')
def _transfer_progress_cb(stats_ptr, data):
self = ffi.from_handle(data)
transfer_progress = getattr(self, 'transfer_progress', None)
if not transfer_progress:
return 0
try:
transfer_progress(TransferProgress(stats_ptr))
except Exception as e:
self._stored_exception = e
return C.GIT_EUSER
return 0
@ffi.callback('git_transport_message_cb')
def _sideband_progress_cb(string, length, data):
self = ffi.from_handle(data)
progress = getattr(self, 'progress', None)
if not progress:
return 0
try:
s = ffi.string(string, length).decode()
progress(s)
except Exception as e:
self._stored_exception = e
return C.GIT_EUSER
return 0
@ffi.callback('int (*update_tips)(const char *refname, const git_oid *a,'
'const git_oid *b, void *data)')
def _update_tips_cb(refname, a, b, data):
self = ffi.from_handle(data)
update_tips = getattr(self, 'update_tips', None)
if not update_tips:
return 0
try:
s = maybe_string(refname)
a = Oid(raw=bytes(ffi.buffer(a)[:]))
b = Oid(raw=bytes(ffi.buffer(b)[:]))
update_tips(s, a, b)
except Exception as e:
self._stored_exception = e
return C.GIT_EUSER
return 0
@ffi.callback("int (*push_update_reference)(const char *ref, const char *msg, void *data)")
def _push_update_reference_cb(ref, msg, data):
self = ffi.from_handle(data)
push_update_reference = getattr(self, 'push_update_reference', None)
if not push_update_reference:
return 0
try:
refname = ffi.string(ref)
message = maybe_string(msg)
push_update_reference(refname, message)
except Exception as e:
self._stored_exception = e
return C.GIT_EUSER
return 0
@ffi.callback('int (*credentials)(git_cred **cred, const char *url,'
'const char *username_from_url, unsigned int allowed_types,'
'void *data)')
def _credentials_cb(cred_out, url, username, allowed, data):
self = ffi.from_handle(data)
credentials = getattr(self, 'credentials', None)
if not credentials:
return 0
try:
ccred = get_credentials(credentials, url, username, allowed)
cred_out[0] = ccred[0]
except Passthrough as e:
return C.GIT_PASSTHROUGH
except Exception as e:
self._stored_exception = e
return C.GIT_EUSER
return 0
@ffi.callback('int (*git_transport_certificate_check_cb)'
'(git_cert *cert, int valid, const char *host, void *payload)')
def _certificate_cb(cert_i, valid, host, data):
self = ffi.from_handle(data)
# We want to simulate what should happen if libgit2 supported pass-through for
# this callback. For SSH, 'valid' is always False, because it doesn't look
# at known_hosts, but we do want to let it through in order to do what libgit2 would
# if the callback were not set.
try:
is_ssh = cert_i.cert_type == C.GIT_CERT_HOSTKEY_LIBSSH2
certificate_check = getattr(self, 'certificate_check', None)
if not certificate_check:
raise Passthrough
# python's parsing is deep in the libraries and assumes an OpenSSL-owned cert
val = certificate_check(None, bool(valid), ffi.string(host))
if not val:
return C.GIT_ECERTIFICATE
except Passthrough as e:
if is_ssh:
return 0
elif valid:
return 0
else:
return C.GIT_ECERTIFICATE
except Exception as e:
self._stored_exception = e
return C.GIT_EUSER
return 0
class Remote(object):
def __init__(self, repo, ptr):
"""The constructor is for internal use only"""
@ -354,7 +165,7 @@ class Remote(object):
err = C.git_remote_save(self._remote)
check_error(err)
def fetch(self, refspecs=None, message=None, callbacks=None):
def fetch(self, refspecs=None, message=None):
"""Perform a fetch against this remote. Returns a <TransferProgress>
object.
"""
@ -362,19 +173,24 @@ class Remote(object):
fetch_opts = ffi.new('git_fetch_options *')
err = C.git_fetch_init_options(fetch_opts, C.GIT_FETCH_OPTIONS_VERSION)
if callbacks is None:
callbacks = RemoteCallbacks()
fetch_opts.callbacks.sideband_progress = self._sideband_progress_cb
fetch_opts.callbacks.transfer_progress = self._transfer_progress_cb
fetch_opts.callbacks.update_tips = self._update_tips_cb
fetch_opts.callbacks.credentials = self._credentials_cb
# We need to make sure that this handle stays alive
self._self_handle = ffi.new_handle(self)
fetch_opts.callbacks.payload = self._self_handle
callbacks._fill_fetch_options(fetch_opts)
self._stored_exception = None
try:
with StrArray(refspecs) as arr:
err = C.git_remote_fetch(self._remote, arr, fetch_opts, to_bytes(message))
if callbacks._stored_exception:
raise callbacks._stored_exception
if self._stored_exception:
raise self._stored_exception
check_error(err)
finally:
callbacks._self_handle = None
self._self_handle = None
return TransferProgress(C.git_remote_stats(self._remote))
@ -409,33 +225,123 @@ class Remote(object):
return strarray_to_strings(specs)
def push(self, specs, callbacks=None):
def push(self, specs):
"""Push the given refspec to the remote. Raises ``GitError`` on
protocol error or unpack failure.
When the remote has a githook installed, that denies the reference
this function will return successfully. Thus it is stronly recommended
to install a callback, that implements
:py:meth:`RemoteCallbacks.push_update_reference` and check the passed
parameters for successfull operations.
:param [str] specs: push refspecs to use
"""
push_opts = ffi.new('git_push_options *')
err = C.git_push_init_options(push_opts, C.GIT_PUSH_OPTIONS_VERSION)
if callbacks is None:
callbacks = RemoteCallbacks()
callbacks._fill_push_options(push_opts)
# Build custom callback structure
push_opts.callbacks.sideband_progress = self._sideband_progress_cb
push_opts.callbacks.transfer_progress = self._transfer_progress_cb
push_opts.callbacks.update_tips = self._update_tips_cb
push_opts.callbacks.credentials = self._credentials_cb
push_opts.callbacks.push_update_reference = self._push_update_reference_cb
# We need to make sure that this handle stays alive
self._self_handle = ffi.new_handle(self)
push_opts.callbacks.payload = self._self_handle
try:
with StrArray(specs) as refspecs:
err = C.git_remote_push(self._remote, refspecs, push_opts)
err = C.git_remote_push(self._remote, refspecs, ffi.NULL)
check_error(err)
finally:
callbacks._self_handle = None
self._self_handle = None
# These functions exist to be called by the git_remote as
# callbacks. They proxy the call to whatever the user set
@ffi.callback('git_transfer_progress_cb')
def _transfer_progress_cb(stats_ptr, data):
self = ffi.from_handle(data)
if not hasattr(self, 'transfer_progress') \
or not self.transfer_progress:
return 0
try:
self.transfer_progress(TransferProgress(stats_ptr))
except Exception as e:
self._stored_exception = e
return C.GIT_EUSER
return 0
@ffi.callback('git_transport_message_cb')
def _sideband_progress_cb(string, length, data):
self = ffi.from_handle(data)
if not hasattr(self, 'progress') or not self.progress:
return 0
try:
s = ffi.string(string, length).decode()
self.progress(s)
except Exception as e:
self._stored_exception = e
return C.GIT_EUSER
return 0
@ffi.callback('int (*update_tips)(const char *refname, const git_oid *a,'
'const git_oid *b, void *data)')
def _update_tips_cb(refname, a, b, data):
self = ffi.from_handle(data)
if not hasattr(self, 'update_tips') or not self.update_tips:
return 0
try:
s = maybe_string(refname)
a = Oid(raw=bytes(ffi.buffer(a)[:]))
b = Oid(raw=bytes(ffi.buffer(b)[:]))
self.update_tips(s, a, b)
except Exception as e:
self._stored_exception = e
return C.GIT_EUSER
return 0
@ffi.callback("int (*push_update_reference)(const char *ref, const char *msg, void *data)")
def _push_update_reference_cb(ref, msg, data):
self = ffi.from_handle(data)
if not hasattr(self, 'push_update_reference') or not self.push_update_reference:
return 0
try:
refname = ffi.string(ref)
message = maybe_string(msg)
self.push_update_reference(refname, message)
except Exception as e:
self._stored_exception = e
return C.GIT_EUSER
return 0
@ffi.callback('int (*credentials)(git_cred **cred, const char *url,'
'const char *username_from_url, unsigned int allowed_types,'
'void *data)')
def _credentials_cb(cred_out, url, username, allowed, data):
self = ffi.from_handle(data)
if not hasattr(self, 'credentials') or not self.credentials:
return 0
try:
ccred = get_credentials(self.credentials, url, username, allowed)
cred_out[0] = ccred[0]
except Exception as e:
self._stored_exception = e
return C.GIT_EUSER
return 0
def get_credentials(fn, url, username, allowed):
"""Call fn and return the credentials object"""
@ -445,24 +351,23 @@ def get_credentials(fn, url, username, allowed):
creds = fn(url_str, username_str, allowed)
credential_type = getattr(creds, 'credential_type', None)
credential_tuple = getattr(creds, 'credential_tuple', None)
if not credential_type or not credential_tuple:
if not hasattr(creds, 'credential_type') \
or not hasattr(creds, 'credential_tuple'):
raise TypeError("credential does not implement interface")
cred_type = credential_type
cred_type = creds.credential_type
if not (allowed & cred_type):
raise TypeError("invalid credential type")
ccred = ffi.new('git_cred **')
if cred_type == C.GIT_CREDTYPE_USERPASS_PLAINTEXT:
name, passwd = credential_tuple
name, passwd = creds.credential_tuple
err = C.git_cred_userpass_plaintext_new(ccred, to_bytes(name),
to_bytes(passwd))
elif cred_type == C.GIT_CREDTYPE_SSH_KEY:
name, pubkey, privkey, passphrase = credential_tuple
name, pubkey, privkey, passphrase = creds.credential_tuple
if pubkey is None and privkey is None:
err = C.git_cred_ssh_key_from_agent(ccred, to_bytes(name))
else:

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright 2010-2017 The pygit2 contributors
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,
@ -32,21 +32,17 @@ from __future__ import absolute_import
from string import hexdigits
import sys, tarfile
from time import time
if sys.version_info[0] < 3:
from cStringIO import StringIO
else:
from io import BytesIO as StringIO
import six
# Import from pygit2
from _pygit2 import Repository as _Repository, init_file_backend
from _pygit2 import Repository as _Repository
from _pygit2 import Oid, GIT_OID_HEXSZ, GIT_OID_MINPREFIXLEN
from _pygit2 import GIT_CHECKOUT_SAFE, GIT_CHECKOUT_RECREATE_MISSING, GIT_DIFF_NORMAL
from _pygit2 import GIT_FILEMODE_LINK
from _pygit2 import GIT_BRANCH_LOCAL, GIT_BRANCH_REMOTE, GIT_BRANCH_ALL
from _pygit2 import Reference, Tree, Commit, Blob, Signature
from _pygit2 import Reference, Tree, Commit, Blob
from .config import Config
from .errors import check_error
@ -58,11 +54,21 @@ from .utils import to_bytes, is_string
from .submodule import Submodule
class BaseRepository(_Repository):
def __init__(self, backend, *args, **kwargs):
super(BaseRepository, self).__init__(backend, *args, **kwargs)
class Repository(_Repository):
def __init__(self, *args, **kwargs):
super(Repository, self).__init__(*args, **kwargs)
self._common_init()
@classmethod
def _from_c(cls, ptr, owned):
cptr = ffi.new('git_repository **')
cptr[0] = ptr
repo = cls.__new__(cls)
super(cls, repo)._from_c(bytes(ffi.buffer(cptr)[:]), owned)
repo._common_init()
return repo
def _common_init(self):
self.remotes = RemoteCollection(self)
@ -269,6 +275,11 @@ class BaseRepository(_Repository):
oid = reference.resolve().target
treeish = self[oid]
self.checkout_tree(treeish, **kwargs)
head = self.lookup_reference('HEAD')
if head.type == C.GIT_REF_SYMBOLIC:
from_ = self.head.shorthand
else:
from_ = head.target.hex
self.set_head(refname)
@ -307,23 +318,8 @@ class BaseRepository(_Repository):
Keyword arguments:
a
None, a str (that refers to an Object, see revparse_single()) or a
Reference object.
If None, b must be None, too. In this case the working directory is
compared with the index. Otherwise the referred object is compared to
'b'.
b
None, a str (that refers to an Object, see revparse_single()) or a
Reference object.
If None, the working directory is compared to 'a'. (except
'cached' is True, in which case the index is compared to 'a').
Otherwise the referred object is compared to 'a'
cached
if 'b' is None, by default the working directory is compared to 'a'.
If 'cached' is set to True, the index/staging area is used for comparing.
use staged changes instead of workdir
flag
a GIT_DIFF_* constant
@ -485,7 +481,6 @@ class BaseRepository(_Repository):
@staticmethod
def _merge_options(favor):
"""Return a 'git_merge_opts *'"""
def favor_to_enum(favor):
if favor == 'normal':
return C.GIT_MERGE_FILE_FAVOR_NORMAL
@ -532,13 +527,13 @@ class BaseRepository(_Repository):
theirs._to_c() if theirs is not None else (ffi.NULL, ffi.NULL))
err = C.git_merge_file_from_index(
cmergeresult, self._repo,
cancestor, cours, ctheirs,
ffi.NULL);
cmergeresult, self._repo,
cancestor, cours, ctheirs,
ffi.NULL);
check_error(err)
ret = ffi.string(cmergeresult.ptr,
cmergeresult.len).decode('utf-8')
cmergeresult.len).decode('utf-8')
C.git_merge_file_result_free(cmergeresult)
return ret
@ -642,196 +637,6 @@ class BaseRepository(_Repository):
return Index.from_c(self, cindex)
#
# Describe
#
def describe(self, committish=None, max_candidates_tags=None,
describe_strategy=None, pattern=None,
only_follow_first_parent=None,
show_commit_oid_as_fallback=None, abbreviated_size=None,
always_use_long_format=None, dirty_suffix=None):
"""Describe a commit-ish or the current working tree.
:param committish: Commit-ish object or object name to describe, or
`None` to describe the current working tree.
:type committish: `str`, :class:`~.Reference`, or :class:`~.Commit`
:param int max_candidates_tags: The number of candidate tags to
consider. Increasing above 10 will take slightly longer but may
produce a more accurate result. A value of 0 will cause only exact
matches to be output.
:param int describe_strategy: A GIT_DESCRIBE_* constant.
:param str pattern: Only consider tags matching the given `glob(7)`
pattern, excluding the "refs/tags/" prefix.
:param bool only_follow_first_parent: Follow only the first parent
commit upon seeing a merge commit.
:param bool show_commit_oid_as_fallback: Show uniquely abbreviated
commit object as fallback.
:param int abbreviated_size: The minimum number of hexadecimal digits
to show for abbreviated object names. A value of 0 will suppress
long format, only showing the closest tag.
:param bool always_use_long_format: Always output the long format (the
nearest tag, the number of commits, and the abbrevated commit name)
even when the committish matches a tag.
:param str dirty_suffix: A string to append if the working tree is
dirty.
:returns: The description.
:rtype: `str`
Example::
repo.describe(pattern='public/*', dirty_suffix='-dirty')
"""
options = ffi.new('git_describe_options *')
C.git_describe_init_options(options, C.GIT_DESCRIBE_OPTIONS_VERSION)
if max_candidates_tags is not None:
options.max_candidates_tags = max_candidates_tags
if describe_strategy is not None:
options.describe_strategy = describe_strategy
if pattern:
# The returned pointer object has ownership on the allocated
# memory. Make sure it is kept alive until git_describe_commit() or
# git_describe_workdir() are called below.
pattern_char = ffi.new('char[]', to_bytes(pattern))
options.pattern = pattern_char
if only_follow_first_parent is not None:
options.only_follow_first_parent = only_follow_first_parent
if show_commit_oid_as_fallback is not None:
options.show_commit_oid_as_fallback = show_commit_oid_as_fallback
result = ffi.new('git_describe_result **')
if committish:
if is_string(committish):
committish = self.revparse_single(committish)
commit = committish.peel(Commit)
cptr = ffi.new('git_object **')
ffi.buffer(cptr)[:] = commit._pointer[:]
err = C.git_describe_commit(result, cptr[0], options)
else:
err = C.git_describe_workdir(result, self._repo, options)
check_error(err)
try:
format_options = ffi.new('git_describe_format_options *')
C.git_describe_init_format_options(format_options, C.GIT_DESCRIBE_FORMAT_OPTIONS_VERSION)
if abbreviated_size is not None:
format_options.abbreviated_size = abbreviated_size
if always_use_long_format is not None:
format_options.always_use_long_format = always_use_long_format
dirty_ptr = None
if dirty_suffix:
dirty_ptr = ffi.new('char[]', to_bytes(dirty_suffix))
format_options.dirty_suffix = dirty_ptr
buf = ffi.new('git_buf *', (ffi.NULL, 0))
err = C.git_describe_format(buf, result[0], format_options)
check_error(err)
try:
return ffi.string(buf.ptr).decode('utf-8')
finally:
C.git_buf_free(buf)
finally:
C.git_describe_result_free(result[0])
#
# Stash
#
def stash(self, stasher, message=None, keep_index=False,
include_untracked=False, include_ignored=False):
"""Save changes to the working directory to the stash.
:param Signature stasher: The identity of the person doing the stashing.
:param str message: An optional description of stashed state.
:param bool keep_index: Leave changes already added to the index
in the working directory.
:param bool include_untracked: Also stash untracked files.
:param bool include_ignored: Also stash ignored files.
:returns: The Oid of the stash merge commit.
:rtype: Oid
Example::
>>> repo = pygit2.Repsitory('.')
>>> repo.stash(repo.default_signature(), 'WIP: stashing')
"""
if message is not None:
stash_msg = ffi.new('char[]', to_bytes(message)) if message else ffi.NULL
else:
stash_msg = ffi.NULL
flags = 0
flags |= keep_index * C.GIT_STASH_KEEP_INDEX
flags |= include_untracked * C.GIT_STASH_INCLUDE_UNTRACKED
flags |= include_ignored * C.GIT_STASH_INCLUDE_IGNORED
stasher_cptr = ffi.new('git_signature **')
ffi.buffer(stasher_cptr)[:] = stasher._pointer[:]
coid = ffi.new('git_oid *')
err = C.git_stash_save(coid, self._repo, stasher_cptr[0], stash_msg, flags)
check_error(err)
return Oid(raw=bytes(ffi.buffer(coid)[:]))
@staticmethod
def _stash_args_to_options(reinstate_index=False, **kwargs):
stash_opts = ffi.new('git_stash_apply_options *')
check_error(C.git_stash_apply_init_options(stash_opts, 1))
flags = reinstate_index * C.GIT_STASH_APPLY_REINSTATE_INDEX
stash_opts.flags = flags
copts, refs = Repository._checkout_args_to_options(**kwargs)
stash_opts.checkout_options = copts[0]
return stash_opts
def stash_apply(self, index=0, **kwargs):
"""Apply a stashed state in the stash list to the working directory.
:param int index: The position within the stash list of the stash to apply.
0 is the most recent stash.
:param bool reinstate_index: Try to reinstate stashed changes to the index.
The checkout options may be customized using the same arguments taken by
Repository.checkout().
Example::
>>> repo = pygit2.Repsitory('.')
>>> repo.stash(repo.default_signature(), 'WIP: stashing')
>>> repo.stash_apply(strategy=GIT_CHECKOUT_ALLOW_CONFLICTS)
"""
stash_opts = Repository._stash_args_to_options(**kwargs)
check_error(C.git_stash_apply(self._repo, index, stash_opts))
def stash_drop(self, index=0):
"""Remove a stashed state from the stash list.
:param int index: The position within the stash list of the stash to remove.
0 is the most recent stash.
"""
check_error(C.git_stash_drop(self._repo, index))
def stash_pop(self, index=0, **kwargs):
"""Apply a stashed state and remove it from the stash list.
For arguments, see Repository.stash_apply().
"""
stash_opts = Repository._stash_args_to_options(**kwargs)
check_error(C.git_stash_pop(self._repo, index, stash_opts))
#
# Utility for writing a tree into an archive
#
@ -860,7 +665,7 @@ class BaseRepository(_Repository):
>>> import tarfile, pygit2
>>>> with tarfile.open('foo.tar', 'w') as archive:
>>>> repo = pygit2.Repsitory('.')
>>>> repo.write_archive(repo.head.target, archive)
>>>> repo.write_archive(archive, repo.head.target)
"""
# Try to get a tree form whatever we got
@ -892,11 +697,11 @@ class BaseRepository(_Repository):
info = tarfile.TarInfo(prefix + entry.path)
info.size = len(content)
info.mtime = timestamp
info.uname = info.gname = 'root' # just because git does this
info.uname = info.gname = 'root' # just because git does this
if entry.mode == GIT_FILEMODE_LINK:
info.type = tarfile.SYMTYPE
info.linkname = content.decode("utf-8")
info.mode = 0o777 # symlinks get placeholder
info.type = archive.SYMTYPE
info.linkname = content
info.mode = 0o777 # symlinks get placeholder
info.size = 0
archive.addfile(info)
else:
@ -1000,130 +805,3 @@ class BaseRepository(_Repository):
err = C.git_repository_set_ident(self._repo, to_bytes(name), to_bytes(email))
check_error(err)
def revert_commit(self, revert_commit, our_commit, mainline=0):
"""Reverts the given Commit against the given "our" Commit,
producing an Index that reflects the result of the revert.
Arguments
revert_commit
The Commit to revert
our_commit
The Commit to revert against (eg, HEAD)
mainline
The parent of the revert Commit, if it is a merge (i.e. 1, 2)
Returns an Index with the result of the revert.
"""
cindex = ffi.new('git_index **')
revert_commit_ptr = ffi.new('git_commit **')
our_commit_ptr = ffi.new('git_commit **')
ffi.buffer(revert_commit_ptr)[:] = revert_commit._pointer[:]
ffi.buffer(our_commit_ptr)[:] = our_commit._pointer[:]
opts = ffi.new('git_merge_options *')
err = C.git_merge_init_options(opts, C.GIT_MERGE_OPTIONS_VERSION)
check_error(err)
err = C.git_revert_commit(
cindex, self._repo, revert_commit_ptr[0], our_commit_ptr[0], mainline, opts
)
check_error(err)
return Index.from_c(self, cindex)
class Branches(object):
def __init__(self, repository, flag=GIT_BRANCH_ALL):
self._repository = repository
self._flag = flag
if flag == GIT_BRANCH_ALL:
self.local = Branches(repository, flag=GIT_BRANCH_LOCAL)
self.remote = Branches(repository, flag=GIT_BRANCH_REMOTE)
def __getitem__(self, name):
branch = None
if self._flag & GIT_BRANCH_LOCAL:
branch = self._repository.lookup_branch(name, GIT_BRANCH_LOCAL)
if branch is None and self._flag & GIT_BRANCH_REMOTE:
branch = self._repository.lookup_branch(name, GIT_BRANCH_REMOTE)
if branch is None:
raise KeyError('Branch not found: {}'.format(name))
return branch
def get(self, key):
try:
return self[key]
except KeyError:
return None
def __iter__(self):
for branch_name in self._repository.listall_branches(self._flag):
yield branch_name
def create(self, name, commit, force=False):
return self._repository.create_branch(name, commit, force)
def delete(self, name):
self[name].delete()
def __contains__(self, name):
return self.get(name) is not None
class References(object):
def __init__(self, repository):
self._repository = repository
def __getitem__(self, name):
return self._repository.lookup_reference(name)
def get(self, key):
try:
return self[key]
except KeyError:
return None
def __iter__(self):
for ref_name in self._repository.listall_references():
yield ref_name
def create(self, name, target, force=False):
return self._repository.create_reference(name, target, force)
def delete(self, name):
self[name].delete()
def __contains__(self, name):
return self.get(name) is not None
@property
def objects(self):
return self._repository.listall_reference_objects()
class Repository(BaseRepository):
def __init__(self, path, *args, **kwargs):
if not isinstance(path, six.string_types):
path = path.decode('utf-8')
path_backend = init_file_backend(path)
super(Repository, self).__init__(backend=path_backend, *args, **kwargs)
self.branches = Branches(self)
self.references = References(self)
@classmethod
def _from_c(cls, ptr, owned):
cptr = ffi.new('git_repository **')
cptr[0] = ptr
repo = cls.__new__(cls)
super(cls, repo)._from_c(bytes(ffi.buffer(cptr)[:]), owned)
repo._common_init()
return repo

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright 2010-2017 The pygit2 contributors
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,
@ -28,11 +28,6 @@
from _pygit2 import option
from _pygit2 import GIT_OPT_GET_SEARCH_PATH, GIT_OPT_SET_SEARCH_PATH
from _pygit2 import GIT_OPT_GET_MWINDOW_SIZE, GIT_OPT_SET_MWINDOW_SIZE
from _pygit2 import GIT_OPT_GET_MWINDOW_MAPPED_LIMIT, GIT_OPT_SET_MWINDOW_MAPPED_LIMIT
from _pygit2 import GIT_OPT_SET_CACHE_OBJECT_LIMIT
from _pygit2 import GIT_OPT_GET_CACHED_MEMORY
from _pygit2 import GIT_OPT_ENABLE_CACHING
from _pygit2 import GIT_OPT_SET_CACHE_MAX_SIZE
class SearchPathList(object):
@ -69,36 +64,3 @@ class Settings(object):
@mwindow_size.setter
def mwindow_size(self, value):
option(GIT_OPT_SET_MWINDOW_SIZE, value)
@property
def mwindow_mapped_limit(self):
"""Mwindow mapped limit"""
return option(GIT_OPT_GET_MWINDOW_MAPPED_LIMIT)
@mwindow_mapped_limit.setter
def mwindow_mapped_limit(self, value):
"""Mwindow mapped limit"""
return option(GIT_OPT_SET_MWINDOW_MAPPED_LIMIT, value)
@property
def cached_memory(self):
"""Maximum mmap window size"""
return option(GIT_OPT_GET_CACHED_MEMORY)
def enable_caching(self, value=True):
return option(GIT_OPT_ENABLE_CACHING, value)
def cache_max_size(self, value):
return option(GIT_OPT_SET_CACHE_MAX_SIZE, value)
def cache_object_limit(self, object_type, value):
"""Set the maximum data size for the given type of object to be
considered eligible for caching in memory.
Setting to value to zero means that that type of object will not
be cached. Defaults to 0 for GIT_OBJ_BLOB (i.e. won't cache
blobs) and 4k for GIT_OBJ_COMMIT, GIT_OBJ_TREE, and GIT_OBJ_TAG.
"""
return option(GIT_OPT_SET_CACHE_OBJECT_LIMIT, object_type, value)

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright 2010-2017 The pygit2 contributors
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright 2010-2017 The pygit2 contributors
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,

129
setup.py

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# coding: UTF-8
#
# Copyright 2010-2017 The pygit2 contributors
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,
@ -45,26 +45,22 @@ from subprocess import Popen, PIPE
import sys
import unittest
# Get cffi major version
try:
import cffi
except ImportError:
cffi_major_version = None
else:
cffi_major_version = cffi.__version_info__[0]
# Import stuff from pygit2/_utils.py without loading the whole pygit2 package
sys.path.insert(0, 'pygit2')
from _build import __version__, get_libgit2_paths
if cffi_major_version == 0:
from _run import ffi, preamble, C_KEYWORDS
ffi.verify(preamble, **C_KEYWORDS)
from _utils import __version__, get_libgit2_paths, get_ffi
del sys.path[0]
# Python 2 support
# See https://github.com/libgit2/pygit2/pull/180 for a discussion about this.
if sys.version_info[0] == 2:
u = lambda s: unicode(s, 'utf-8')
else:
u = str
libgit2_bin, libgit2_include, libgit2_lib = get_libgit2_paths()
pygit2_exts = [os.path.join('src', name) for name in sorted(listdir('src'))
pygit2_exts = [os.path.join('src', name) for name in listdir('src')
if name.endswith('.c')]
@ -99,43 +95,19 @@ class TestCommand(Command):
unittest.main(None, defaultTest='test.test_suite', argv=test_argv)
class sdist_files_from_git(sdist):
def get_file_list(self):
popen = Popen(['git', 'ls-files'], stdout=PIPE, stderr=PIPE,
universal_newlines=True)
stdoutdata, stderrdata = popen.communicate()
if popen.returncode != 0:
print(stderrdata)
sys.exit()
for line in stdoutdata.splitlines():
# Skip hidden files at the root
if line[0] == '.':
continue
self.filelist.append(line)
# Ok
self.filelist.sort()
self.filelist.remove_duplicates()
self.write_manifest()
class CFFIBuild(build):
"""Hack to combat the chicken and egg problem that we need cffi
to add cffi as an extension.
"""
def finalize_options(self):
ffi, C = get_ffi()
self.distribution.ext_modules.append(ffi.verifier.get_extension())
build.finalize_options(self)
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"Topic :: Software Development :: Version Control"]
class BuildWithDLLs(CFFIBuild):
with codecs.open('README.rst', 'r', 'utf-8') as readme:
long_description = readme.read()
cmdclass = {
'test': TestCommand,
'sdist': sdist_files_from_git,
}
# On Windows, we install the git2.dll too.
class BuildWithDLLs(build):
# On Windows, we install the git2.dll too.
def _get_dlls(self):
# return a list of (FQ-in-name, relative-out-name) tuples.
ret = []
@ -161,27 +133,45 @@ class BuildWithDLLs(build):
def run(self):
build.run(self)
# On Windows we package up the dlls with the plugin.
for s, d in self._get_dlls():
self.copy_file(s, d)
# On Windows we package up the dlls with the plugin.
if os.name == 'nt':
cmdclass['build'] = BuildWithDLLs
extra_args = {
'ext_modules': [
Extension('_pygit2', pygit2_exts, libraries=['git2'],
include_dirs=[libgit2_include],
library_dirs=[libgit2_lib]),
# FFI is added in the build step
],
}
class sdist_files_from_git(sdist):
def get_file_list(self):
popen = Popen(['git', 'ls-files'], stdout=PIPE, stderr=PIPE)
stdoutdata, stderrdata = popen.communicate()
if popen.returncode != 0:
print(stderrdata)
sys.exit()
if cffi_major_version == 0:
extra_args['ext_modules'].append(ffi.verifier.get_extension())
else:
extra_args['cffi_modules'] = ['pygit2/_run.py:ffi']
for line in stdoutdata.splitlines():
# Skip hidden files at the root
if line[0] == '.':
continue
self.filelist.append(line)
# Ok
self.filelist.sort()
self.filelist.remove_duplicates()
self.write_manifest()
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"Topic :: Software Development :: Version Control"]
with codecs.open('README.rst', 'r', 'utf-8') as readme:
long_description = readme.read()
cmdclass = {
'build': BuildWithDLLs if os.name == 'nt' else CFFIBuild,
'test': TestCommand,
'sdist': sdist_files_from_git,
}
setup(name='pygit2',
description='Python bindings for libgit2.',
@ -190,13 +180,18 @@ setup(name='pygit2',
url='http://github.com/libgit2/pygit2',
classifiers=classifiers,
license='GPLv2 with linking exception',
maintainer=u'J. David Ibáñez',
maintainer=u('J. David Ibáñez'),
maintainer_email='jdavid.ibp@gmail.com',
long_description=long_description,
packages=['pygit2'],
package_data={'pygit2': ['decl.h']},
setup_requires=['cffi'],
install_requires=['cffi', 'six'],
install_requires=['cffi'],
zip_safe=False,
cmdclass=cmdclass,
**extra_args)
ext_modules=[
Extension('_pygit2', pygit2_exts, libraries=['git2'],
include_dirs=[libgit2_include],
library_dirs=[libgit2_lib]),
# FFI is added in the build step
],
cmdclass=cmdclass)

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,
@ -133,7 +133,7 @@ PyDoc_STRVAR(Blob_size__doc__, "Size.");
PyObject *
Blob_size__get__(Blob *self)
{
return PyInt_FromLongLong(git_blob_rawsize(self->blob));
return PyLong_FromLongLong(git_blob_rawsize(self->blob));
}

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,
@ -81,28 +81,6 @@ Branch_is_head(Branch *self)
return Error_set(err);
}
PyDoc_STRVAR(Branch_is_checked_out__doc__,
"is_checked_out()\n"
"\n"
"True if branch is checked out by any repo connected to the current one, "
" False otherwise.");
PyObject *
Branch_is_checked_out(Branch *self)
{
int err;
CHECK_REFERENCE(self);
err = git_branch_is_checked_out(self->reference);
if (err == 1)
Py_RETURN_TRUE;
else if (err == 0)
Py_RETURN_FALSE;
else
return Error_set(err);
}
PyDoc_STRVAR(Branch_rename__doc__,
"rename(name, force=False)\n"
@ -256,7 +234,6 @@ Branch_upstream_name__get__(Branch *self)
PyMethodDef Branch_methods[] = {
METHOD(Branch, delete, METH_NOARGS),
METHOD(Branch, is_head, METH_NOARGS),
METHOD(Branch, is_checked_out, METH_NOARGS),
METHOD(Branch, rename, METH_VARARGS),
{NULL}
};

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,
@ -34,7 +34,6 @@
PyObject* Branch_delete(Branch *self, PyObject *args);
PyObject* Branch_is_head(Branch *self);
PyObject* Branch_is_checked_out(Branch *self);
PyObject* Branch_move(Branch *self, PyObject *args);
PyObject* wrap_branch(git_reference *c_reference, Repository *repo);

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,
@ -35,7 +35,6 @@
#include "oid.h"
extern PyTypeObject TreeType;
extern PyObject *GitError;
PyDoc_STRVAR(Commit_message_encoding__doc__, "Message encoding.");
@ -80,7 +79,7 @@ PyDoc_STRVAR(Commit_commit_time__doc__, "Commit time.");
PyObject *
Commit_commit_time__get__(Commit *commit)
{
return PyInt_FromLongLong(git_commit_time(commit->commit));
return PyLong_FromLongLong(git_commit_time(commit->commit));
}
@ -89,7 +88,7 @@ PyDoc_STRVAR(Commit_commit_time_offset__doc__, "Commit time offset.");
PyObject *
Commit_commit_time_offset__get__(Commit *commit)
{
return PyInt_FromLong(git_commit_time_offset(commit->commit));
return PyLong_FromLong(git_commit_time_offset(commit->commit));
}
@ -132,11 +131,8 @@ Commit_tree__get__(Commit *commit)
int err;
err = git_commit_tree(&tree, commit->commit);
if (err == GIT_ENOTFOUND) {
char tree_id[GIT_OID_HEXSZ + 1] = { 0 };
git_oid_fmt(tree_id, git_commit_tree_id(commit->commit));
return PyErr_Format(GitError, "Unable to read tree %s", tree_id);
}
if (err == GIT_ENOTFOUND)
Py_RETURN_NONE;
if (err < 0)
return Error_set(err);

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,
@ -482,8 +482,7 @@ Diff_len(Diff *self)
return (Py_ssize_t)git_diff_num_deltas(self->diff);
}
PyDoc_STRVAR(Diff_patch__doc__,
"Patch diff string. Can be None in some cases, such as empty commits.");
PyDoc_STRVAR(Diff_patch__doc__, "Patch diff string.");
PyObject *
Diff_patch__get__(Diff *self)
@ -587,7 +586,7 @@ PyDoc_STRVAR(DiffStats_insertions__doc__, "Total number of insertions");
PyObject *
DiffStats_insertions__get__(DiffStats *self)
{
return PyInt_FromSize_t(git_diff_stats_insertions(self->stats));
return PyLong_FromSize_t(git_diff_stats_insertions(self->stats));
}
PyDoc_STRVAR(DiffStats_deletions__doc__, "Total number of deletions");
@ -595,7 +594,7 @@ PyDoc_STRVAR(DiffStats_deletions__doc__, "Total number of deletions");
PyObject *
DiffStats_deletions__get__(DiffStats *self)
{
return PyInt_FromSize_t(git_diff_stats_deletions(self->stats));
return PyLong_FromSize_t(git_diff_stats_deletions(self->stats));
}
PyDoc_STRVAR(DiffStats_files_changed__doc__, "Total number of files changed");
@ -603,7 +602,7 @@ PyDoc_STRVAR(DiffStats_files_changed__doc__, "Total number of files changed");
PyObject *
DiffStats_files_changed__get__(DiffStats *self)
{
return PyInt_FromSize_t(git_diff_stats_files_changed(self->stats));
return PyLong_FromSize_t(git_diff_stats_files_changed(self->stats));
}
PyDoc_STRVAR(DiffStats_format__doc__,
@ -805,10 +804,10 @@ Diff_getitem(Diff *self, PyObject *value)
{
size_t i;
if (!PyInt_Check(value))
return NULL; /* FIXME Raise error */
if (!PyLong_Check(value))
return NULL;
i = PyInt_AsSize_t(value);
i = PyLong_AsUnsignedLong(value);
return diff_get_patch_byindex(self->diff, i);
}

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,
@ -126,10 +126,3 @@ Error_set_oid(int err, const git_oid *oid, size_t len)
hex[len] = '\0';
return Error_set_str(err, hex);
}
PyObject *
Error_type_error(const char *format, PyObject *value)
{
PyErr_Format(PyExc_TypeError, format, Py_TYPE(value)->tp_name);
return NULL;
}

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,
@ -37,6 +37,5 @@ PyObject* Error_set(int err);
PyObject* Error_set_exc(PyObject* exception);
PyObject* Error_set_str(int err, const char *str);
PyObject* Error_set_oid(int err, const git_oid *oid, size_t len);
PyObject* Error_type_error(const char *format, PyObject *value);
#endif

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,
@ -97,7 +97,7 @@ PyDoc_STRVAR(Object_type__doc__,
PyObject *
Object_type__get__(Object *self)
{
return PyInt_FromLong(git_object_type(self->obj));
return PyLong_FromLong(git_object_type(self->obj));
}
PyDoc_STRVAR(Object__pointer__doc__, "Get the object's pointer. For internal use only.");
@ -143,15 +143,14 @@ PyDoc_STRVAR(Object_peel__doc__,
PyObject *
Object_peel(Object *self, PyObject *py_type)
{
int err;
git_otype otype;
int type = -1, err;
git_object *peeled;
otype = py_object_to_otype(py_type);
if (otype == GIT_OBJ_BAD)
type = py_object_to_object_type(py_type);
if (type == -1)
return NULL;
err = git_object_peel(&peeled, self->obj, otype);
err = git_object_peel(&peeled, self->obj, (git_otype)type);
if (err < 0)
return Error_set(err);

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,
@ -209,10 +209,8 @@ Oid_init(Oid *self, PyObject *args, PyObject *kw)
Py_hash_t
Oid_hash(PyObject *oid)
{
PyObject *py_oid = git_oid_to_py_str(&((Oid *)oid)->oid);
Py_hash_t ret = PyObject_Hash(py_oid);
Py_DECREF(py_oid);
return ret;
/* TODO Randomize (use _Py_HashSecret) to avoid collission DoS attacks? */
return *(Py_hash_t*) ((Oid*)oid)->oid.id;
}

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,
@ -65,11 +65,10 @@ option(PyObject *self, PyObject *args)
if (!py_option)
return NULL;
if (!PyInt_Check(py_option))
return Error_type_error(
"option should be an integer, got %.200s", py_option);
if (!PyLong_Check(py_option))
goto on_non_integer;
option = PyInt_AsLong(py_option);
option = PyLong_AsLong(py_option);
switch (option) {
case GIT_OPT_GET_SEARCH_PATH:
@ -80,11 +79,11 @@ option(PyObject *self, PyObject *args)
if (!py_level)
return NULL;
if (!PyInt_Check(py_level))
return Error_type_error(
"level should be an integer, got %.200s", py_level);
if (!PyLong_Check(py_level))
goto on_non_integer;
return get_search_path(PyInt_AsLong(py_level));
return get_search_path(PyLong_AsLong(py_level));
break;
}
case GIT_OPT_SET_SEARCH_PATH:
@ -101,22 +100,23 @@ option(PyObject *self, PyObject *args)
if (!py_path)
return NULL;
if (!PyInt_Check(py_level))
return Error_type_error(
"level should be an integer, got %.200s", py_level);
if (!PyLong_Check(py_level))
goto on_non_integer;
path = py_str_borrow_c_str(&tpath, py_path, NULL);
if (!path)
return NULL;
err = git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, PyInt_AsLong(py_level), path);
err = git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, PyLong_AsLong(py_level), path);
Py_DECREF(tpath);
if (err < 0)
return Error_set(err);
if (err < 0) {
Error_set(err);
return NULL;
}
Py_RETURN_NONE;
break;
}
case GIT_OPT_GET_MWINDOW_SIZE:
@ -124,10 +124,14 @@ option(PyObject *self, PyObject *args)
size_t size;
error = git_libgit2_opts(GIT_OPT_GET_MWINDOW_SIZE, &size);
if (error < 0)
return Error_set(error);
if (error < 0) {
Error_set(error);
return NULL;
}
return PyInt_FromSize_t(size);
return PyLong_FromSize_t(size);
break;
}
case GIT_OPT_SET_MWINDOW_SIZE:
@ -139,141 +143,25 @@ option(PyObject *self, PyObject *args)
if (!py_size)
return NULL;
if (!PyInt_Check(py_size))
return Error_type_error(
"size should be an integer, got %.200s", py_size);
if (!PyLong_Check(py_size))
goto on_non_integer;
size = PyInt_AsSize_t(py_size);
size = PyLong_AsSize_t(py_size);
error = git_libgit2_opts(GIT_OPT_SET_MWINDOW_SIZE, size);
if (error < 0)
return Error_set(error);
Py_RETURN_NONE;
}
case GIT_OPT_GET_MWINDOW_MAPPED_LIMIT:
{
size_t limit;
error = git_libgit2_opts(GIT_OPT_GET_MWINDOW_MAPPED_LIMIT, &limit);
if (error < 0)
return Error_set(error);
return PyInt_FromSize_t(limit);
}
case GIT_OPT_SET_MWINDOW_MAPPED_LIMIT:
{
size_t limit;
PyObject *py_limit;
py_limit = PyTuple_GetItem(args, 1);
if (!py_limit)
if (error < 0) {
Error_set(error);
return NULL;
if (PyInt_Check(py_limit)) {
limit = PyInt_AsSize_t(py_limit);
} else if (PyLong_Check(py_limit)) {
limit = PyLong_AsSize_t(py_limit);
} else {
return Error_type_error(
"limit should be an integer, got %.200s", py_limit);
}
error = git_libgit2_opts(GIT_OPT_SET_MWINDOW_MAPPED_LIMIT, limit);
if (error < 0)
return Error_set(error);
Py_RETURN_NONE;
break;
}
case GIT_OPT_SET_CACHE_OBJECT_LIMIT:
{
size_t limit;
int object_type;
PyObject *py_object_type, *py_limit;
py_object_type = PyTuple_GetItem(args, 1);
if (!py_object_type)
return NULL;
py_limit = PyTuple_GetItem(args, 2);
if (!py_limit)
return NULL;
if (!PyInt_Check(py_limit))
return Error_type_error(
"limit should be an integer, got %.200s", py_limit);
object_type = PyInt_AsLong(py_object_type);
limit = PyInt_AsSize_t(py_limit);
error = git_libgit2_opts(
GIT_OPT_SET_CACHE_OBJECT_LIMIT, object_type, limit);
if (error < 0)
return Error_set(error);
Py_RETURN_NONE;
}
case GIT_OPT_SET_CACHE_MAX_SIZE:
{
size_t max_size;
PyObject *py_max_size;
py_max_size = PyTuple_GetItem(args, 1);
if (!py_max_size)
return NULL;
if (!PyInt_Check(py_max_size))
return Error_type_error(
"max_size should be an integer, got %.200s", py_max_size);
max_size = PyInt_AsSize_t(py_max_size);
error = git_libgit2_opts(GIT_OPT_SET_CACHE_MAX_SIZE, max_size);
if (error < 0)
return Error_set(error);
Py_RETURN_NONE;
}
case GIT_OPT_ENABLE_CACHING:
{
int flag;
PyObject *py_flag;
py_flag = PyTuple_GetItem(args, 1);
if (!PyInt_Check(py_flag))
return Error_type_error(
"flag should be an integer, got %.200s", py_flag);
flag = PyInt_AsSize_t(py_flag);
error = git_libgit2_opts(GIT_OPT_ENABLE_CACHING, flag);
if (error < 0)
return Error_set(error);
Py_RETURN_NONE;
}
case GIT_OPT_GET_CACHED_MEMORY:
{
size_t current;
size_t allowed;
PyObject* tup = PyTuple_New(2);
error = git_libgit2_opts(GIT_OPT_GET_CACHED_MEMORY, &current, &allowed);
if (error < 0)
return Error_set(error);
PyTuple_SetItem(tup, 0, PyInt_FromLong(current));
PyTuple_SetItem(tup, 1, PyInt_FromLong(allowed));
return tup;
}
}
PyErr_SetString(PyExc_ValueError, "unknown/unsupported option value");
return NULL;
on_non_integer:
PyErr_SetString(PyExc_TypeError, "option is not an integer");
return NULL;
}

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,
@ -144,44 +144,7 @@ hash(PyObject *self, PyObject *args)
}
PyDoc_STRVAR(init_file_backend__doc__,
"init_file_backend(path) -> object\n"
"\n"
"open repo backend given path.");
PyObject *
init_file_backend(PyObject *self, PyObject *args)
{
const char* path = NULL;
int err = GIT_OK;
git_repository *repository = NULL;
if (!PyArg_ParseTuple(args, "s", &path)) {
return NULL;
}
err = git_repository_open(&repository, path);
if (err < 0) {
Error_set_str(err, path);
goto cleanup;
}
return PyCapsule_New(repository, "backend", NULL);
cleanup:
if (repository) {
git_repository_free(repository);
}
if (err == GIT_ENOTFOUND) {
PyErr_Format(GitError, "Repository not found at %s", path);
}
return NULL;
}
PyMethodDef module_methods[] = {
{"init_file_backend", init_file_backend, METH_VARARGS,
init_file_backend__doc__},
{"discover_repository", discover_repository, METH_VARARGS,
discover_repository__doc__},
{"hashfile", hashfile, METH_VARARGS, hashfile__doc__},
@ -207,12 +170,6 @@ moduleinit(PyObject* m)
ADD_CONSTANT_INT(m, GIT_OPT_SET_SEARCH_PATH);
ADD_CONSTANT_INT(m, GIT_OPT_GET_MWINDOW_SIZE);
ADD_CONSTANT_INT(m, GIT_OPT_SET_MWINDOW_SIZE);
ADD_CONSTANT_INT(m, GIT_OPT_GET_MWINDOW_MAPPED_LIMIT);
ADD_CONSTANT_INT(m, GIT_OPT_SET_MWINDOW_MAPPED_LIMIT);
ADD_CONSTANT_INT(m, GIT_OPT_SET_CACHE_OBJECT_LIMIT);
ADD_CONSTANT_INT(m, GIT_OPT_GET_CACHED_MEMORY);
ADD_CONSTANT_INT(m, GIT_OPT_ENABLE_CACHING);
ADD_CONSTANT_INT(m, GIT_OPT_SET_CACHE_MAX_SIZE);
/* Errors */
GitError = PyErr_NewException("_pygit2.GitError", NULL, NULL);
@ -303,7 +260,6 @@ moduleinit(PyObject* m)
ADD_TYPE(m, Branch)
ADD_CONSTANT_INT(m, GIT_BRANCH_LOCAL)
ADD_CONSTANT_INT(m, GIT_BRANCH_REMOTE)
ADD_CONSTANT_INT(m, GIT_BRANCH_ALL)
/*
* Index & Working copy
@ -367,7 +323,6 @@ moduleinit(PyObject* m)
ADD_CONSTANT_INT(m, GIT_DIFF_IGNORE_CASE)
ADD_CONSTANT_INT(m, GIT_DIFF_SHOW_UNTRACKED_CONTENT)
ADD_CONSTANT_INT(m, GIT_DIFF_SKIP_BINARY_CHECK)
ADD_CONSTANT_INT(m, GIT_DIFF_SHOW_BINARY)
ADD_CONSTANT_INT(m, GIT_DIFF_INCLUDE_TYPECHANGE)
ADD_CONSTANT_INT(m, GIT_DIFF_INCLUDE_TYPECHANGE_TREES)
ADD_CONSTANT_INT(m, GIT_DIFF_RECURSE_IGNORED_DIRS)
@ -425,19 +380,6 @@ moduleinit(PyObject* m)
ADD_CONSTANT_INT(m, GIT_MERGE_ANALYSIS_FASTFORWARD)
ADD_CONSTANT_INT(m, GIT_MERGE_ANALYSIS_UNBORN)
/* Describe */
ADD_CONSTANT_INT(m, GIT_DESCRIBE_DEFAULT);
ADD_CONSTANT_INT(m, GIT_DESCRIBE_TAGS);
ADD_CONSTANT_INT(m, GIT_DESCRIBE_ALL);
/* Stash */
ADD_CONSTANT_INT(m, GIT_STASH_DEFAULT);
ADD_CONSTANT_INT(m, GIT_STASH_KEEP_INDEX);
ADD_CONSTANT_INT(m, GIT_STASH_INCLUDE_UNTRACKED);
ADD_CONSTANT_INT(m, GIT_STASH_INCLUDE_IGNORED);
ADD_CONSTANT_INT(m, GIT_STASH_APPLY_DEFAULT);
ADD_CONSTANT_INT(m, GIT_STASH_APPLY_REINSTATE_INDEX);
/* Global initialization of libgit2 */
git_libgit2_init();

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,
@ -325,7 +325,7 @@ Reference_type__get__(Reference *self)
CHECK_REFERENCE(self);
c_type = git_reference_type(self->reference);
return PyInt_FromLong(c_type);
return PyLong_FromLong(c_type);
}
@ -379,8 +379,7 @@ PyDoc_STRVAR(Reference_peel__doc__,
PyObject *
Reference_peel(Reference *self, PyObject *args)
{
int err;
git_otype otype;
int err, type;
git_object *obj;
PyObject *py_type = Py_None;
@ -389,11 +388,11 @@ Reference_peel(Reference *self, PyObject *args)
if (!PyArg_ParseTuple(args, "|O", &py_type))
return NULL;
otype = py_object_to_otype(py_type);
if (otype == GIT_OBJ_BAD)
type = py_object_to_object_type(py_type);
if (type == -1)
return NULL;
err = git_reference_peel(&obj, self->reference, otype);
err = git_reference_peel(&obj, self->reference, type);
if (err < 0)
return Error_set(err);

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,
@ -88,7 +88,8 @@ wrap_repository(git_repository *c_repo)
int
Repository_init(Repository *self, PyObject *args, PyObject *kwds)
{
PyObject *backend;
char *path;
int err;
if (kwds && PyDict_Size(kwds) > 0) {
PyErr_SetString(PyExc_TypeError,
@ -96,16 +97,15 @@ Repository_init(Repository *self, PyObject *args, PyObject *kwds)
return -1;
}
if (!PyArg_ParseTuple(args, "O", &backend)) {
if (!PyArg_ParseTuple(args, "s", &path))
return -1;
err = git_repository_open(&self->repo, path);
if (err < 0) {
Error_set_str(err, path);
return -1;
}
self->repo = PyCapsule_GetPointer(backend, "backend");
if (self->repo == NULL) {
PyErr_SetString(PyExc_TypeError,
"Repository unable to unpack backend.");
return -1;
}
self->owned = 1;
self->config = NULL;
self->index = NULL;
@ -349,26 +349,6 @@ Repository_lookup_branch(Repository *self, PyObject *args)
}
PyDoc_STRVAR(Repository_path_is_ignored__doc__,
"Check if a path is ignored in the repository.");
PyObject *
Repository_path_is_ignored(Repository *self, PyObject *args)
{
int ignored;
char *path;
if (!PyArg_ParseTuple(args, "s", &path))
return NULL;
git_ignore_path_is_ignored(&ignored, self->repo, path);
if (ignored == 1)
Py_RETURN_TRUE;
Py_RETURN_FALSE;
}
PyDoc_STRVAR(Repository_revparse_single__doc__,
"revparse_single(revision) -> Object\n"
"\n"
@ -862,86 +842,6 @@ Repository_create_blob_fromdisk(Repository *self, PyObject *args)
}
#define BUFSIZE 4096
PyDoc_STRVAR(Repository_create_blob_fromiobase__doc__,
"create_blob_fromiobase(io.IOBase) -> Oid\n"
"\n"
"Create a new blob from an IOBase object.");
PyObject *
Repository_create_blob_fromiobase(Repository *self, PyObject *py_file)
{
git_writestream *stream;
git_oid oid;
PyObject *py_is_readable;
int is_readable;
int err;
py_is_readable = PyObject_CallMethod(py_file, "readable", NULL);
if (!py_is_readable) {
if (PyErr_ExceptionMatches(PyExc_AttributeError))
PyErr_SetObject(PyExc_TypeError, py_file);
return NULL;
}
is_readable = PyObject_IsTrue(py_is_readable);
Py_DECREF(py_is_readable);
if (!is_readable) {
Py_DECREF(py_file);
PyErr_SetString(PyExc_TypeError, "expected readable IO type");
return NULL;
}
err = git_blob_create_fromstream(&stream, self->repo, NULL);
if (err < 0)
return Error_set(err);
for (;;) {
PyObject *py_bytes;
char *bytes;
Py_ssize_t size;
py_bytes = PyObject_CallMethod(py_file, "read", "i", 4096);
if (!py_bytes)
return NULL;
if (py_bytes == Py_None) {
Py_DECREF(py_bytes);
goto cleanup;
}
if (PyBytes_AsStringAndSize(py_bytes, &bytes, &size)) {
Py_DECREF(py_bytes);
return NULL;
}
if (size == 0) {
Py_DECREF(py_bytes);
break;
}
err = stream->write(stream, bytes, size);
Py_DECREF(py_bytes);
if (err < 0)
goto cleanup;
}
cleanup:
if (err < 0) {
stream->free(stream);
return Error_set(err);
}
err = git_blob_create_fromstream_commit(&oid, stream);
if (err < 0)
return Error_set(err);
return git_oid_to_python(&oid);
}
PyDoc_STRVAR(Repository_create_commit__doc__,
"create_commit(reference_name, author, committer, message, tree, parents[, encoding]) -> Oid\n"
"\n"
@ -1141,56 +1041,6 @@ out:
}
PyDoc_STRVAR(Repository_listall_reference_objects__doc__,
"listall_reference_objects() -> [Reference, ...]\n"
"\n"
"Return a list with all the reference objects in the repository.");
PyObject *
Repository_listall_reference_objects(Repository *self, PyObject *args)
{
git_reference_iterator *iter;
git_reference *ref = NULL;
int err;
PyObject *list;
list = PyList_New(0);
if (list == NULL)
return NULL;
if ((err = git_reference_iterator_new(&iter, self->repo)) < 0)
return Error_set(err);
while ((err = git_reference_next(&ref, iter)) == 0) {
PyObject *py_ref = wrap_reference(ref, self);
if (py_ref == NULL)
goto error;
err = PyList_Append(list, py_ref);
Py_DECREF(py_ref);
if (err < 0)
goto error;
}
git_reference_iterator_free(iter);
if (err == GIT_ITEROVER)
err = 0;
if (err < 0) {
Py_CLEAR(list);
return Error_set(err);
}
return list;
error:
git_reference_iterator_free(iter);
Py_CLEAR(list);
return NULL;
}
PyDoc_STRVAR(Repository_listall_branches__doc__,
"listall_branches([flag]) -> [str, ...]\n"
"\n"
@ -1287,141 +1137,6 @@ Repository_listall_submodules(Repository *self, PyObject *args)
}
PyDoc_STRVAR(Repository_init_submodules__doc__,
"init_submodule(submodules=None, overwrite=False)\n"
"\n"
"Initialize all submodules in repository.\n"
"submodules: List of submodules to initialize. Default argument initializes all submodules.\n"
"overwrite: Flag indicating if initialization should overwrite submodule entries.\n");
static int foreach_sub_init_cb(git_submodule *submodule, const char *name, void *payload)
{
return git_submodule_init(submodule, *(int*)payload);
}
PyObject *
Repository_init_submodules(Repository* self, PyObject *args, PyObject *kwds)
{
PyObject *list = Py_None;
PyObject *oflag = Py_False;
char *kwlist[] = {"submodules", "overwrite", NULL};
int err, fflag;
PyObject *iter, *subpath, *next;
const char *c_subpath;
git_submodule *submodule;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO", kwlist, &list, &oflag))
return NULL;
fflag = PyObject_IsTrue(oflag);
if (fflag != 0 && fflag != 1)
fflag = 0;
//Init all submodules listed in repository
if (list == Py_None) {
err = git_submodule_foreach(self->repo, foreach_sub_init_cb, &fflag);
if (err != 0)
return Error_set(err);
Py_RETURN_NONE;
}
iter = PyObject_GetIter(list);
if (!iter)
return NULL;
while (1) {
next = PyIter_Next(iter);
if (!next)
break;
c_subpath = py_str_borrow_c_str(&subpath, next, NULL);
git_submodule_lookup(&submodule, self->repo, c_subpath);
Py_DECREF(subpath);
if (!submodule) {
PyErr_SetString(PyExc_KeyError,
"Submodule does not exist");
return NULL;
}
err = git_submodule_init(submodule, fflag);
if (err != 0) {
return Error_set(err);
}
}
Py_RETURN_NONE;
}
PyDoc_STRVAR(Repository_update_submodules__doc__,
"update_submodules(submodules=None, init=False)\n"
"\n"
"Updates the specified submodules, or all if None are specified\n"
"init: Flag indicating if submodules should be automatically initialized if necessary.\n");
static int foreach_sub_update_cb(git_submodule *submodule, const char *name, void *payload)
{
git_submodule_update_options opts = GIT_SUBMODULE_UPDATE_OPTIONS_INIT;
return git_submodule_update(submodule, *(int*)payload, &opts);
}
PyObject *
Repository_update_submodules(Repository *self, PyObject *args, PyObject *kwds)
{
PyObject *list = Py_None;
PyObject *py_init = Py_False;
PyObject *iter, *next, *subpath;
int init, err;
const char *c_subpath;
git_submodule *submodule;
git_submodule_update_options opts = GIT_SUBMODULE_UPDATE_OPTIONS_INIT;
char *kwlist[] = {"submodules", "init", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO", kwlist, &list, &py_init))
return NULL;
init = PyObject_IsTrue(py_init);
if (init != 0 && init != 1)
init = 0;
if (list == Py_None) {
err = git_submodule_foreach(self->repo, foreach_sub_update_cb, &init);
if (err != 0)
return Error_set(err);
Py_RETURN_NONE;
}
iter = PyObject_GetIter(list);
if (!iter)
return NULL;
while (1) {
next = PyIter_Next(iter);
if (!next)
break;
c_subpath = py_str_borrow_c_str(&subpath, next, NULL);
git_submodule_lookup(&submodule, self->repo, c_subpath);
Py_DECREF(subpath);
if (!submodule) {
PyErr_SetString(PyExc_KeyError,
"Submodule does not exist");
return NULL;
}
err = git_submodule_update(submodule, init, &opts);
if (err != 0) {
return Error_set(err);
}
}
Py_RETURN_NONE;
}
PyDoc_STRVAR(Repository_lookup_reference__doc__,
"lookup_reference(name) -> Reference\n"
"\n"
@ -1563,7 +1278,7 @@ Repository_status(Repository *self)
path = entry->head_to_index->old_file.path;
else
path = entry->index_to_workdir->old_file.path;
status = PyInt_FromLong((long) entry->status);
status = PyLong_FromLong((long) entry->status);
err = PyDict_SetItemString(dict, path, status);
Py_CLEAR(status);
@ -1605,7 +1320,7 @@ Repository_status_file(Repository *self, PyObject *value)
free(path);
return err_obj;
}
return PyInt_FromLong(status);
return PyLong_FromLong(status);
}
@ -1778,8 +1493,8 @@ PyDoc_STRVAR(Repository_reset__doc__,
"\n"
"Resets current head to the provided oid.\n"
"reset_type:\n"
"GIT_RESET_SOFT: resets head to point to oid, but does not modify working copy, and leaves the changes in the index.\n"
"GIT_RESET_MIXED: resets head to point to oid, but does not modify working copy. It empties the index too.\n"
"GIT_RESET_SOFT: resets head to point to oid, but does not modfy working copy, and leaves the changes in the index.\n"
"GIT_RESET_MIXED: resets head to point to oid, but does not modfy working copy. It empties the index too.\n"
"GIT_RESET_HARD: resets head to point to oid, and resets too the working copy and the content of the index.\n");
PyObject *
@ -1832,7 +1547,6 @@ PyMethodDef Repository_methods[] = {
METHOD(Repository, create_blob, METH_VARARGS),
METHOD(Repository, create_blob_fromworkdir, METH_VARARGS),
METHOD(Repository, create_blob_fromdisk, METH_VARARGS),
METHOD(Repository, create_blob_fromiobase, METH_O),
METHOD(Repository, create_commit, METH_VARARGS),
METHOD(Repository, create_tag, METH_VARARGS),
METHOD(Repository, TreeBuilder, METH_VARARGS),
@ -1846,10 +1560,7 @@ PyMethodDef Repository_methods[] = {
METHOD(Repository, create_reference_direct, METH_VARARGS),
METHOD(Repository, create_reference_symbolic, METH_VARARGS),
METHOD(Repository, listall_references, METH_NOARGS),
METHOD(Repository, listall_reference_objects, METH_NOARGS),
METHOD(Repository, listall_submodules, METH_NOARGS),
METHOD(Repository, init_submodules, METH_VARARGS | METH_KEYWORDS),
METHOD(Repository, update_submodules, METH_VARARGS | METH_KEYWORDS),
METHOD(Repository, lookup_reference, METH_O),
METHOD(Repository, revparse_single, METH_O),
METHOD(Repository, status, METH_NOARGS),
@ -1859,7 +1570,6 @@ PyMethodDef Repository_methods[] = {
METHOD(Repository, lookup_note, METH_VARARGS),
METHOD(Repository, git_object_lookup_prefix, METH_O),
METHOD(Repository, lookup_branch, METH_VARARGS),
METHOD(Repository, path_is_ignored, METH_VARARGS),
METHOD(Repository, listall_branches, METH_VARARGS),
METHOD(Repository, create_branch, METH_VARARGS),
METHOD(Repository, reset, METH_VARARGS),
@ -1884,7 +1594,7 @@ PyGetSetDef Repository_getseters[] = {
PyDoc_STRVAR(Repository__doc__,
"Repository(backend) -> Repository\n"
"Repository(path) -> Repository\n"
"\n"
"Git repository.");

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,
@ -58,8 +58,6 @@ PyObject* Repository_create_commit(Repository *self, PyObject *args);
PyObject* Repository_create_tag(Repository *self, PyObject *args);
PyObject* Repository_create_branch(Repository *self, PyObject *args);
PyObject* Repository_listall_references(Repository *self, PyObject *args);
PyObject* Repository_listall_reference_objects(Repository *self,
PyObject *args);
PyObject* Repository_listall_branches(Repository *self, PyObject *args);
PyObject* Repository_lookup_reference(Repository *self, PyObject *py_name);

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,
@ -38,7 +38,7 @@ Signature_init(Signature *self, PyObject *args, PyObject *kwds)
{
char *keywords[] = {"name", "email", "time", "offset", "encoding", NULL};
PyObject *py_name, *tname;
char *email, *encoding = "utf-8";
char *email, *encoding = "ascii";
const char *name;
long long time = -1;
int offset = 0;
@ -96,10 +96,10 @@ Signature_dealloc(Signature *self)
PyDoc_STRVAR(Signature__pointer__doc__, "Get the signature's pointer. For internal use only.");
PyObject *
Signature__pointer__get__(Signature *self)
Signature__pointer__get__(Repository *self)
{
/* Bytes means a raw buffer */
return PyBytes_FromStringAndSize((char *) &self->signature, sizeof(git_signature *));
return PyBytes_FromStringAndSize((char *) &self->repo, sizeof(git_repository *));
}
PyDoc_STRVAR(Signature__encoding__doc__, "Encoding.");
@ -158,7 +158,7 @@ PyDoc_STRVAR(Signature_time__doc__, "Unix time.");
PyObject *
Signature_time__get__(Signature *self)
{
return PyInt_FromLongLong(self->signature->when.time);
return PyLong_FromLongLong(self->signature->when.time);
}
@ -167,7 +167,7 @@ PyDoc_STRVAR(Signature_offset__doc__, "Offset from UTC in minutes.");
PyObject *
Signature_offset__get__(Signature *self)
{
return PyInt_FromLong(self->signature->when.offset);
return PyLong_FromLong(self->signature->when.offset);
}
PyGetSetDef Signature_getseters[] = {

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,
@ -111,11 +111,7 @@ PyDoc_STRVAR(Tag__message__doc__, "Tag message (bytes).");
PyObject *
Tag__message__get__(Tag *self)
{
const char *message;
message = git_tag_message(self->tag);
if (!message)
Py_RETURN_NONE;
return PyBytes_FromString(message);
return PyBytes_FromString(git_tag_message(self->tag));
}
PyMethodDef Tag_methods[] = {

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,
@ -54,7 +54,7 @@ PyDoc_STRVAR(TreeEntry_filemode__doc__, "Filemode.");
PyObject *
TreeEntry_filemode__get__(TreeEntry *self)
{
return PyInt_FromLong(git_tree_entry_filemode(self->entry));
return PyLong_FromLong(git_tree_entry_filemode(self->entry));
}
@ -67,24 +67,6 @@ TreeEntry_name__get__(TreeEntry *self)
}
PyDoc_STRVAR(TreeEntry__name__doc__, "Name (bytes).");
PyObject *
TreeEntry__name__get__(TreeEntry *self)
{
return PyBytes_FromString(git_tree_entry_name(self->entry));
}
PyDoc_STRVAR(TreeEntry_type__doc__, "Type.");
PyObject *
TreeEntry_type__get__(TreeEntry *self)
{
return to_path(git_object_type2string(git_tree_entry_type(self->entry)));
}
PyDoc_STRVAR(TreeEntry_id__doc__, "Object id.");
PyObject *
@ -186,11 +168,9 @@ TreeEntry_repr(TreeEntry *self)
PyGetSetDef TreeEntry_getseters[] = {
GETTER(TreeEntry, filemode),
GETTER(TreeEntry, name),
GETTER(TreeEntry, _name),
GETTER(TreeEntry, oid),
GETTER(TreeEntry, id),
GETTER(TreeEntry, hex),
GETTER(TreeEntry, type),
{NULL}
};
@ -290,7 +270,7 @@ Tree_fix_index(Tree *self, PyObject *py_index)
size_t len;
long slen;
index = PyInt_AsLong(py_index);
index = PyLong_AsLong(py_index);
if (PyErr_Occurred())
return -1;
@ -359,7 +339,7 @@ Tree_getitem(Tree *self, PyObject *value)
int err;
/* Case 1: integer */
if (PyInt_Check(value))
if (PyLong_Check(value))
return Tree_getitem_by_index(self, value);
/* Case 2: byte or text string */

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,
@ -32,8 +32,8 @@
#include <Python.h>
#include <git2.h>
#if !(LIBGIT2_VER_MAJOR == 0 && LIBGIT2_VER_MINOR == 26)
#error You need a compatible libgit2 version (v0.26.x)
#if !(LIBGIT2_VER_MAJOR == 0 && LIBGIT2_VER_MINOR == 23)
#error You need a compatible libgit2 version (v0.23.x)
#endif
/*

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,
@ -83,7 +83,8 @@ py_str_borrow_c_str(PyObject **tvalue, PyObject *value, const char *encoding)
}
/* Type error */
Error_type_error("unexpected %.200s", value);
PyErr_Format(PyExc_TypeError, "unexpected %.200s",
Py_TYPE(value)->tp_name);
return NULL;
}
@ -93,7 +94,7 @@ py_str_borrow_c_str(PyObject **tvalue, PyObject *value, const char *encoding)
PyObject *
get_pylist_from_git_strarray(git_strarray *strarray)
{
size_t index;
int index;
PyObject *new_list;
new_list = PyList_New(strarray->count);
@ -160,39 +161,40 @@ on_error:
static git_otype
py_type_to_git_type(PyTypeObject *py_type)
{
if (py_type == &CommitType)
return GIT_OBJ_COMMIT;
else if (py_type == &TreeType)
return GIT_OBJ_TREE;
else if (py_type == &BlobType)
return GIT_OBJ_BLOB;
else if (py_type == &TagType)
return GIT_OBJ_TAG;
git_otype type = GIT_OBJ_BAD;
PyErr_SetString(PyExc_ValueError, "invalid target type");
return GIT_OBJ_BAD; /* -1 */
if (py_type == &CommitType) {
type = GIT_OBJ_COMMIT;
} else if (py_type == &TreeType) {
type = GIT_OBJ_TREE;
} else if (py_type == &BlobType) {
type = GIT_OBJ_BLOB;
} else if (py_type == &TagType) {
type = GIT_OBJ_TAG;
}
return type;
}
git_otype
py_object_to_otype(PyObject *py_type)
int
py_object_to_object_type(PyObject *py_type)
{
long value;
int type = -1;
if (py_type == Py_None)
return GIT_OBJ_ANY;
if (PyInt_Check(py_type)) {
value = PyInt_AsLong(py_type);
if (value == -1 && PyErr_Occurred())
return GIT_OBJ_BAD;
/* TODO Check whether the value is a valid value */
return (git_otype)value;
if (PyLong_Check(py_type)) {
type = PyLong_AsLong(py_type);
if (type == -1 && PyErr_Occurred())
return -1;
} else if (PyType_Check(py_type)) {
type = py_type_to_git_type((PyTypeObject *) py_type);
}
if (PyType_Check(py_type))
return py_type_to_git_type((PyTypeObject *) py_type);
if (type == -1) {
PyErr_SetString(PyExc_ValueError, "invalid target type");
}
PyErr_SetString(PyExc_ValueError, "invalid target type");
return GIT_OBJ_BAD; /* -1 */
return type;
}

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,
@ -40,17 +40,14 @@
#endif
/* Python 2 support */
#ifndef Py_hash_t
#define Py_hash_t long
#endif
#ifndef PyLong_AsSize_t
#define PyLong_AsSize_t (size_t)PyLong_AsSsize_t
#endif
#if PY_MAJOR_VERSION == 2
#define PyInt_AsSize_t (size_t)PyInt_AsLong
#define PyInt_FromLongLong PyInt_FromLong
#define PyLong_FromSize_t PyInt_FromSize_t
#define PyLong_AsSize_t (size_t)PyInt_AsSsize_t
#define PyLong_AsLong PyInt_AsLong
#undef PyLong_Check
#define PyLong_Check PyInt_Check
#define PyLong_FromLong PyInt_FromLong
#define PyInteger_Type PyInt_Type
#define PyBytes_AS_STRING PyString_AS_STRING
#define PyBytes_AsString PyString_AsString
#define PyBytes_AsStringAndSize PyString_AsStringAndSize
@ -61,18 +58,20 @@
#define to_path(x) to_bytes(x)
#define to_encoding(x) to_bytes(x)
#else
#define PyInt_Check PyLong_Check
#define PyInt_FromSize_t PyLong_FromSize_t
#define PyInt_FromLong PyLong_FromLong
#define PyInt_FromLongLong PyLong_FromLongLong
#define PyInt_AsLong PyLong_AsLong
#define PyInt_AsSize_t PyLong_AsSize_t
#define PyInteger_Type PyLong_Type
#define to_path(x) to_unicode(x, Py_FileSystemDefaultEncoding, "strict")
#define to_encoding(x) PyUnicode_DecodeASCII(x, strlen(x), "strict")
#define PyString_FromFormat(s, ...) PyUnicode_FromFormat(s, __VA_ARGS__)
#endif
#ifdef PYPY_VERSION
#define PyLong_AsSize_t (size_t)PyLong_AsUnsignedLong
#endif
#ifndef Py_hash_t
#define Py_hash_t long
#endif
#define CHECK_REFERENCE(self)\
if (self->reference == NULL) {\
@ -121,7 +120,7 @@ const char *py_str_borrow_c_str(PyObject **tvaue, PyObject *value, const char *e
PyObject * get_pylist_from_git_strarray(git_strarray *strarray);
int get_strarraygit_from_pylist(git_strarray *array, PyObject *pylist);
int py_object_to_otype(PyObject *py_type);
int py_object_to_object_type(PyObject *py_type);
#define py_path_to_c_str(py_path) \
py_str_to_c_str(py_path, Py_FileSystemDefaultEncoding)

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,
@ -98,13 +98,13 @@ PyDoc_STRVAR(Walker_sort__doc__,
PyObject *
Walker_sort(Walker *self, PyObject *py_sort_mode)
{
long sort_mode;
int sort_mode;
sort_mode = PyInt_AsLong(py_sort_mode);
sort_mode = (int)PyLong_AsLong(py_sort_mode);
if (sort_mode == -1 && PyErr_Occurred())
return NULL;
git_revwalk_sorting(self->walk, (unsigned int)sort_mode);
git_revwalk_sorting(self->walk, sort_mode);
Py_RETURN_NONE;
}

@ -1,5 +1,5 @@
/*
* Copyright 2010-2017 The pygit2 contributors
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2017 The pygit2 contributors
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,

Binary file not shown.

Binary file not shown.

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2017 The pygit2 contributors
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2017 The pygit2 contributors
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2017 The pygit2 contributors
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2017 The pygit2 contributors
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,
@ -30,7 +30,6 @@
from __future__ import absolute_import
from __future__ import unicode_literals
from os.path import dirname, join
import io
import unittest
import pygit2
@ -113,19 +112,6 @@ class BlobTest(utils.RepoTestCase):
self.assertTrue(isinstance(blob, pygit2.Blob))
self.assertEqual(pygit2.GIT_OBJ_BLOB, blob.type)
def test_create_blob_fromiobase(self):
self.assertRaises(TypeError, self.repo.create_blob_fromiobase, 'bad type')
f = io.BytesIO(BLOB_CONTENT)
blob_oid = self.repo.create_blob_fromiobase(f)
blob = self.repo[blob_oid]
self.assertTrue(isinstance(blob, pygit2.Blob))
self.assertEqual(pygit2.GIT_OBJ_BLOB, blob.type)
self.assertEqual(blob_oid, blob.id)
self.assertEqual(BLOB_SHA, blob_oid.hex)
def test_diff_blob(self):
blob = self.repo[BLOB_SHA]
old_blob = self.repo['3b18e512dba79e4c8300dd08aeb37f8e728b8dad']

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2017 The pygit2 contributors
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,
@ -39,135 +39,6 @@ I18N_LAST_COMMIT = '5470a671a80ac3789f1a6a8cefbcf43ce7af0563'
ORIGIN_MASTER_COMMIT = '784855caf26449a1914d2cf62d12b9374d76ae78'
class BranchesObjectTestCase(utils.RepoTestCase):
def test_lookup_branch_local(self):
branch = self.repo.branches['master']
self.assertEqual(branch.target.hex, LAST_COMMIT)
branch = self.repo.branches.local['i18n']
self.assertEqual(branch.target.hex, I18N_LAST_COMMIT)
self.assertTrue(self.repo.branches.get('not-exists') is None)
self.assertRaises(KeyError, lambda: self.repo.branches['not-exists'])
def test_listall_branches(self):
branches = sorted(self.repo.branches)
self.assertEqual(branches, ['i18n', 'master'])
def test_create_branch(self):
commit = self.repo[LAST_COMMIT]
reference = self.repo.branches.create('version1', commit)
self.assertTrue('version1' in self.repo.branches)
reference = self.repo.branches['version1']
self.assertEqual(reference.target.hex, LAST_COMMIT)
# try to create existing reference
self.assertRaises(ValueError,
lambda: self.repo.branches.create('version1', commit))
# try to create existing reference with force
reference = self.repo.branches.create('version1', commit, True)
self.assertEqual(reference.target.hex, LAST_COMMIT)
def test_delete(self):
self.repo.branches.delete('i18n')
self.assertTrue(self.repo.branches.get('i18n') is None)
def test_cant_delete_master(self):
self.assertRaises(pygit2.GitError, lambda: self.repo.branches.delete('master'))
def test_branch_is_head_returns_true_if_branch_is_head(self):
branch = self.repo.branches.get('master')
self.assertTrue(branch.is_head())
def test_branch_is_head_returns_false_if_branch_is_not_head(self):
branch = self.repo.branches.get('i18n')
self.assertFalse(branch.is_head())
def test_branch_rename_succeeds(self):
new_branch = self.repo.branches['i18n'].rename('new-branch')
self.assertEqual(new_branch.target.hex, I18N_LAST_COMMIT)
new_branch_2 = self.repo.branches.get('new-branch')
self.assertEqual(new_branch_2.target.hex, I18N_LAST_COMMIT)
def test_branch_rename_fails_if_destination_already_exists(self):
original_branch = self.repo.branches.get('i18n')
self.assertRaises(ValueError, lambda: original_branch.rename('master'))
def test_branch_rename_not_fails_if_force_is_true(self):
original_branch = self.repo.branches.get('master')
new_branch = original_branch.rename('i18n', True)
self.assertEqual(new_branch.target.hex, LAST_COMMIT)
def test_branch_rename_fails_with_invalid_names(self):
original_branch = self.repo.branches.get('i18n')
self.assertRaises(ValueError,
lambda: original_branch.rename('abc@{123'))
def test_branch_name(self):
branch = self.repo.branches.get('master')
self.assertEqual(branch.branch_name, 'master')
self.assertEqual(branch.name, 'refs/heads/master')
branch = self.repo.branches.get('i18n')
self.assertEqual(branch.branch_name, 'i18n')
self.assertEqual(branch.name, 'refs/heads/i18n')
class BranchesObjectEmptyRepoTestCase(utils.EmptyRepoTestCase):
def setUp(self):
super(utils.EmptyRepoTestCase, self).setUp()
remote = self.repo.remotes[0]
remote.fetch()
def test_lookup_branch_remote(self):
branch = self.repo.branches.remote.get('origin/master')
self.assertEqual(branch.target.hex, ORIGIN_MASTER_COMMIT)
self.assertTrue(
self.repo.branches.remote.get('origin/not-exists') is None)
def test_listall_branches(self):
branches = sorted(self.repo.branches.remote)
self.assertEqual(branches, ['origin/master'])
def test_branch_remote_name(self):
self.repo.remotes[0].fetch()
branch = self.repo.branches.remote['origin/master']
self.assertEqual(branch.remote_name, 'origin')
def test_branch_upstream(self):
self.repo.remotes[0].fetch()
remote_master = self.repo.branches.remote['origin/master']
master = self.repo.branches.create('master',
self.repo[remote_master.target.hex])
self.assertTrue(master.upstream is None)
master.upstream = remote_master
self.assertEqual(master.upstream.branch_name, 'origin/master')
def set_bad_upstream():
master.upstream = 2.5
self.assertRaises(TypeError, set_bad_upstream)
master.upstream = None
self.assertTrue(master.upstream is None)
def test_branch_upstream_name(self):
self.repo.remotes[0].fetch()
remote_master = self.repo.branches.remote['origin/master']
master = self.repo.branches.create('master',
self.repo[remote_master.target.hex])
master.upstream = remote_master
self.assertEqual(master.upstream_name, 'refs/remotes/origin/master')
class BranchesTestCase(utils.RepoTestCase):
def test_lookup_branch_local(self):
branch = self.repo.lookup_branch('master')
@ -217,14 +88,6 @@ class BranchesTestCase(utils.RepoTestCase):
branch = self.repo.lookup_branch('i18n')
self.assertFalse(branch.is_head())
def test_branch_is_checked_out_returns_true_if_branch_is_checked_out(self):
branch = self.repo.lookup_branch('master')
self.assertTrue(branch.is_checked_out())
def test_branch_is_checked_out_returns_false_if_branch_is_not_checked_out(self):
branch = self.repo.lookup_branch('i18n')
self.assertFalse(branch.is_checked_out())
def test_branch_rename_succeeds(self):
original_branch = self.repo.lookup_branch('i18n')
new_branch = original_branch.rename('new-branch')
@ -296,7 +159,6 @@ class BranchesEmptyRepoTestCase(utils.EmptyRepoTestCase):
def set_bad_upstream():
master.upstream = 2.5
self.assertRaises(TypeError, set_bad_upstream)
master.upstream = None

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2017 The pygit2 contributors
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2017 The pygit2 contributors
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2017 The pygit2 contributors
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,
@ -97,7 +97,7 @@ class ConfigTest(utils.RepoTestCase):
self.assertRaises(TypeError, lambda: config[()])
self.assertRaises(TypeError, lambda: config[-4])
self.assertRaisesWithArg(ValueError, "invalid config item name 'abc'",
self.assertRaisesWithArg(ValueError, "Invalid config item name 'abc'",
lambda: config['abc'])
self.assertRaisesWithArg(KeyError, 'abc.def',
lambda: config['abc.def'])
@ -153,7 +153,7 @@ class ConfigTest(utils.RepoTestCase):
new_file.write("[this]\n\tthat = foobar\n\tthat = foobeer\n")
new_file.close()
config.add_file(CONFIG_FILENAME, 6)
config.add_file(CONFIG_FILENAME, 5)
self.assertTrue('this.that' in config)
l = config.get_multivar('this.that', 'foo.*')
self.assertEqual(2, len(list(l)))

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2017 The pygit2 contributors
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,
@ -70,37 +70,32 @@ class CredentialCreateTest(utils.NoRepoTestCase):
class CredentialCallback(utils.RepoTestCase):
def test_callback(self):
class MyCallbacks(pygit2.RemoteCallbacks):
@staticmethod
def credentials(url, username, allowed):
self.assertTrue(allowed & GIT_CREDTYPE_USERPASS_PLAINTEXT)
raise Exception("I don't know the password")
def credentials_cb(url, username, allowed):
self.assertTrue(allowed & GIT_CREDTYPE_USERPASS_PLAINTEXT)
raise Exception("I don't know the password")
url = "https://github.com/github/github"
remote = self.repo.create_remote("github", url)
remote = self.repo.create_remote("github", "https://github.com/github/github")
remote.credentials = credentials_cb
self.assertRaises(Exception, lambda: remote.fetch(callbacks=MyCallbacks()))
self.assertRaises(Exception, remote.fetch)
def test_bad_cred_type(self):
class MyCallbacks(pygit2.RemoteCallbacks):
@staticmethod
def credentials(url, username, allowed):
self.assertTrue(allowed & GIT_CREDTYPE_USERPASS_PLAINTEXT)
return Keypair("git", "foo.pub", "foo", "sekkrit")
def credentials_cb(url, username, allowed):
self.assertTrue(allowed & GIT_CREDTYPE_USERPASS_PLAINTEXT)
return Keypair("git", "foo.pub", "foo", "sekkrit")
url = "https://github.com/github/github"
remote = self.repo.create_remote("github", url)
self.assertRaises(TypeError, lambda: remote.fetch(callbacks=MyCallbacks()))
remote = self.repo.create_remote("github", "https://github.com/github/github")
remote.credentials = credentials_cb
self.assertRaises(TypeError, remote.fetch)
class CallableCredentialTest(utils.RepoTestCase):
def test_user_pass(self):
credentials = UserPass("libgit2", "libgit2")
callbacks = pygit2.RemoteCallbacks(credentials=credentials)
remote = self.repo.create_remote("bb", "https://bitbucket.org/libgit2/testgitrepository.git")
remote.credentials = UserPass("libgit2", "libgit2")
url = "https://bitbucket.org/libgit2/testgitrepository.git"
remote = self.repo.create_remote("bb", url)
remote.fetch(callbacks=callbacks)
remote.fetch()
if __name__ == '__main__':
unittest.main()

@ -1,106 +0,0 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2017 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,
# as published by the Free Software Foundation.
#
# In addition to the permissions in the GNU General Public License,
# the authors give you unlimited permission to link the compiled
# version of this file into combinations with other programs,
# and to distribute those combinations without any restriction
# coming from the use of this file. (The General Public License
# restrictions do apply in other respects; for example, they cover
# modification of the file, and distribution when not linked into
# a combined executable.)
#
# This file is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING. If not, write to
# the Free Software Foundation, 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301, USA.
"""Tests for describing commits."""
from __future__ import absolute_import
from __future__ import unicode_literals
import unittest
from pygit2 import GIT_DESCRIBE_DEFAULT, GIT_DESCRIBE_TAGS, GIT_DESCRIBE_ALL
import pygit2
from . import utils
def add_tag(repo, name, target):
message = 'Example tag.\n'
tagger = pygit2.Signature('John Doe', 'jdoe@example.com', 12347, 0)
sha = repo.create_tag(name, target, pygit2.GIT_OBJ_COMMIT, tagger, message)
return sha
class DescribeTest(utils.RepoTestCase):
def test_describe(self):
add_tag(self.repo, 'thetag', '4ec4389a8068641da2d6578db0419484972284c8')
self.assertEqual('thetag-2-g2be5719', self.repo.describe())
def test_describe_without_ref(self):
self.assertRaises(pygit2.GitError, self.repo.describe)
def test_describe_default_oid(self):
self.assertEqual('2be5719', self.repo.describe(show_commit_oid_as_fallback=True))
def test_describe_strategies(self):
self.assertEqual('heads/master', self.repo.describe(describe_strategy=GIT_DESCRIBE_ALL))
self.repo.create_reference('refs/tags/thetag', '4ec4389a8068641da2d6578db0419484972284c8')
self.assertRaises(KeyError, self.repo.describe)
self.assertEqual('thetag-2-g2be5719', self.repo.describe(describe_strategy=GIT_DESCRIBE_TAGS))
def test_describe_pattern(self):
add_tag(self.repo, 'private/tag1', '5ebeeebb320790caf276b9fc8b24546d63316533')
add_tag(self.repo, 'public/tag2', '4ec4389a8068641da2d6578db0419484972284c8')
self.assertEqual('public/tag2-2-g2be5719', self.repo.describe(pattern='public/*'))
def test_describe_committish(self):
add_tag(self.repo, 'thetag', 'acecd5ea2924a4b900e7e149496e1f4b57976e51')
self.assertEqual('thetag-4-g2be5719', self.repo.describe(committish='HEAD'))
self.assertEqual('thetag-1-g5ebeeeb', self.repo.describe(committish='HEAD^'))
self.assertEqual('thetag-4-g2be5719', self.repo.describe(committish=self.repo.head))
self.assertEqual('thetag-1-g6aaa262', self.repo.describe(committish='6aaa262e655dd54252e5813c8e5acd7780ed097d'))
self.assertEqual('thetag-1-g6aaa262', self.repo.describe(committish='6aaa262'))
def test_describe_follows_first_branch_only(self):
add_tag(self.repo, 'thetag', '4ec4389a8068641da2d6578db0419484972284c8')
self.assertRaises(KeyError, self.repo.describe, only_follow_first_parent=True)
def test_describe_abbreviated_size(self):
add_tag(self.repo, 'thetag', '4ec4389a8068641da2d6578db0419484972284c8')
self.assertEqual('thetag-2-g2be5719152d4f82c', self.repo.describe(abbreviated_size=16))
self.assertEqual('thetag', self.repo.describe(abbreviated_size=0))
def test_describe_long_format(self):
add_tag(self.repo, 'thetag', '2be5719152d4f82c7302b1c0932d8e5f0a4a0e98')
self.assertEqual('thetag-0-g2be5719', self.repo.describe(always_use_long_format=True))
class DescribeDirtyWorkdirTest(utils.DirtyRepoTestCase):
def setUp(self):
super(utils.DirtyRepoTestCase, self).setUp()
add_tag(self.repo, 'thetag', 'a763aa560953e7cfb87ccbc2f536d665aa4dff22')
def test_describe(self):
self.assertEqual('thetag', self.repo.describe())
def test_describe_with_dirty_suffix(self):
self.assertEqual('thetag-dirty', self.repo.describe(dirty_suffix='-dirty'))

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2017 The pygit2 contributors
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,
@ -33,7 +33,6 @@ import unittest
import pygit2
from pygit2 import GIT_DIFF_INCLUDE_UNMODIFIED
from pygit2 import GIT_DIFF_IGNORE_WHITESPACE, GIT_DIFF_IGNORE_WHITESPACE_EOL
from pygit2 import GIT_DIFF_SHOW_BINARY
from pygit2 import GIT_DELTA_RENAMED
from . import utils
from itertools import chain
@ -64,22 +63,6 @@ index 297efb8..0000000
-c/d contents
"""
PATCH_BINARY = """diff --git a/binary_file b/binary_file
index 86e5c10..b835d73 100644
Binary files a/binary_file and b/binary_file differ
"""
PATCH_BINARY_SHOW = """diff --git a/binary_file b/binary_file
index 86e5c1008b5ce635d3e3fffa4434c5eccd8f00b6..b835d73543244b6694f36a8c5dfdffb71b153db7 100644
GIT binary patch
literal 8
Pc${NM%FIhFs^kIy3n&7R
literal 8
Pc${NM&PdElPvrst3ey5{
"""
DIFF_HEAD_TO_INDEX_EXPECTED = [
'staged_changes',
'staged_changes_file_deleted',
@ -325,15 +308,5 @@ class DiffTest(utils.BareRepoTestCase):
width=80)
self.assertEqual(STATS_EXPECTED, formatted)
class BinaryDiffTest(utils.BinaryFileRepoTestCase):
def test_binary_diff(self):
repo = self.repo
diff = repo.diff('HEAD', 'HEAD^')
self.assertEqual(PATCH_BINARY, diff.patch)
diff = repo.diff('HEAD', 'HEAD^', flags=GIT_DIFF_SHOW_BINARY)
self.assertEqual(PATCH_BINARY_SHOW, diff.patch)
if __name__ == '__main__':
unittest.main()

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2017 The pygit2 contributors
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2017 The pygit2 contributors
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2017 The pygit2 contributors
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2017 The pygit2 contributors
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2017 The pygit2 contributors
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2017 The pygit2 contributors
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,
@ -31,81 +31,24 @@ from __future__ import absolute_import
from __future__ import unicode_literals
import unittest
import pygit2
from pygit2 import (
GIT_OBJ_BLOB,
GIT_OPT_GET_MWINDOW_SIZE, GIT_OPT_SET_MWINDOW_SIZE,
GIT_OPT_GET_SEARCH_PATH, GIT_OPT_SET_SEARCH_PATH,
GIT_OPT_GET_MWINDOW_MAPPED_LIMIT, GIT_OPT_SET_MWINDOW_MAPPED_LIMIT,
GIT_CONFIG_LEVEL_SYSTEM, GIT_CONFIG_LEVEL_XDG, GIT_CONFIG_LEVEL_GLOBAL,
GIT_OPT_SET_CACHE_OBJECT_LIMIT,
GIT_OPT_GET_CACHED_MEMORY,
GIT_OPT_ENABLE_CACHING,
)
from pygit2 import GIT_OPT_GET_MWINDOW_SIZE, GIT_OPT_SET_MWINDOW_SIZE
from pygit2 import GIT_OPT_GET_SEARCH_PATH, GIT_OPT_SET_SEARCH_PATH
from pygit2 import GIT_CONFIG_LEVEL_SYSTEM, GIT_CONFIG_LEVEL_XDG, GIT_CONFIG_LEVEL_GLOBAL
from pygit2 import option
from . import utils
class OptionsTest(utils.NoRepoTestCase):
def __option(self, getter, setter, value):
old_value = option(getter)
option(setter, value)
self.assertEqual(value, option(getter))
# Reset to avoid side effects in later tests
option(setter, old_value)
def __proxy(self, name, value):
old_value = getattr(pygit2.settings, name)
setattr(pygit2.settings, name, value)
self.assertEqual(value, getattr(pygit2.settings, name))
# Reset to avoid side effects in later tests
setattr(pygit2.settings, name, old_value)
def test_mwindow_size(self):
self.__option(
GIT_OPT_GET_MWINDOW_SIZE,
GIT_OPT_SET_MWINDOW_SIZE,
200 * 1024)
new_size = 200 * 1024
option(GIT_OPT_SET_MWINDOW_SIZE, new_size)
self.assertEqual(new_size, option(GIT_OPT_GET_MWINDOW_SIZE))
def test_mwindow_size_proxy(self):
self.__proxy('mwindow_size', 300 * 1024)
new_size = 300 * 1024
pygit2.settings.mwindow_size = new_size
def test_mwindow_mapped_limit_200(self):
self.__option(
GIT_OPT_GET_MWINDOW_MAPPED_LIMIT,
GIT_OPT_SET_MWINDOW_MAPPED_LIMIT,
200 * 1024)
def test_mwindow_mapped_limit_300(self):
self.__proxy('mwindow_mapped_limit', 300 * 1024)
def test_cache_object_limit(self):
new_limit = 2 * 1024
option(GIT_OPT_SET_CACHE_OBJECT_LIMIT, GIT_OBJ_BLOB, new_limit)
def test_cache_object_limit_proxy(self):
new_limit = 4 * 1024
pygit2.settings.cache_object_limit(GIT_OBJ_BLOB, new_limit)
def test_cached_memory(self):
value = option(GIT_OPT_GET_CACHED_MEMORY)
self.assertEqual(value[1], 256 * 1024**2)
def test_cached_memory_proxy(self):
self.assertEqual(pygit2.settings.cached_memory[1], 256 * 1024**2)
def test_enable_cache(self):
option(GIT_OPT_ENABLE_CACHING, False)
option(GIT_OPT_ENABLE_CACHING, True)
def test_enable_cache_proxy(self):
pygit2.settings.enable_caching(False)
pygit2.settings.enable_caching(True)
def test_cache_max_size_proxy(self):
pygit2.settings.cache_max_size(128 * 1024**2)
self.assertEqual(pygit2.settings.cached_memory[1], 128 * 1024**2)
pygit2.settings.cache_max_size(256 * 1024**2)
self.assertEqual(pygit2.settings.cached_memory[1], 256 * 1024**2)
self.assertEqual(new_size, pygit2.settings.mwindow_size)
def test_search_path(self):
paths = [(GIT_CONFIG_LEVEL_GLOBAL, '/tmp/global'),

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2017 The pygit2 contributors
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,
@ -35,213 +35,12 @@ from pygit2 import GitError, GIT_REF_OID, GIT_REF_SYMBOLIC, Signature
from pygit2 import Commit, Tree
from . import utils
LAST_COMMIT = '2be5719152d4f82c7302b1c0932d8e5f0a4a0e98'
class ReferencesObjectTest(utils.RepoTestCase):
def test_list_all_reference_objects(self):
repo = self.repo
refs = [(ref.name, ref.target.hex)
for ref in repo.references.objects]
self.assertEqual(sorted(refs),
[('refs/heads/i18n',
'5470a671a80ac3789f1a6a8cefbcf43ce7af0563'),
('refs/heads/master',
'2be5719152d4f82c7302b1c0932d8e5f0a4a0e98')])
def test_list_all_references(self):
repo = self.repo
# Without argument
self.assertEqual(sorted(repo.references),
['refs/heads/i18n', 'refs/heads/master'])
# We add a symbolic reference
repo.create_reference('refs/tags/version1', 'refs/heads/master')
self.assertEqual(sorted(repo.references),
['refs/heads/i18n', 'refs/heads/master',
'refs/tags/version1'])
def test_head(self):
head = self.repo.head
self.assertEqual(LAST_COMMIT, self.repo[head.target].hex)
def test_lookup_reference(self):
repo = self.repo
refname = 'refs/foo'
# Raise KeyError ?
self.assertRaises(KeyError, lambda: self.repo.references[refname])
# Return None ?
self.assertIsNone(self.repo.references.get(refname))
# Test a lookup
reference = repo.references.get('refs/heads/master')
self.assertEqual(reference.name, 'refs/heads/master')
def test_reference_get_sha(self):
reference = self.repo.references['refs/heads/master']
self.assertEqual(reference.target.hex, LAST_COMMIT)
def test_reference_set_sha(self):
NEW_COMMIT = '5ebeeebb320790caf276b9fc8b24546d63316533'
reference = self.repo.references.get('refs/heads/master')
reference.set_target(NEW_COMMIT)
self.assertEqual(reference.target.hex, NEW_COMMIT)
def test_reference_set_sha_prefix(self):
NEW_COMMIT = '5ebeeebb320790caf276b9fc8b24546d63316533'
reference = self.repo.references.get('refs/heads/master')
reference.set_target(NEW_COMMIT[0:6])
self.assertEqual(reference.target.hex, NEW_COMMIT)
def test_reference_get_type(self):
reference = self.repo.references.get('refs/heads/master')
self.assertEqual(reference.type, GIT_REF_OID)
def test_get_target(self):
reference = self.repo.references.get('HEAD')
self.assertEqual(reference.target, 'refs/heads/master')
def test_set_target(self):
reference = self.repo.references.get('HEAD')
self.assertEqual(reference.target, 'refs/heads/master')
reference.set_target('refs/heads/i18n')
self.assertEqual(reference.target, 'refs/heads/i18n')
def test_get_shorthand(self):
reference = self.repo.references.get('refs/heads/master')
self.assertEqual(reference.shorthand, 'master')
reference = self.repo.references.create('refs/remotes/origin/master', LAST_COMMIT)
self.assertEqual(reference.shorthand, 'origin/master')
def test_set_target_with_message(self):
reference = self.repo.references.get('HEAD')
self.assertEqual(reference.target, 'refs/heads/master')
sig = Signature('foo', 'bar')
self.repo.set_ident('foo', 'bar')
msg = 'Hello log'
reference.set_target('refs/heads/i18n', message=msg)
self.assertEqual(reference.target, 'refs/heads/i18n')
self.assertEqual(list(reference.log())[0].message, msg)
self.assertEqualSignature(list(reference.log())[0].committer, sig)
def test_delete(self):
repo = self.repo
# We add a tag as a new reference that points to "origin/master"
reference = repo.references.create('refs/tags/version1', LAST_COMMIT)
self.assertTrue('refs/tags/version1' in repo.references)
# And we delete it
reference.delete()
self.assertFalse('refs/tags/version1' in repo.references)
# Access the deleted reference
self.assertRaises(GitError, getattr, reference, 'name')
self.assertRaises(GitError, getattr, reference, 'type')
self.assertRaises(GitError, getattr, reference, 'target')
self.assertRaises(GitError, reference.delete)
self.assertRaises(GitError, reference.resolve)
self.assertRaises(GitError, reference.rename, "refs/tags/version2")
def test_rename(self):
# We add a tag as a new reference that points to "origin/master"
reference = self.repo.references.create('refs/tags/version1',
LAST_COMMIT)
self.assertEqual(reference.name, 'refs/tags/version1')
reference.rename('refs/tags/version2')
self.assertEqual(reference.name, 'refs/tags/version2')
# def test_reload(self):
# name = 'refs/tags/version1'
# repo = self.repo
# ref = repo.create_reference(name, "refs/heads/master", symbolic=True)
# ref2 = repo.lookup_reference(name)
# ref.delete()
# self.assertEqual(ref2.name, name)
# self.assertRaises(KeyError, ref2.reload)
# self.assertRaises(GitError, getattr, ref2, 'name')
def test_reference_resolve(self):
reference = self.repo.references.get('HEAD')
self.assertEqual(reference.type, GIT_REF_SYMBOLIC)
reference = reference.resolve()
self.assertEqual(reference.type, GIT_REF_OID)
self.assertEqual(reference.target.hex, LAST_COMMIT)
def test_reference_resolve_identity(self):
head = self.repo.references.get('HEAD')
ref = head.resolve()
self.assertTrue(ref.resolve() is ref)
def test_create_reference(self):
# We add a tag as a new reference that points to "origin/master"
reference = self.repo.references.create('refs/tags/version1',
LAST_COMMIT)
refs = self.repo.references
self.assertTrue('refs/tags/version1' in refs)
reference = self.repo.references.get('refs/tags/version1')
self.assertEqual(reference.target.hex, LAST_COMMIT)
# try to create existing reference
self.assertRaises(ValueError, self.repo.references.create,
'refs/tags/version1', LAST_COMMIT)
# try to create existing reference with force
reference = self.repo.references.create('refs/tags/version1',
LAST_COMMIT, force=True)
self.assertEqual(reference.target.hex, LAST_COMMIT)
def test_create_symbolic_reference(self):
repo = self.repo
# We add a tag as a new symbolic reference that always points to
# "refs/heads/master"
reference = repo.references.create('refs/tags/beta',
'refs/heads/master')
self.assertEqual(reference.type, GIT_REF_SYMBOLIC)
self.assertEqual(reference.target, 'refs/heads/master')
# try to create existing symbolic reference
self.assertRaises(ValueError, repo.references.create,
'refs/tags/beta', 'refs/heads/master')
# try to create existing symbolic reference with force
reference = repo.references.create('refs/tags/beta',
'refs/heads/master', force=True)
self.assertEqual(reference.type, GIT_REF_SYMBOLIC)
self.assertEqual(reference.target, 'refs/heads/master')
# def test_packall_references(self):
# self.repo.packall_references()
def test_get_object(self):
repo = self.repo
ref = repo.references.get('refs/heads/master')
self.assertEqual(repo[ref.target].id, ref.get_object().id)
def test_peel(self):
ref = self.repo.references.get('refs/heads/master')
commit = ref.peel(Commit)
self.assertEqual(commit.tree.id, ref.peel(Tree).id)
class ReferencesTest(utils.RepoTestCase):
def test_list_all_reference_objects(self):
repo = self.repo
refs = [(ref.name, ref.target.hex)
for ref in repo.listall_reference_objects()]
self.assertEqual(sorted(refs),
[('refs/heads/i18n',
'5470a671a80ac3789f1a6a8cefbcf43ce7af0563'),
('refs/heads/master',
'2be5719152d4f82c7302b1c0932d8e5f0a4a0e98')])
def test_list_all_references(self):
repo = self.repo
@ -270,10 +69,12 @@ class ReferencesTest(utils.RepoTestCase):
reference = repo.lookup_reference('refs/heads/master')
self.assertEqual(reference.name, 'refs/heads/master')
def test_reference_get_sha(self):
reference = self.repo.lookup_reference('refs/heads/master')
self.assertEqual(reference.target.hex, LAST_COMMIT)
def test_reference_set_sha(self):
NEW_COMMIT = '5ebeeebb320790caf276b9fc8b24546d63316533'
reference = self.repo.lookup_reference('refs/heads/master')
@ -286,14 +87,17 @@ class ReferencesTest(utils.RepoTestCase):
reference.set_target(NEW_COMMIT[0:6])
self.assertEqual(reference.target.hex, NEW_COMMIT)
def test_reference_get_type(self):
reference = self.repo.lookup_reference('refs/heads/master')
self.assertEqual(reference.type, GIT_REF_OID)
def test_get_target(self):
reference = self.repo.lookup_reference('HEAD')
self.assertEqual(reference.target, 'refs/heads/master')
def test_set_target(self):
reference = self.repo.lookup_reference('HEAD')
self.assertEqual(reference.target, 'refs/heads/master')
@ -336,6 +140,7 @@ class ReferencesTest(utils.RepoTestCase):
self.assertRaises(GitError, reference.resolve)
self.assertRaises(GitError, reference.rename, "refs/tags/version2")
def test_rename(self):
# We add a tag as a new reference that points to "origin/master"
reference = self.repo.create_reference('refs/tags/version1',
@ -344,16 +149,17 @@ class ReferencesTest(utils.RepoTestCase):
reference.rename('refs/tags/version2')
self.assertEqual(reference.name, 'refs/tags/version2')
# def test_reload(self):
# name = 'refs/tags/version1'
# repo = self.repo
# ref = repo.create_reference(name, "refs/heads/master", symbolic=True)
# ref2 = repo.lookup_reference(name)
# ref.delete()
# self.assertEqual(ref2.name, name)
# self.assertRaises(KeyError, ref2.reload)
# self.assertRaises(GitError, getattr, ref2, 'name')
# def test_reload(self):
# name = 'refs/tags/version1'
# repo = self.repo
# ref = repo.create_reference(name, "refs/heads/master", symbolic=True)
# ref2 = repo.lookup_reference(name)
# ref.delete()
# self.assertEqual(ref2.name, name)
# self.assertRaises(KeyError, ref2.reload)
# self.assertRaises(GitError, getattr, ref2, 'name')
def test_reference_resolve(self):
@ -363,11 +169,13 @@ class ReferencesTest(utils.RepoTestCase):
self.assertEqual(reference.type, GIT_REF_OID)
self.assertEqual(reference.target.hex, LAST_COMMIT)
def test_reference_resolve_identity(self):
head = self.repo.lookup_reference('HEAD')
ref = head.resolve()
self.assertTrue(ref.resolve() is ref)
def test_create_reference(self):
# We add a tag as a new reference that points to "origin/master"
reference = self.repo.create_reference('refs/tags/version1',
@ -386,6 +194,7 @@ class ReferencesTest(utils.RepoTestCase):
LAST_COMMIT, force=True)
self.assertEqual(reference.target.hex, LAST_COMMIT)
def test_create_symbolic_reference(self):
repo = self.repo
# We add a tag as a new symbolic reference that always points to
@ -395,6 +204,7 @@ class ReferencesTest(utils.RepoTestCase):
self.assertEqual(reference.type, GIT_REF_SYMBOLIC)
self.assertEqual(reference.target, 'refs/heads/master')
# try to create existing symbolic reference
self.assertRaises(ValueError, repo.create_reference,
'refs/tags/beta', 'refs/heads/master')
@ -405,8 +215,9 @@ class ReferencesTest(utils.RepoTestCase):
self.assertEqual(reference.type, GIT_REF_SYMBOLIC)
self.assertEqual(reference.target, 'refs/heads/master')
# def test_packall_references(self):
# self.repo.packall_references()
# def test_packall_references(self):
# self.repo.packall_references()
def test_get_object(self):

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2017 The pygit2 contributors
# Copyright 2010-2014 The pygit2 contributors
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,
@ -33,7 +33,6 @@ import pygit2
import sys
from pygit2 import Oid
from . import utils
import gc
try:
import __pypy__
@ -189,6 +188,21 @@ class RepositoryTest(utils.RepoTestCase):
end = sys.getrefcount(self.repo)
self.assertEqual(start, end)
def test_remote_callback_typecheck(self):
remote = self.repo.remotes[0]
remote.progress = 5
self.assertRaises(TypeError, remote, 'fetch')
remote = self.repo.remotes[0]
remote.transfer_progress = 5
self.assertRaises(TypeError, remote, 'fetch')
remote = self.repo.remotes[0]
remote.update_tips = 5
self.assertRaises(TypeError, remote, 'fetch')
class EmptyRepositoryTest(utils.EmptyRepoTestCase):
def test_fetch(self):
remote = self.repo.remotes[0]
@ -198,37 +212,31 @@ class EmptyRepositoryTest(utils.EmptyRepoTestCase):
self.assertEqual(stats.received_objects, REMOTE_REPO_OBJECTS)
def test_transfer_progress(self):
class MyCallbacks(pygit2.RemoteCallbacks):
def transfer_progress(self, stats):
self.tp = stats
self.tp = None
def tp_cb(stats):
self.tp = stats
callbacks = MyCallbacks()
remote = self.repo.remotes[0]
stats = remote.fetch(callbacks=callbacks)
self.assertEqual(stats.received_bytes, callbacks.tp.received_bytes)
self.assertEqual(stats.indexed_objects, callbacks.tp.indexed_objects)
self.assertEqual(stats.received_objects, callbacks.tp.received_objects)
remote.transfer_progress = tp_cb
stats = remote.fetch()
self.assertEqual(stats.received_bytes, self.tp.received_bytes)
self.assertEqual(stats.indexed_objects, self.tp.indexed_objects)
self.assertEqual(stats.received_objects, self.tp.received_objects)
def test_update_tips(self):
remote = self.repo.remotes[0]
tips = [('refs/remotes/origin/master', Oid(hex='0'*40),
Oid(hex='784855caf26449a1914d2cf62d12b9374d76ae78')),
('refs/tags/root', Oid(hex='0'*40),
Oid(hex='3d2962987c695a29f1f80b6c3aa4ec046ef44369'))]
self.i = 0
self.tips = [('refs/remotes/origin/master', Oid(hex='0'*40),
Oid(hex='784855caf26449a1914d2cf62d12b9374d76ae78')),
('refs/tags/root', Oid(hex='0'*40),
Oid(hex='3d2962987c695a29f1f80b6c3aa4ec046ef44369'))]
class MyCallbacks(pygit2.RemoteCallbacks):
def __init__(self, test_self, tips):
self.test = test_self
self.tips = tips
self.i = 0
def ut_cb(name, old, new):
self.assertEqual(self.tips[self.i], (name, old, new))
self.i += 1
def update_tips(self, name, old, new):
self.test.assertEqual(self.tips[self.i], (name, old, new))
self.i += 1
callbacks = MyCallbacks(self, tips)
remote.fetch(callbacks=callbacks)
self.assertTrue(callbacks.i > 0)
remote.update_tips = ut_cb
remote.fetch()
class PushTestCase(unittest.TestCase):
def setUp(self):
@ -239,11 +247,6 @@ class PushTestCase(unittest.TestCase):
self.remote = self.clone.create_remote('origin', self.origin.path)
def tearDown(self):
self.origin = None
self.clone = None
self.remote = None
gc.collect()
self.origin_ctxtmgr.__exit__(None, None, None)
self.clone_ctxtmgr.__exit__(None, None, None)

Some files were not shown because too many files have changed in this diff Show More