Compare commits

...

117 Commits

Author SHA1 Message Date
Bogdan Vasilescu
371c97cadb Update diff.rst
`old_lineno` appeared twice. I think it should be `new_lineno` instead.
2017-07-18 12:58:56 -04:00
anatoly techtonik
ab3bb01249 install.rst: Use PyPI wheels on Windows 2017-07-07 21:24:04 +03:00
J. David Ibáñez
62c70e852d Release 0.26.0 2017-07-06 17:12:44 +02:00
J. David Ibáñez
e81f45c4c6 Merge remote-tracking branch 'nhynes/br-is-co' 2017-07-05 23:20:15 +02:00
J. David Ibáñez
295166bb64 Fixing AppVeyor & Travis
AppVeyor, upgrade to 0.26
Travis, disable pypy3 for now
2017-07-03 22:55:10 +02:00
Carlos Martín Nieto
96d37e16a9 Update install docs with the v0.26 version of libgit2 2017-07-03 15:48:20 +02:00
Carlos Martín Nieto
2ce8b952c4 Update Travis CI script to use libgit2 v0.26 2017-07-03 15:47:52 +02:00
Carlos Martín Nieto
e41f71f458 Update for libgit2 v0.26
The API isn't changing as much recently so all we needed to adjust was the
proper capitalisation of the error string.
2017-07-03 15:40:29 +02:00
Mark Adams
c6305a062b revert: Add support for git_revert_commit via Repository.revert_commit()
This change adds `Repository.revert_commit()` which wraps around
`git_revert_commit` which will return an `Index` with the appropriate
changes to revert the specified commit.

Fixes #710
2017-06-05 16:08:39 -05:00
Mark Adams
87beb76dcc Modify Index.write_tree() to have more robust Repository detection
Currently, Index.write_tree() relies on either the caller passing in a
`repo=` arg or the underlying `git_index` being already bound to a
`git_repository`. This ignores the case where the caller does not pass
a `repo` argument to `Index.write_tree()` but the `Index._repo`
property is populated on the index.

This change modifies Index.write_tree() to use the passed-in `repo`
argument, falls back to using `Index._repo` and then assumes that
`git_index` must be bound to a `git_repository`. This change should make
Index.write_tree() a little more robust in the most common use-case.
2017-06-05 16:02:01 -05:00
Lukas Fleischer
f18de427bf Randomize OID object hashes
Instead of using type punning to convert the OID to a Python hash, use
_Py_HashBytes() to hash the OID again. This means we no longer make any
assumptions on the internal representation of OID values or Python
hashes (before this commit, we at least relied on the fact that OID
hases are longer than Python hashes). Moreover, the random seed stored
in PYTHONHASHSEED is now honored.

This also fixes a compiler warning seen with -Wstrict-aliasing.

Signed-off-by: Lukas Fleischer <lfleischer@lfos.de>
2017-05-07 10:03:17 +02:00
J. David Ibáñez
f841c62fa6 Drop support for Python 3.2, cffi 1.10 doesn't work with 2017-05-07 09:53:10 +02:00
Lukas Fleischer
035d4a9396 Mark index unsigned in get_pylist_from_git_strarray()
Signed-off-by: Lukas Fleischer <lfleischer@lfos.de>
2017-05-07 07:47:00 +02:00
Lukas Fleischer
21d668421f Remove unused variable from Repository_init()
Signed-off-by: Lukas Fleischer <lfleischer@lfos.de>
2017-05-07 07:44:01 +02:00
Lukas Fleischer
b88dc86842 Fix parameter passing of describe patterns
When ffi.new() is used to build a new pointer object, the returned
pointer object has ownership on the allocated memory. When it is
garbage-collected, then the memory is freed. Thus, we need to make sure
the original object survives its use, otherwise the casted pointer will
point to garbage.

This fixes one test which was failing with the latest CFFI version, see
issue #694. Thus, this commit also reverts 803b1cb (cffi 1.10 not yet
supported, 2017-03-22) where the latest CFFI version was marked as
unsupported.

Signed-off-by: Lukas Fleischer <lfleischer@lfos.de>
2017-05-06 21:49:47 +02:00
J. David Ibáñez
8559b2da20 Release 0.25.1 2017-04-25 19:08:10 +02:00
J. David Ibáñez
9325494d6f docs: fix references 2017-04-21 11:36:40 +02:00
J. David Ibáñez
74717bed55 Merge remote-tracking branch 'tmr232/references-object' 2017-04-21 11:13:09 +02:00
Tamir Bahar
3818555e14 Added Repository.references accessor. 2017-04-21 08:51:41 +00:00
J. David Ibáñez
706c60c4ab Clean some cffi warnings
"has no values explicitly defined"
2017-04-20 22:32:03 +02:00
J. David Ibáñez
0733ba4da3 docs: fix make html 2017-04-19 21:34:07 +02:00
Tamir Bahar
320ee5e733 Added GIT_BRANCH_ALL 2017-04-19 21:10:11 +03:00
Tamir Bahar
d6716e035a Updated docs to match new branches API. 2017-04-19 21:03:43 +03:00
Tamir Bahar
d14438725e Added basic Repository.branches implementation. 2017-04-17 23:02:58 +03:00
J. David Ibáñez
dd57c9b366 Fixing error on Python 2.7 / Windows 64bits 2017-04-09 13:11:50 +02:00
J. David Ibáñez
f2c89a760a (partial) review the way we handle Python int/long 2017-04-09 12:33:24 +02:00
J. David Ibáñez
f37cf25b8e Fix warning, and coding style a bit 2017-04-08 16:56:04 +02:00
J. David Ibáñez
11ff7a99eb Options, improve error messages 2017-04-08 11:16:15 +02:00
J. David Ibáñez
9335819795 Opening repos, raise more meaningful exceptions 2017-04-05 22:18:21 +02:00
Tamir Bahar
784583d21e Fixed indentation 2017-04-05 21:59:30 +03:00
Tamir Bahar
b81810e9cb Better error messages for opening repos.
Closes #645.
2017-04-05 20:59:36 +03:00
Tamir Bahar
7ee851273a Added explicit check for path = None in init_repository
Closes #688.
2017-04-05 16:37:25 +03:00
Nick Hynes
1fadc2eae0 Wrap branch_is_checked_out 2017-03-29 18:14:46 -04:00
Nick Hynes
453fd8a9a3 Add docs 2017-03-27 17:10:51 -04:00
Nick Hynes
630d905e73 Add stash tests 2017-03-27 17:10:45 -04:00
Nick Hynes
9be907983f Wrap stash_pop 2017-03-27 16:42:38 -04:00
Nick Hynes
b31ac50210 Wrap stash_drop 2017-03-27 16:33:32 -04:00
Nick Hynes
da233b16c5 Wrap git_stash_apply 2017-03-27 16:31:21 -04:00
Nick Hynes
1a842ff8bd Wrap git_stash_save 2017-03-27 16:20:33 -04:00
Nick Hynes
cbbf9f1f87 Fix Signature._pointer 2017-03-27 16:18:21 -04:00
Nick Hynes
a294655aa5 Add declarations for git-stash 2017-03-27 16:18:13 -04:00
J. David Ibáñez
5a940987cd Add support for Python 3.6 2017-03-22 21:45:12 +01:00
J. David Ibáñez
354d56a95c Update copyright years 2017-03-22 21:15:34 +01:00
Jason Ziglar
8327e1bee3 Add test for init_submodules() and update_submodules() 2017-03-22 11:23:17 -04:00
Jason Ziglar
15326b731f Add update_submodules() command 2017-03-22 11:23:17 -04:00
Jason Ziglar
f5cd6da307 Add init_submodules() command 2017-03-22 11:23:17 -04:00
J. David Ibáñez
803b1cb154 cffi 1.10 not yet supported 2017-03-22 16:01:23 +01:00
J. David Ibáñez
d622e87654 test options, avoid side effects
This makes tests in PR#692 to pass
2017-03-22 13:38:11 +01:00
J. David Ibáñez
819cbff552 Remove some tabs 2017-02-09 17:31:50 +01:00
Matthaus Woolard
4fbc1f1c05 Add support for custom backends
Signed-off-by: Matthaus Woolard <matthaus.woolard@gmail.com>
2017-02-09 15:57:56 +00:00
Tamir Bahar
5c061cbb0a Remove unused code
Removed a chunk of code from `checkout` that did nothing, but had a bug.
When checking out from a branch-less state (like the state when a repository is first initialized) the code failed.
The failure was due to trying to get some properties of the current branch, which were never used in the code.
2017-01-03 01:17:48 +02:00
J. David Ibáñez
68817aad4f Release 0.25.0 2016-12-26 12:30:36 +01:00
J. David Ibáñez
0b513d57fa Merge remote-tracking branch 'carlos/next' 2016-12-23 21:37:58 +01:00
Carlos Martín Nieto
074a726d7f Update versions to libgit2 v0.25.0 2016-12-23 20:24:37 +00:00
J. David Ibáñez
950249442e Merge remote-tracking branch 'bisho/master' 2016-12-20 20:02:47 +01:00
Guillermo Pérez
809fe33b8a Make pygit2 throw if tree of a commit is not found
Commit objects in git always have a tree_id associated, that points
to the corresponding Tree object.

When the tree object is missing, the repo is corrupted.

In those cases:
* official git cli fatals with status code 128 and message:
  fatal: unable to read tree <hash>
* libgit2 returns error GIT_ENOTFOUND when calling git_commit_tree()
* pygit2 when accessing the tree by id with repo[commit.tree_id]
raises a KeyError: <hash>

But on the other hand, on the commit object, rather than throwing
and exception, pygit2 is swallowing the error returned by libgit2
and setting the <Commit object>.tree property to None.

None is arguable the wrong choice to encode an error condition,
specially in python that is used heavily.

In particular this caused in our system to assume there was
an empty tree, and the sync service that tails git repo changes
decided to DELETE everything. The code was using None to
represent empty tree, usefull for example when we need to
compare a path between two commits (the path might be non-existant
at one of the commits you are comparing).

I think that in this case the right decision would be to raise
since is an exceptional case, caused by a corrupted repo,
is more consistent with other tools, and ensures user code
does not take the wrong decissions.

For curiosity the corrupted repository can happen more commonly
than expected. We run our repositories on a shared NFS filer,
and one of our servers didn't have the lookupcache=positive
flag. This makes NFS cache the metadata (files on a directory
for example) and use that for negative lookups (to deny existance
of files). In this case, the commit object was on a directory
not cached, so the commit was seen immediately, but the tree
object was in a folder that was cached, the cache didn't
contained the tree object, and thus for some seconds the tree
was not existing and the repo was corrupted. Our sync service
saw tree being None and decided to delete everything, causing
a lot of issues down the way.
2016-12-19 11:28:00 -08:00
Szucs Krisztian
6402302002 fixed cached memory tests 2016-12-03 14:01:39 +01:00
Szucs Krisztian
77f0585645 Added mwindow_mapped_limit, cached_memory, enable_caching, cache_max_size, cache_object_limit options 2016-12-03 13:52:19 +01:00
Carlos Martín Nieto
acdec78617 Update for v0.24+1 2016-11-14 16:40:36 +01:00
J. David Ibáñez
66280af83a Release 0.24.2 2016-11-01 20:34:50 +01:00
J. David Ibáñez
b2a34bd901 Merge remote-tracking branch 'fourplusone/master' 2016-11-01 13:41:23 +01:00
Matthias Bartelmeß
44ef9ad2e9 Remove python 3.2 from appveyor file since it is not supported 2016-10-30 11:55:36 +01:00
Matthias Bartelmeß
db213113f4 Fix/appveyor all (#1)
* Create python-33.yml

* Delete python-33.yml

* Update appveyor.yml

* Update appveyor.yml

* Update appveyor.yml

* Update appveyor.yml

* Update appveyor.yml

* Update appveyor.yml

* Update appveyor.yml

* Update appveyor.yml

* Update appveyor.yml

* Update appveyor.yml

* Update appveyor.yml

* Use weakref for conflicts caching

To prevent GC issues for python <= 3.3, use a weak reference for Index._conflicts

* Update index.py

* Update appveyor.yml
2016-10-30 12:52:25 +02:00
Robert Hölzl
ee28de65a0 Extend comment of Remote.push by note about push_update_reference.
As happened in support request https://github.com/libgit2/libgit2/issues/3963 it can be easily overseen,
that push returns True, when the remote has installed a hook that denies the commits.
2016-10-23 23:55:53 +02:00
Matthias Bartelmeß
825f3e45bd add slashes to URL if needed 2016-10-21 06:31:19 +03:00
Matthias Bartelmess
00dd78bf1b Fix windows tests 2016-10-21 06:06:40 +03:00
anatoly techtonik
e2393a5e24 appveyor.yml Fix nosetests report upload
/xunit/ endpoint in AppVeyor is made for uploading xUnit.net reports
http://help.appveyor.com/discussions/problems/5264-xunit-results-are-not-being-parsed
2016-10-18 13:51:03 +03:00
anatoly techtonik
da59cb1c92 appveyor.yml Attempt to fix test failure reporting
https://www.appveyor.com/docs/build-configuration/#script-blocks-in-build-configuration
2016-10-18 12:40:05 +03:00
anatoly techtonik
e873c6a363 appveyor.yml Attempt to fix test run
broken by 865c2f0
2016-10-15 20:17:28 +03:00
J. David Ibáñez
865c2f0e82 Revert "Update appveyor.yml"
This reverts commit faf6a63d25d9c12d7480e9b4faf4d6531b13b7c3.
2016-10-14 09:45:34 +02:00
J. David Ibáñez
6d6931cd26 Merge remote-tracking branch 'fourplusone/fix/windows-tests' 2016-10-13 12:26:19 +02:00
J. David Ibáñez
9b364dc7f3 Readme, badge to appveyor 2016-10-07 17:40:25 +02:00
Carlos Martín Nieto
578cf58cd7 Add Repository.create_reference to the automethod list 2016-10-03 20:31:56 +02:00
J. David Ibáñez
554f167353 Merge remote-tracking branch 'mrh/fix-non-ascii-errmsg' 2016-09-15 09:25:08 +02:00
mrh1997
54e4da837b Support non-english errors with non-ascii chars.
Libgit2 partially forwards OS error message texts.
On non-english Windows OSes these errors may contain non-ascii characters (i.e. umlauts).
To avoid that a UnicodeDecodeError is raised the error message is interpreted as UTF-8.
The solution should not be necessary on linux/osx as they return always ascii (as far as I know).
Thus this solution will not change the behaviour on linux/osx.
2016-09-13 22:31:49 +02:00
Matthias Bartelmeß
faf6a63d25 Update appveyor.yml 2016-07-24 22:57:05 +02:00
Matthias Bartelmeß
30980751cf Update appveyor.yml 2016-07-24 22:55:05 +02:00
Matthias Bartelmeß
dae61ded38 Update appveyor.yml 2016-07-24 22:52:41 +02:00
Matthias Bartelmeß
0e270c72bd Update appveyor.yml 2016-07-24 22:12:00 +02:00
Matthias Bartelmeß
1afbde0d7f install dependencies in init script 2016-07-24 21:56:21 +02:00
Matthias Bartelmeß
7fe7a4da8d Remove qoutes from env vars 2016-07-24 21:50:17 +02:00
Matthias Bartelmeß
fd1e9e3d35 Update appveyor.yml
upload test results
2016-07-24 15:54:54 +02:00
Matthias Bartelmeß
cdd57b2c0f make sure the repo object will be collected before the repo is removed 2016-07-22 10:46:11 +02:00
mrh1997
ffc514fa24 Ammend the doc-string of Repository.diff()
According to the old documentation, it was not clear how to compare 
working directory/index to a git object.
2016-07-11 14:41:39 +02:00
Matthias Bartelmeß
c57a3aeb22 install locally 2016-07-03 17:01:26 +02:00
Matthias Bartelmeß
ca444f3c7d Update appveyor.yml 2016-07-03 16:54:40 +02:00
Matthias Bartelmeß
96beae5c82 fix yaml error 2016-07-03 16:15:41 +02:00
Matthias Bartelmeß
68de0f8bb6 fix yaml error 2016-07-03 16:14:26 +02:00
Matthias Bartelmeß
df53551cb2 Build 32 and 64 bit version 2016-07-03 16:13:21 +02:00
Matthias Bartelmeß
5864b17b57 archive wheels 2016-07-03 16:03:05 +02:00
Matthias Bartelmeß
6c4fa88d07 using cd,cd .. instead of popd 2016-07-03 15:49:39 +02:00
Matthias Bartelmeß
e96d0286b8 Create appveyor.yml 2016-07-03 15:41:23 +02:00
J. David Ibáñez
4fa43e234e docs, update version 2016-06-21 23:15:56 +02:00
J. David Ibáñez
4416f65fe1 Release 0.24.1 2016-06-21 23:04:12 +02:00
Ondřej Nový
5dcc793aff Make build reproducible
https://wiki.debian.org/ReproducibleBuilds
2016-06-07 22:33:46 +02:00
J. David Ibáñez
30f539ff35 Merge remote-tracking branch 'seanfarley/smf/pygit2-upgrade' 2016-06-02 16:18:07 +02:00
Carlos Martín Nieto
df30f9213f Remove checks for obsolete methods
This is not how you define your callbacks, so this test isn't testing
for anything useful.
2016-04-29 13:19:32 +02:00
Ondřej Nový
50c0569cf0 Fixed typo 2016-04-18 21:58:58 +02:00
J. David Ibáñez
d8fd2e78d8 Merge remote-tracking branch 'ignatenkobrain/gh620' 2016-04-17 20:48:56 +02:00
Igor Gnatenko
fd9a39a91b repository: decode() linkname
Reference: https://github.com/libgit2/pygit2/issues/620
Signed-off-by: Igor Gnatenko <ignatenko@redhat.com>
2016-04-15 14:13:47 +02:00
Igor Gnatenko
270dad8cd3 repository: SYMTYPE is constant in module tarfile, not in any class
Reference: https://github.com/libgit2/pygit2/issues/618
Signed-off-by: Igor Gnatenko <ignatenko@redhat.com>
2016-04-15 14:07:33 +02:00
Yu Jianjian
51915ddf0e wrong order of the args in docstring of write_archive 2016-03-23 23:33:20 +08:00
Dustin Raimondi
f2864c0511 fix addition occurence of libgit2 version number 2016-03-11 10:24:53 -05:00
Dustin Raimondi
456bf59a88 bump libgit2 version number 2016-03-11 09:38:08 -05:00
J. David Ibáñez
22021c67fc Release 0.24.0 2016-03-05 23:21:05 +01:00
Carlos Martín Nieto
c1d831c98a Update to libgit2 v0.24 2016-03-04 17:08:55 +01:00
J. David Ibáñez
391a3a74e9 Merge remote-tracking branch 'thom/tox' 2016-02-28 17:22:58 +01:00
J. David Ibáñez
141f0abe62 docs: add Repository.path_is_ignored 2016-02-28 14:26:19 +01:00
J. David Ibáñez
6b926494db Merge remote-tracking branch 'ccope/gitignore' 2016-02-28 14:19:35 +01:00
Thom Wiggers
cde5b5170b
Allow testing with tox 2016-02-28 12:53:35 +01:00
Thom Wiggers
735510f14d
Fix repository crash if path passed is not a str
Tries to decode any non-string objects (such as bytes)

Introduces `six` as a dependency

Closes #588
2016-02-28 12:32:51 +01:00
Thom Wiggers
bc424e342f
Add unit tests for bytes and unicode Repositories
Add unit test for bytes repository paths
Add a unicode path test for Repositories
2016-02-28 12:32:41 +01:00
Thom Wiggers
3470fbc1c6
Add unit test for bytes repository paths 2016-02-27 23:44:05 +01:00
Carlos Martín Nieto
487fb5913e Keep the describe dirty suffix string alive 2016-02-25 08:04:27 +01:00
J. David Ibáñez
33cf1a1ca2 travis: test with Python 3.5 too 2016-01-31 14:14:07 +01:00
Cam Cope
95ad6b1b0a add method to check if a path is ignored 2016-01-25 02:54:00 -08:00
Brodie Rao
78d134c016 repository: add listall_reference_objects() method
This allows for efficient reading of many references and their targets,
without incurring the overhead of lookup_reference() (which stats for
a loose ref and then reads packed-refs) which can be expensive on NFS
with thousands of refs.
2014-01-08 15:14:27 -08:00
107 changed files with 2744 additions and 1203 deletions

1
.gitignore vendored

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

@ -18,3 +18,11 @@ 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.23 https://github.com/libgit2/libgit2.git
git clone --depth=1 -b maint/v0.26 https://github.com/libgit2/libgit2.git
cd libgit2/
mkdir build && cd build

@ -2,11 +2,12 @@ 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

859
CHANGELOG.rst Normal file

@ -0,0 +1,859 @@
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,16 +5,19 @@ 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.2, 3.3, 3.4 and
PyPy 2.6
implements Git plumbing. Pygit2 works with Python 2.7, 3.3, 3.4, 3.5, 3.6
and PyPy 2.6
Links:
- http://github.com/libgit2/pygit2 -- Source code and issue tracker
- https://github.com/libgit2/pygit2 -- Source code and issue tracker
- http://www.pygit2.org/ -- Documentation
- http://pypi.python.org/pypi/pygit2 -- Download
- https://pypi.python.org/pypi/pygit2 -- Download
- https://github.com/libgit2/pygit2/blob/master/CHANGELOG.rst -- Changelog
How to install
==============
@ -22,768 +25,50 @@ How to install
- Check http://www.pygit2.org/install.html
Changelog
==============
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>`_
Authors
==============
102 developers have contributed at least 1 commit to pygit2::
117 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 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 Nicolas Dandrimont
David Versmisse Rémi Duraffort Santiago Perez De Rosso
Sebastian Thiel Alok Singhal Fraser Tweedale
Han-Wen Nienhuys Leonardo Rhodes Petr Viktorin
Ron Cohen Thomas Kluyver Alex Chamberlain
Alexander Bayandin Amit Bakshi Andrey Devyatkin
Arno van Lumig 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 Masud Rahman Michael Sondergaard
Sarath Lakshman Vicent Marti Zoran Zaric
Adam Spiers Andrew Chin András Veres-Szentkirályi
Ash Berlin Benjamin Kircher Benjamin Pollack
Bryan O'Sullivan Chason Chaffin Chris Rebert
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
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
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
Eric Davis Erik Meusel Erik van Zijst
Ferengee Guille -bisho- Gustavo Di Pietro
Holger Frey Hugh Cole-Baker Jasper Lievisse Adriaanse
Josh Bleecher Snyder Justin Clift Kyriakos Oikonomakos
Lukas Fleischer Mathieu Bridon Nicolás Sanguinetti
Noah Fontes Óscar San José Peter Dave Hello
Philippe Ombredanne Ridge Kennedy Ross Nicoll
Rui Abreu Ferreira Sheeo Soasme
Vladimir Rutsky chengyuhang earl
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
License

53
appveyor.yml Normal file

@ -0,0 +1,53 @@
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

8
docs/backends.rst Normal file

@ -0,0 +1,8 @@
**********************************************************************
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.

@ -50,9 +50,9 @@ copyright = u'2010-2015 The pygit2 contributors'
# built documents.
#
# The short X.Y version.
version = '0.23'
version = '0.26'
# The full version, including alpha/beta/rc tags.
release = '0.23.3'
release = '0.26.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.

@ -5,6 +5,9 @@ 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

@ -111,5 +111,5 @@ The DiffLine type
.. autoattribute :: pygit2.DiffLine.origin
.. autoattribute :: pygit2.DiffLine.content
.. autoattribute :: pygit2.DiffLine.old_lineno
.. autoattribute :: pygit2.DiffLine.old_lineno
.. autoattribute :: pygit2.DiffLine.new_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.23.3``::
``0.26.0``::
>>> print LIBGIT2_VER_MAJOR
0
@ -26,25 +26,25 @@ 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.23.3``::
``0.26.0``::
>>> print LIBGIT2_VER_MINOR
23
26
.. py:data:: LIBGIT2_VER_REVISION
Integer value of the revision version number. For example, for the version
``0.23.3``::
``0.26.0``::
>>> print LIBGIT2_VER_REVISION
3
0
.. py:data:: LIBGIT2_VERSION
The libgit2 version number as a string::
>>> print LIBGIT2_VERSION
'0.23.3'
'0.26.0'
Errors
======

@ -7,17 +7,18 @@ 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.2, 3.3, 3.4 and
pypy.
implements the core of Git. Pygit2 works with Python 2.7, 3.3, 3.4, 3.5,
3.6 and pypy.
It is likely to work with Python 2.6 and 3.1, but these versions are not
officially supported.
Pygit2 links:
Links:
- http://github.com/libgit2/pygit2 -- Source code and issue tracker
- https://github.com/libgit2/pygit2 -- Source code and issue tracker
- http://www.pygit2.org/ -- Documentation
- http://pypi.python.org/pypi/pygit2 -- Download
- https://pypi.python.org/pypi/pygit2 -- Download
- https://github.com/libgit2/pygit2/blob/master/CHANGELOG.rst -- Changelog
Start:
@ -49,6 +50,7 @@ Usage guide:
blame
settings
features
backends
Indices and tables

@ -13,9 +13,11 @@ Installation
Requirements
============
- Python 2.7, 3.2+ or PyPy 2.6+ (including the development headers)
- Libgit2 v0.23.x
- 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:
@ -41,11 +43,11 @@ while the last number |lq| *.micro* |rq| auto-increments independently.
As illustration see this table of compatible releases:
+-----------+----------------------------------------+--------------------------------+
|**libgit2**| 0.23.0, 0.23.1, 0.23.2, 0.23.3, 0.23.4 | 0.22.0, 0.22.1, 0.22.2, 0.22.3 |
+-----------+----------------------------------------+--------------------------------+
|**pygit2** | 0.23.0, 0.23.1, 0.23.2, 0.23.3 | 0.22.0, 0.22.1 |
+-----------+----------------------------------------+--------------------------------+
+-----------+--------+----------------+------------------------+
|**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 |
+-----------+--------+----------------+------------------------+
.. warning::
@ -62,9 +64,9 @@ directory, do:
.. code-block:: sh
$ wget https://github.com/libgit2/libgit2/archive/v0.23.4.tar.gz
$ tar xzf v0.23.4.tar.gz
$ cd libgit2-0.23.4/
$ wget https://github.com/libgit2/libgit2/archive/v0.26.0.tar.gz
$ tar xzf v0.26.0.tar.gz
$ cd libgit2-0.26.0/
$ cmake .
$ make
$ sudo make install
@ -146,9 +148,9 @@ Install libgit2 (see we define the installation prefix):
.. code-block:: sh
$ wget https://github.com/libgit2/libgit2/archive/v0.23.4.tar.gz
$ tar xzf v0.23.4.tar.gz
$ cd libgit2-0.23.4/
$ wget https://github.com/libgit2/libgit2/archive/v0.26.0.tar.gz
$ tar xzf v0.26.0.tar.gz
$ cd libgit2-0.26.0/
$ cmake . -DCMAKE_INSTALL_PREFIX=$LIBGIT2
$ make
$ make install
@ -184,32 +186,34 @@ everytime. Verify yourself if curious:
.. code-block:: sh
$ readelf --dynamic lib/python2.7/site-packages/pygit2-0.23.0-py2.7-linux-x86_64.egg/_pygit2.so | grep PATH
$ readelf --dynamic lib/python2.7/site-packages/pygit2-0.26.0-py2.7-linux-x86_64.egg/_pygit2.so | grep PATH
0x000000000000001d (RUNPATH) Library runpath: [/tmp/venv/lib]
Installing on Windows
===================================
pygit2 expects to find the libgit2 installed files in the directory specified
in the ``LIBGIT2`` environment variable.
`pygit2` for Windows is packaged into wheels and can be easily
installed with `pip`:
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:
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:
.. code-block:: sh
$ export LIBGIT2=C:/Dev/libgit2
$ wget https://github.com/libgit2/libgit2/archive/v0.23.4.tar.gz
$ tar xzf v0.23.4.tar.gz
$ cd libgit2-0.23.4/
$ git clone --depth=1 -b maint/v0.26 https://github.com/libgit2/libgit2.git
$ cd libgit2
$ 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 above.
At this point, you're ready to execute the generic `pygit2`
installation steps described at the start of this page.
Installing on OS X

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

@ -4,15 +4,25 @@ References
.. contents::
.. automethod:: pygit2.Repository.listall_references
.. automethod:: pygit2.Repository.lookup_reference
.. autoclass:: pygit2.repository.References
:members:
:undoc-members:
:special-members: __getitem__, __iter__, __contains__
Example::
>>> all_refs = repo.listall_references()
>>> all_refs = list(repo.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
====================
@ -68,28 +78,33 @@ Branches
Branches inherit from References, and additionally provide specialized
accessors for some unique features.
.. automethod:: pygit2.Repository.listall_branches
.. automethod:: pygit2.Repository.lookup_branch
.. automethod:: pygit2.Repository.create_branch
.. autoclass:: pygit2.repository.Branches
:members:
:undoc-members:
:special-members: __getitem__, __iter__, __contains__
Example::
>>> local_branches = repo.listall_branches()
>>> # equivalent to
>>> local_branches = repo.listall_branches(pygit2.GIT_BRANCH_LOCAL)
>>> # Listing all branches
>>> branches_list = list(repo.branches)
>>> # Local only
>>> local_branches = list(repo.branches.local)
>>> # Remote only
>>> remote_branches = list(repo.branches.remote)
>>> remote_branches = repo.listall_branches(pygit2.GIT_BRANCH_REMOTE)
>>> # 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
>>> all_branches = repo.listall_branches(pygit2.GIT_BRANCH_REMOTE |
pygit2.GIT_BRANCH_LOCAL)
>>> remote_branch = repo.branches.remote['upstream/feature']
>>> master_branch = repo.lookup_branch('master')
>>> # equivalent to
>>> master_branch = repo.lookup_branch('master',
pygit2.GIT_BRANCH_LOCAL)
>>> # Create a local branch
>>> new_branch = repo.branches.local.create('new-branch')
>>> And delete it
>>> repo.branches.delete('new-branch')
>>> remote_branch = repo.lookup_branch('upstream/feature',
pygit2.GIT_BRANCH_REMOTE)
The Branch type
====================
@ -98,17 +113,19 @@ 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.lookup_reference('refs/heads/master')
>>> 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
>>> for entry in head.log():
... print(entry.message)

@ -67,8 +67,11 @@ 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
.. automethod:: pygit2.Repository.describe

@ -1,10 +1,12 @@
**********************************************************************
The submodule
Submodules
**********************************************************************
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,3 +71,11 @@ 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-2015 The pygit2 contributors
# 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,
@ -105,6 +105,9 @@ 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

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright 2010-2015 The pygit2 contributors
# 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,
@ -37,7 +37,7 @@ from os import getenv
#
# The version number of pygit2
#
__version__ = '0.23.3'
__version__ = '0.26.0'
#

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright 2010-2015 The pygit2 contributors
# 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,

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright 2010-2015 The pygit2 contributors
# 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,

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright 2010-2015 The pygit2 contributors
# 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,

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright 2010-2015 The pygit2 contributors
# 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,

@ -54,6 +54,16 @@ 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,
@ -131,21 +141,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_t cert_type;
git_cert parent;
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,
@ -197,10 +207,30 @@ 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 ...
@ -225,6 +255,8 @@ 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 ...
@ -336,13 +368,20 @@ 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;
void *notify_payload;
git_diff_notify_cb notify_cb;
git_diff_progress_cb progress_cb;
void *payload;
uint32_t context_lines;
uint32_t interhunk_lines;
uint16_t id_abbrev;
@ -371,7 +410,16 @@ int git_diff_tree_to_index(git_diff **diff, git_repository *repo, git_tree *old_
* git_checkout
*/
typedef enum { ... } git_checkout_notify_t;
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 int (*git_checkout_notify_cb)(
git_checkout_notify_t why,
@ -478,11 +526,12 @@ typedef ... git_config;
typedef ... git_config_iterator;
typedef enum {
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_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_HIGHEST_LEVEL = -1,
} git_config_level_t;
@ -671,22 +720,22 @@ typedef struct git_blame_options {
uint16_t min_match_characters;
git_oid newest_commit;
git_oid oldest_commit;
uint32_t min_line;
uint32_t max_line;
size_t min_line;
size_t max_line;
} git_blame_options;
#define GIT_BLAME_OPTIONS_VERSION ...
typedef struct git_blame_hunk {
uint16_t lines_in_hunk;
size_t lines_in_hunk;
git_oid final_commit_id;
uint16_t final_start_line_number;
size_t final_start_line_number;
git_signature *final_signature;
git_oid orig_commit_id;
const char *orig_path;
uint16_t orig_start_line_number;
size_t orig_start_line_number;
git_signature *orig_signature;
char boundary;
@ -695,7 +744,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, uint32_t lineno);
const git_blame_hunk *git_blame_get_hunk_byline(git_blame *blame, size_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);
@ -703,7 +752,12 @@ void git_blame_free(git_blame *blame);
* Merging
*/
typedef enum { ... } git_merge_tree_flag_t;
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_FILE_FAVOR_NORMAL = 0,
@ -714,10 +768,12 @@ typedef enum {
typedef struct {
unsigned int version;
git_merge_tree_flag_t tree_flags;
git_merge_flag_t 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;
@ -737,7 +793,12 @@ typedef enum {
GIT_MERGE_FILE_STYLE_MERGE = 1,
GIT_MERGE_FILE_STYLE_DIFF3 = 2,
GIT_MERGE_FILE_SIMPLIFY_ALNUM = 4,
} git_merge_file_flags_t;
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;
typedef struct {
unsigned int version;
@ -745,7 +806,7 @@ typedef struct {
const char *our_label;
const char *their_label;
git_merge_file_favor_t favor;
git_merge_file_flags_t flags;
git_merge_file_flag_t flags;
} git_merge_file_options;
#define GIT_MERGE_OPTIONS_VERSION ...
@ -756,6 +817,56 @@ 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
*/
@ -811,3 +922,5 @@ 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-2015 The pygit2 contributors
# 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,
@ -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()
message = ffi.string(giterr.message).decode('utf8')
else:
message = "err %d (no message provided)" % err
@ -64,4 +64,6 @@ def check_error(err, io=False):
raise GitError(message)
# Indicate that we want libgit2 to pretend a function was not set
Passthrough = Exception("The function asked for pass-through")
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-2015 The pygit2 contributors
# 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,

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright 2010-2015 The pygit2 contributors
# 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,
@ -28,6 +28,8 @@
# 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
@ -155,6 +157,9 @@ 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:
@ -305,10 +310,12 @@ class Index(object):
self._conflicts = None
return None
if self._conflicts is None:
self._conflicts = ConflictCollection(self)
if self._conflicts is None or self._conflicts() is None:
conflicts = ConflictCollection(self)
self._conflicts = weakref.ref(conflicts)
return conflicts
return self._conflicts
return self._conflicts()
class IndexEntry(object):

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright 2010-2015 The pygit2 contributors
# 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,

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright 2010-2015 The pygit2 contributors
# 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,

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright 2010-2015 The pygit2 contributors
# 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,

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright 2010-2015 The pygit2 contributors
# 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,
@ -278,11 +278,9 @@ class RemoteCallbacks(object):
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:
if e is Passthrough:
return C.GIT_PASSTHROUGH
self._stored_exception = e
return C.GIT_EUSER
@ -308,15 +306,14 @@ class RemoteCallbacks(object):
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:
if e is Passthrough:
if is_ssh:
return 0
elif valid:
return 0
else:
return C.GIT_ECERTIFICATE
self._stored_exception = e
return C.GIT_EUSER
@ -416,6 +413,12 @@ class Remote(object):
"""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 *')

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright 2010-2015 The pygit2 contributors
# 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,
@ -32,17 +32,21 @@ 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
from _pygit2 import Repository as _Repository, init_file_backend
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 Reference, Tree, Commit, Blob
from _pygit2 import GIT_BRANCH_LOCAL, GIT_BRANCH_REMOTE, GIT_BRANCH_ALL
from _pygit2 import Reference, Tree, Commit, Blob, Signature
from .config import Config
from .errors import check_error
@ -54,21 +58,11 @@ from .utils import to_bytes, is_string
from .submodule import Submodule
class Repository(_Repository):
def __init__(self, *args, **kwargs):
super(Repository, self).__init__(*args, **kwargs)
class BaseRepository(_Repository):
def __init__(self, backend, *args, **kwargs):
super(BaseRepository, self).__init__(backend, *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)
@ -275,11 +269,6 @@ class Repository(_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)
@ -318,8 +307,23 @@ class Repository(_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
use staged changes instead of workdir
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.
flag
a GIT_DIFF_* constant
@ -481,6 +485,7 @@ class Repository(_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
@ -527,13 +532,13 @@ class Repository(_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
@ -687,7 +692,11 @@ class Repository(_Repository):
if describe_strategy is not None:
options.describe_strategy = describe_strategy
if pattern:
options.pattern = ffi.new('char[]', to_bytes(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:
@ -716,8 +725,10 @@ class Repository(_Repository):
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:
format_options.dirty_suffix = ffi.new('char[]', to_bytes(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))
@ -731,6 +742,96 @@ class Repository(_Repository):
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
#
@ -759,7 +860,7 @@ class Repository(_Repository):
>>> import tarfile, pygit2
>>>> with tarfile.open('foo.tar', 'w') as archive:
>>>> repo = pygit2.Repsitory('.')
>>>> repo.write_archive(archive, repo.head.target)
>>>> repo.write_archive(repo.head.target, archive)
"""
# Try to get a tree form whatever we got
@ -791,11 +892,11 @@ class Repository(_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 = archive.SYMTYPE
info.linkname = content
info.mode = 0o777 # symlinks get placeholder
info.type = tarfile.SYMTYPE
info.linkname = content.decode("utf-8")
info.mode = 0o777 # symlinks get placeholder
info.size = 0
archive.addfile(info)
else:
@ -899,3 +1000,130 @@ class Repository(_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-2015 The pygit2 contributors
# 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,
@ -28,6 +28,11 @@
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):
@ -64,3 +69,36 @@ 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-2015 The pygit2 contributors
# 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,

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright 2010-2015 The pygit2 contributors
# 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,

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# coding: UTF-8
#
# Copyright 2010-2015 The pygit2 contributors
# 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,
@ -61,17 +61,10 @@ if cffi_major_version == 0:
ffi.verify(preamble, **C_KEYWORDS)
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 listdir('src')
pygit2_exts = [os.path.join('src', name) for name in sorted(listdir('src'))
if name.endswith('.c')]
@ -108,7 +101,8 @@ class TestCommand(Command):
class sdist_files_from_git(sdist):
def get_file_list(self):
popen = Popen(['git', 'ls-files'], stdout=PIPE, stderr=PIPE)
popen = Popen(['git', 'ls-files'], stdout=PIPE, stderr=PIPE,
universal_newlines=True)
stdoutdata, stderrdata = popen.communicate()
if popen.returncode != 0:
print(stderrdata)
@ -186,7 +180,7 @@ extra_args = {
if cffi_major_version == 0:
extra_args['ext_modules'].append(ffi.verifier.get_extension())
else:
extra_args['cffi_modules']=['pygit2/_run.py:ffi']
extra_args['cffi_modules'] = ['pygit2/_run.py:ffi']
setup(name='pygit2',
@ -196,13 +190,13 @@ 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'],
install_requires=['cffi', 'six'],
zip_safe=False,
cmdclass=cmdclass,
**extra_args)

@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 The pygit2 contributors
* 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,
@ -133,7 +133,7 @@ PyDoc_STRVAR(Blob_size__doc__, "Size.");
PyObject *
Blob_size__get__(Blob *self)
{
return PyLong_FromLongLong(git_blob_rawsize(self->blob));
return PyInt_FromLongLong(git_blob_rawsize(self->blob));
}

@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 The pygit2 contributors
* 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,

@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 The pygit2 contributors
* 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,
@ -81,6 +81,28 @@ 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"
@ -234,6 +256,7 @@ 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-2015 The pygit2 contributors
* 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,
@ -34,6 +34,7 @@
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-2015 The pygit2 contributors
* 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,
@ -35,6 +35,7 @@
#include "oid.h"
extern PyTypeObject TreeType;
extern PyObject *GitError;
PyDoc_STRVAR(Commit_message_encoding__doc__, "Message encoding.");
@ -79,7 +80,7 @@ PyDoc_STRVAR(Commit_commit_time__doc__, "Commit time.");
PyObject *
Commit_commit_time__get__(Commit *commit)
{
return PyLong_FromLongLong(git_commit_time(commit->commit));
return PyInt_FromLongLong(git_commit_time(commit->commit));
}
@ -88,7 +89,7 @@ PyDoc_STRVAR(Commit_commit_time_offset__doc__, "Commit time offset.");
PyObject *
Commit_commit_time_offset__get__(Commit *commit)
{
return PyLong_FromLong(git_commit_time_offset(commit->commit));
return PyInt_FromLong(git_commit_time_offset(commit->commit));
}
@ -131,8 +132,11 @@ Commit_tree__get__(Commit *commit)
int err;
err = git_commit_tree(&tree, commit->commit);
if (err == GIT_ENOTFOUND)
Py_RETURN_NONE;
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 < 0)
return Error_set(err);

@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 The pygit2 contributors
* 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,

@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 The pygit2 contributors
* 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,
@ -587,7 +587,7 @@ PyDoc_STRVAR(DiffStats_insertions__doc__, "Total number of insertions");
PyObject *
DiffStats_insertions__get__(DiffStats *self)
{
return PyLong_FromSize_t(git_diff_stats_insertions(self->stats));
return PyInt_FromSize_t(git_diff_stats_insertions(self->stats));
}
PyDoc_STRVAR(DiffStats_deletions__doc__, "Total number of deletions");
@ -595,7 +595,7 @@ PyDoc_STRVAR(DiffStats_deletions__doc__, "Total number of deletions");
PyObject *
DiffStats_deletions__get__(DiffStats *self)
{
return PyLong_FromSize_t(git_diff_stats_deletions(self->stats));
return PyInt_FromSize_t(git_diff_stats_deletions(self->stats));
}
PyDoc_STRVAR(DiffStats_files_changed__doc__, "Total number of files changed");
@ -603,7 +603,7 @@ PyDoc_STRVAR(DiffStats_files_changed__doc__, "Total number of files changed");
PyObject *
DiffStats_files_changed__get__(DiffStats *self)
{
return PyLong_FromSize_t(git_diff_stats_files_changed(self->stats));
return PyInt_FromSize_t(git_diff_stats_files_changed(self->stats));
}
PyDoc_STRVAR(DiffStats_format__doc__,
@ -805,10 +805,10 @@ Diff_getitem(Diff *self, PyObject *value)
{
size_t i;
if (!PyLong_Check(value))
return NULL;
if (!PyInt_Check(value))
return NULL; /* FIXME Raise error */
i = PyLong_AsUnsignedLong(value);
i = PyInt_AsSize_t(value);
return diff_get_patch_byindex(self->diff, i);
}

@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 The pygit2 contributors
* 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,

@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 The pygit2 contributors
* 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,
@ -126,3 +126,10 @@ 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-2015 The pygit2 contributors
* 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,
@ -37,5 +37,6 @@ 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-2015 The pygit2 contributors
* 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,

@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 The pygit2 contributors
* 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,

@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 The pygit2 contributors
* 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,
@ -97,7 +97,7 @@ PyDoc_STRVAR(Object_type__doc__,
PyObject *
Object_type__get__(Object *self)
{
return PyLong_FromLong(git_object_type(self->obj));
return PyInt_FromLong(git_object_type(self->obj));
}
PyDoc_STRVAR(Object__pointer__doc__, "Get the object's pointer. For internal use only.");
@ -143,14 +143,15 @@ PyDoc_STRVAR(Object_peel__doc__,
PyObject *
Object_peel(Object *self, PyObject *py_type)
{
int type = -1, err;
int err;
git_otype otype;
git_object *peeled;
type = py_object_to_object_type(py_type);
if (type == -1)
otype = py_object_to_otype(py_type);
if (otype == GIT_OBJ_BAD)
return NULL;
err = git_object_peel(&peeled, self->obj, (git_otype)type);
err = git_object_peel(&peeled, self->obj, otype);
if (err < 0)
return Error_set(err);

@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 The pygit2 contributors
* 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,

@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 The pygit2 contributors
* 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,
@ -209,8 +209,10 @@ Oid_init(Oid *self, PyObject *args, PyObject *kw)
Py_hash_t
Oid_hash(PyObject *oid)
{
/* TODO Randomize (use _Py_HashSecret) to avoid collission DoS attacks? */
return *(Py_hash_t*) ((Oid*)oid)->oid.id;
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;
}

@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 The pygit2 contributors
* 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,

@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 The pygit2 contributors
* 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,
@ -65,10 +65,11 @@ option(PyObject *self, PyObject *args)
if (!py_option)
return NULL;
if (!PyLong_Check(py_option))
goto on_non_integer;
if (!PyInt_Check(py_option))
return Error_type_error(
"option should be an integer, got %.200s", py_option);
option = PyLong_AsLong(py_option);
option = PyInt_AsLong(py_option);
switch (option) {
case GIT_OPT_GET_SEARCH_PATH:
@ -79,11 +80,11 @@ option(PyObject *self, PyObject *args)
if (!py_level)
return NULL;
if (!PyLong_Check(py_level))
goto on_non_integer;
if (!PyInt_Check(py_level))
return Error_type_error(
"level should be an integer, got %.200s", py_level);
return get_search_path(PyLong_AsLong(py_level));
break;
return get_search_path(PyInt_AsLong(py_level));
}
case GIT_OPT_SET_SEARCH_PATH:
@ -100,23 +101,22 @@ option(PyObject *self, PyObject *args)
if (!py_path)
return NULL;
if (!PyLong_Check(py_level))
goto on_non_integer;
if (!PyInt_Check(py_level))
return Error_type_error(
"level should be an integer, got %.200s", py_level);
path = py_str_borrow_c_str(&tpath, py_path, NULL);
if (!path)
return NULL;
err = git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, PyLong_AsLong(py_level), path);
err = git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, PyInt_AsLong(py_level), path);
Py_DECREF(tpath);
if (err < 0) {
Error_set(err);
return NULL;
}
if (err < 0)
return Error_set(err);
Py_RETURN_NONE;
break;
}
case GIT_OPT_GET_MWINDOW_SIZE:
@ -124,14 +124,10 @@ option(PyObject *self, PyObject *args)
size_t size;
error = git_libgit2_opts(GIT_OPT_GET_MWINDOW_SIZE, &size);
if (error < 0) {
Error_set(error);
return NULL;
}
if (error < 0)
return Error_set(error);
return PyLong_FromSize_t(size);
break;
return PyInt_FromSize_t(size);
}
case GIT_OPT_SET_MWINDOW_SIZE:
@ -143,25 +139,141 @@ option(PyObject *self, PyObject *args)
if (!py_size)
return NULL;
if (!PyLong_Check(py_size))
goto on_non_integer;
if (!PyInt_Check(py_size))
return Error_type_error(
"size should be an integer, got %.200s", py_size);
size = PyLong_AsSize_t(py_size);
size = PyInt_AsSize_t(py_size);
error = git_libgit2_opts(GIT_OPT_SET_MWINDOW_SIZE, size);
if (error < 0) {
Error_set(error);
return NULL;
}
if (error < 0)
return Error_set(error);
Py_RETURN_NONE;
break;
}
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)
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;
}
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-2015 The pygit2 contributors
* 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,

@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 The pygit2 contributors
* 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,

@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 The pygit2 contributors
* 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,

@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 The pygit2 contributors
* 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,
@ -144,7 +144,44 @@ 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__},
@ -170,6 +207,12 @@ 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);
@ -260,6 +303,7 @@ 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
@ -386,6 +430,14 @@ moduleinit(PyObject* m)
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-2015 The pygit2 contributors
* 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,
@ -325,7 +325,7 @@ Reference_type__get__(Reference *self)
CHECK_REFERENCE(self);
c_type = git_reference_type(self->reference);
return PyLong_FromLong(c_type);
return PyInt_FromLong(c_type);
}
@ -379,7 +379,8 @@ PyDoc_STRVAR(Reference_peel__doc__,
PyObject *
Reference_peel(Reference *self, PyObject *args)
{
int err, type;
int err;
git_otype otype;
git_object *obj;
PyObject *py_type = Py_None;
@ -388,11 +389,11 @@ Reference_peel(Reference *self, PyObject *args)
if (!PyArg_ParseTuple(args, "|O", &py_type))
return NULL;
type = py_object_to_object_type(py_type);
if (type == -1)
otype = py_object_to_otype(py_type);
if (otype == GIT_OBJ_BAD)
return NULL;
err = git_reference_peel(&obj, self->reference, type);
err = git_reference_peel(&obj, self->reference, otype);
if (err < 0)
return Error_set(err);

@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 The pygit2 contributors
* 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,

@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 The pygit2 contributors
* 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,
@ -88,8 +88,7 @@ wrap_repository(git_repository *c_repo)
int
Repository_init(Repository *self, PyObject *args, PyObject *kwds)
{
char *path;
int err;
PyObject *backend;
if (kwds && PyDict_Size(kwds) > 0) {
PyErr_SetString(PyExc_TypeError,
@ -97,15 +96,16 @@ Repository_init(Repository *self, PyObject *args, PyObject *kwds)
return -1;
}
if (!PyArg_ParseTuple(args, "s", &path))
return -1;
err = git_repository_open(&self->repo, path);
if (err < 0) {
Error_set_str(err, path);
if (!PyArg_ParseTuple(args, "O", &backend)) {
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,6 +349,26 @@ 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"
@ -842,38 +862,17 @@ 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.");
int read_chunk(char *content, size_t max_length, void *payload)
{
PyObject *py_file;
PyObject *py_bytes;
char *bytes;
Py_ssize_t size;
py_file = (PyObject *)payload;
py_bytes = PyObject_CallMethod(py_file, "read", "i", max_length);
if (!py_bytes)
return -1;
size = 0;
if (py_bytes != Py_None) {
bytes = PyBytes_AsString(py_bytes);
size = PyBytes_Size(py_bytes);
memcpy(content, bytes, size);
}
Py_DECREF(py_bytes);
return size;
}
PyObject *
Repository_create_blob_fromiobase(Repository *self, PyObject *py_file)
{
git_writestream *stream;
git_oid oid;
PyObject *py_is_readable;
int is_readable;
@ -895,8 +894,47 @@ Repository_create_blob_fromiobase(Repository *self, PyObject *py_file)
return NULL;
}
err = git_blob_create_fromchunks(&oid, self->repo, NULL, &read_chunk,
py_file);
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);
@ -1103,6 +1141,56 @@ 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"
@ -1199,6 +1287,141 @@ 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"
@ -1340,7 +1563,7 @@ Repository_status(Repository *self)
path = entry->head_to_index->old_file.path;
else
path = entry->index_to_workdir->old_file.path;
status = PyLong_FromLong((long) entry->status);
status = PyInt_FromLong((long) entry->status);
err = PyDict_SetItemString(dict, path, status);
Py_CLEAR(status);
@ -1382,7 +1605,7 @@ Repository_status_file(Repository *self, PyObject *value)
free(path);
return err_obj;
}
return PyLong_FromLong(status);
return PyInt_FromLong(status);
}
@ -1555,8 +1778,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 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_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_HARD: resets head to point to oid, and resets too the working copy and the content of the index.\n");
PyObject *
@ -1623,7 +1846,10 @@ 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),
@ -1633,6 +1859,7 @@ 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),
@ -1657,7 +1884,7 @@ PyGetSetDef Repository_getseters[] = {
PyDoc_STRVAR(Repository__doc__,
"Repository(path) -> Repository\n"
"Repository(backend) -> Repository\n"
"\n"
"Git repository.");

@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 The pygit2 contributors
* 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,
@ -58,6 +58,8 @@ 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-2015 The pygit2 contributors
* 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,
@ -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__(Repository *self)
Signature__pointer__get__(Signature *self)
{
/* Bytes means a raw buffer */
return PyBytes_FromStringAndSize((char *) &self->repo, sizeof(git_repository *));
return PyBytes_FromStringAndSize((char *) &self->signature, sizeof(git_signature *));
}
PyDoc_STRVAR(Signature__encoding__doc__, "Encoding.");
@ -158,7 +158,7 @@ PyDoc_STRVAR(Signature_time__doc__, "Unix time.");
PyObject *
Signature_time__get__(Signature *self)
{
return PyLong_FromLongLong(self->signature->when.time);
return PyInt_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 PyLong_FromLong(self->signature->when.offset);
return PyInt_FromLong(self->signature->when.offset);
}
PyGetSetDef Signature_getseters[] = {

@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 The pygit2 contributors
* 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,

@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 The pygit2 contributors
* 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,

@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 The pygit2 contributors
* 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,

@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 The pygit2 contributors
* 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,
@ -54,7 +54,7 @@ PyDoc_STRVAR(TreeEntry_filemode__doc__, "Filemode.");
PyObject *
TreeEntry_filemode__get__(TreeEntry *self)
{
return PyLong_FromLong(git_tree_entry_filemode(self->entry));
return PyInt_FromLong(git_tree_entry_filemode(self->entry));
}
@ -290,7 +290,7 @@ Tree_fix_index(Tree *self, PyObject *py_index)
size_t len;
long slen;
index = PyLong_AsLong(py_index);
index = PyInt_AsLong(py_index);
if (PyErr_Occurred())
return -1;
@ -359,7 +359,7 @@ Tree_getitem(Tree *self, PyObject *value)
int err;
/* Case 1: integer */
if (PyLong_Check(value))
if (PyInt_Check(value))
return Tree_getitem_by_index(self, value);
/* Case 2: byte or text string */

@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 The pygit2 contributors
* 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,

@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 The pygit2 contributors
* 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,

@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 The pygit2 contributors
* 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,

@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 The pygit2 contributors
* 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,
@ -32,8 +32,8 @@
#include <Python.h>
#include <git2.h>
#if !(LIBGIT2_VER_MAJOR == 0 && LIBGIT2_VER_MINOR == 23)
#error You need a compatible libgit2 version (v0.23.x)
#if !(LIBGIT2_VER_MAJOR == 0 && LIBGIT2_VER_MINOR == 26)
#error You need a compatible libgit2 version (v0.26.x)
#endif
/*

@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 The pygit2 contributors
* 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,
@ -83,8 +83,7 @@ py_str_borrow_c_str(PyObject **tvalue, PyObject *value, const char *encoding)
}
/* Type error */
PyErr_Format(PyExc_TypeError, "unexpected %.200s",
Py_TYPE(value)->tp_name);
Error_type_error("unexpected %.200s", value);
return NULL;
}
@ -94,7 +93,7 @@ py_str_borrow_c_str(PyObject **tvalue, PyObject *value, const char *encoding)
PyObject *
get_pylist_from_git_strarray(git_strarray *strarray)
{
int index;
size_t index;
PyObject *new_list;
new_list = PyList_New(strarray->count);
@ -161,40 +160,39 @@ on_error:
static git_otype
py_type_to_git_type(PyTypeObject *py_type)
{
git_otype type = GIT_OBJ_BAD;
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;
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;
PyErr_SetString(PyExc_ValueError, "invalid target type");
return GIT_OBJ_BAD; /* -1 */
}
int
py_object_to_object_type(PyObject *py_type)
git_otype
py_object_to_otype(PyObject *py_type)
{
int type = -1;
long value;
if (py_type == Py_None)
return GIT_OBJ_ANY;
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 (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 (type == -1) {
PyErr_SetString(PyExc_ValueError, "invalid target type");
}
if (PyType_Check(py_type))
return py_type_to_git_type((PyTypeObject *) py_type);
return type;
PyErr_SetString(PyExc_ValueError, "invalid target type");
return GIT_OBJ_BAD; /* -1 */
}

@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 The pygit2 contributors
* 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,
@ -40,14 +40,17 @@
#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 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 PyInt_AsSize_t (size_t)PyInt_AsLong
#define PyInt_FromLongLong PyInt_FromLong
#define PyBytes_AS_STRING PyString_AS_STRING
#define PyBytes_AsString PyString_AsString
#define PyBytes_AsStringAndSize PyString_AsStringAndSize
@ -58,20 +61,18 @@
#define to_path(x) to_bytes(x)
#define to_encoding(x) to_bytes(x)
#else
#define PyInteger_Type PyLong_Type
#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 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) {\
@ -120,7 +121,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_object_type(PyObject *py_type);
int py_object_to_otype(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-2015 The pygit2 contributors
* 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,
@ -98,13 +98,13 @@ PyDoc_STRVAR(Walker_sort__doc__,
PyObject *
Walker_sort(Walker *self, PyObject *py_sort_mode)
{
int sort_mode;
long sort_mode;
sort_mode = (int)PyLong_AsLong(py_sort_mode);
sort_mode = PyInt_AsLong(py_sort_mode);
if (sort_mode == -1 && PyErr_Occurred())
return NULL;
git_revwalk_sorting(self->walk, sort_mode);
git_revwalk_sorting(self->walk, (unsigned int)sort_mode);
Py_RETURN_NONE;
}

@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 The pygit2 contributors
* 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,

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2015 The pygit2 contributors
# 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,

Binary file not shown.

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2015 The pygit2 contributors
# 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,

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2015 The pygit2 contributors
# 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,

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2015 The pygit2 contributors
# 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,

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2015 The pygit2 contributors
# 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,

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2015 The pygit2 contributors
# 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,
@ -39,6 +39,135 @@ 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')
@ -88,6 +217,14 @@ 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')
@ -159,6 +296,7 @@ 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-2015 The pygit2 contributors
# 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,

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2015 The pygit2 contributors
# 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,

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2015 The pygit2 contributors
# 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,
@ -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, 5)
config.add_file(CONFIG_FILENAME, 6)
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-2015 The pygit2 contributors
# 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,

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2015 The pygit2 contributors
# 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,

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2015 The pygit2 contributors
# 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,

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2015 The pygit2 contributors
# 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,

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2015 The pygit2 contributors
# 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,

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2015 The pygit2 contributors
# 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,

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2015 The pygit2 contributors
# 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,

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2015 The pygit2 contributors
# 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,

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2015 The pygit2 contributors
# 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,
@ -31,24 +31,81 @@ from __future__ import absolute_import
from __future__ import unicode_literals
import unittest
import pygit2
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 (
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 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):
new_size = 200 * 1024
option(GIT_OPT_SET_MWINDOW_SIZE, new_size)
self.assertEqual(new_size, option(GIT_OPT_GET_MWINDOW_SIZE))
self.__option(
GIT_OPT_GET_MWINDOW_SIZE,
GIT_OPT_SET_MWINDOW_SIZE,
200 * 1024)
def test_mwindow_size_proxy(self):
new_size = 300 * 1024
pygit2.settings.mwindow_size = new_size
self.__proxy('mwindow_size', 300 * 1024)
self.assertEqual(new_size, pygit2.settings.mwindow_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)
def test_search_path(self):
paths = [(GIT_CONFIG_LEVEL_GLOBAL, '/tmp/global'),

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2015 The pygit2 contributors
# 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,
@ -35,12 +35,213 @@ 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
@ -69,12 +270,10 @@ 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')
@ -87,17 +286,14 @@ 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')
@ -140,7 +336,6 @@ 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',
@ -149,17 +344,16 @@ class ReferencesTest(utils.RepoTestCase):
reference.rename('refs/tags/version2')
self.assertEqual(reference.name, 'refs/tags/version2')
# def test_reload(self):
# name = 'refs/tags/version1'
# 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')
# 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):
@ -169,13 +363,11 @@ 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',
@ -194,7 +386,6 @@ 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
@ -204,7 +395,6 @@ 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')
@ -215,9 +405,8 @@ 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-2015 The pygit2 contributors
# 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,
@ -33,6 +33,7 @@ import pygit2
import sys
from pygit2 import Oid
from . import utils
import gc
try:
import __pypy__
@ -188,21 +189,6 @@ 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]
@ -253,6 +239,11 @@ 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)

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2015 The pygit2 contributors
# 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,
@ -39,6 +39,14 @@ import os
from os.path import join, realpath
import sys
import six
if six.PY2:
from urllib import pathname2url
if six.PY3:
from urllib.request import pathname2url
# Import from pygit2
from pygit2 import GIT_OBJ_ANY, GIT_OBJ_BLOB, GIT_OBJ_COMMIT
from pygit2 import init_repository, clone_repository, discover_repository
@ -190,8 +198,8 @@ class RepositoryTest(utils.BareRepoTestCase):
def test_hashfile(self):
data = "bazbarfoo"
tempfile_path = tempfile.mkstemp()[1]
with open(tempfile_path, 'w') as fh:
handle, tempfile_path = tempfile.mkstemp()
with os.fdopen(handle, 'w') as fh:
fh.write(data)
hashed_sha1 = hashfile(tempfile_path)
os.unlink(tempfile_path)
@ -414,6 +422,41 @@ class RepositoryTest_II(utils.RepoTestCase):
self.assertTrue("hola mundo\n" in diff.patch)
self.assertTrue("bonjour le monde\n" in diff.patch)
def test_stash(self):
# some changes to working dir
with open(os.path.join(self.repo.workdir, 'hello.txt'), 'w') as f:
f.write('new content')
sig = pygit2.Signature('Stasher', 'stasher@example.com')
self.repo.stash(sig, include_untracked=True)
self.assertFalse('hello.txt' in self.repo.status())
self.repo.stash_apply()
self.assertTrue('hello.txt' in self.repo.status())
self.repo.stash_drop()
self.assertRaises(KeyError, self.repo.stash_pop)
def test_revert(self):
master = self.repo.head.peel()
commit_to_revert = self.repo['4ec4389a8068641da2d6578db0419484972284c8']
parent = commit_to_revert.parents[0]
commit_diff_stats = (
parent.tree.diff_to_tree(commit_to_revert.tree).stats
)
revert_index = self.repo.revert_commit(commit_to_revert, master)
revert_diff_stats = revert_index.diff_to_tree(master.tree).stats
self.assertEquals(
revert_diff_stats.insertions, commit_diff_stats.deletions
)
self.assertEquals(
revert_diff_stats.deletions, commit_diff_stats.insertions
)
self.assertEquals(
revert_diff_stats.files_changed, commit_diff_stats.files_changed
)
class RepositorySignatureTest(utils.RepoTestCase):
def test_default_signature(self):
@ -482,6 +525,18 @@ class EmptyRepositoryTest(utils.EmptyRepoTestCase):
self.assertFalse(self.repo.head_is_detached)
class StringTypesRepositoryTest(utils.NoRepoTestCase):
def test_bytes_string(self):
repo_path = b'./test/data/testrepo.git/'
pygit2.Repository(repo_path)
def test_unicode_string(self):
# String is unicode because of unicode_literals
repo_path = './test/data/testrepo.git/'
pygit2.Repository(repo_path)
class CloneRepositoryTest(utils.NoRepoTestCase):
def test_clone_repository(self):
@ -499,7 +554,12 @@ class CloneRepositoryTest(utils.NoRepoTestCase):
def test_clone_repository_and_remote_callbacks(self):
src_repo_relpath = "./test/data/testrepo.git/"
repo_path = os.path.join(self._temp_dir, "clone-into")
url = 'file://' + os.path.realpath(src_repo_relpath)
url = pathname2url(os.path.realpath(src_repo_relpath))
if url.startswith('///'):
url = 'file:' + url
else:
url = 'file://' + url
def create_repository(path, bare):
return init_repository(path, bare)

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2015 The pygit2 contributors
# 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,

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2015 The pygit2 contributors
# 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,

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