Codebase list python-git / abf3e12
New upstream version 2.1.9 TANIGUCHI Takaki 5 years ago
47 changed file(s) with 166 addition(s) and 271 deletion(s). Raw diff Collapse all Expand all
00 Metadata-Version: 1.2
11 Name: GitPython
2 Version: 2.1.8
2 Version: 2.1.9
33 Summary: Python Git Library
44 Home-page: https://github.com/gitpython-developers/GitPython
55 Author: Sebastian Thiel, Michael Trier
1818 Classifier: Operating System :: MacOS :: MacOS X
1919 Classifier: Programming Language :: Python
2020 Classifier: Programming Language :: Python :: 2
21 Classifier: Programming Language :: Python :: 2.6
2221 Classifier: Programming Language :: Python :: 2.7
2322 Classifier: Programming Language :: Python :: 3
24 Classifier: Programming Language :: Python :: 3.3
2523 Classifier: Programming Language :: Python :: 3.4
2624 Classifier: Programming Language :: Python :: 3.5
2725 Classifier: Programming Language :: Python :: 3.6
2826 Requires: gitdb2 (>=2.0.0)
29 Requires-Python: >=2.6, !=3.0.*, !=3.1.*, !=3.2.*
27 Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
2828 git/db.py
2929 git/diff.py
3030 git/exc.py
31 git/odict.py
3231 git/remote.py
3332 git/util.py
3433 git/index/__init__.py
00 Metadata-Version: 1.2
11 Name: GitPython
2 Version: 2.1.8
2 Version: 2.1.9
33 Summary: Python Git Library
44 Home-page: https://github.com/gitpython-developers/GitPython
55 Author: Sebastian Thiel, Michael Trier
1818 Classifier: Operating System :: MacOS :: MacOS X
1919 Classifier: Programming Language :: Python
2020 Classifier: Programming Language :: Python :: 2
21 Classifier: Programming Language :: Python :: 2.6
2221 Classifier: Programming Language :: Python :: 2.7
2322 Classifier: Programming Language :: Python :: 3
24 Classifier: Programming Language :: Python :: 3.3
2523 Classifier: Programming Language :: Python :: 3.4
2624 Classifier: Programming Language :: Python :: 3.5
2725 Classifier: Programming Language :: Python :: 3.6
2826 Requires: gitdb2 (>=2.0.0)
29 Requires-Python: >=2.6, !=3.0.*, !=3.1.*, !=3.2.*
27 Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
1818 the `GIT_PYTHON_GIT_EXECUTABLE=<path/to/git>` environment variable.
1919
2020 * Git (1.7.x or newer)
21 * Python 2.7 to 3.6, while python 2.6 is supported on a *best-effort basis*.
21 * Python 2.7 to 3.6.
2222
2323 The list of dependencies are listed in `./requirements.txt` and `./test-requirements.txt`.
2424 The installer takes care of installing them for you.
6666 For *Windows*, we do regularly test it on [Appveyor CI](https://www.appveyor.com/)
6767 but not all test-cases pass - you may help improve them by exploring
6868 [Issue #525](https://github.com/gitpython-developers/GitPython/issues/525).
69
70 #### Python 2.6
71
72 Python 2.6 is supported on best-effort basis; which means that it is likely to deteriorate over time.
7369
7470 ### RUNNING TESTS
7571
131127 this project:
132128
133129 ```
134 curl https://pypi.python.org/packages/7e/13/2a556eb97dcf498c915e5e04bb82bf74e07bb8b7337ca2be49bfd9fb6313/GitPython-2.1.5-py2.py3-none-any.whl\#md5\=d3ecb26cb22753f4414f75f721f6f626z > gitpython.whl
135 curl https://pypi.python.org/packages/7e/13/2a556eb97dcf498c915e5e04bb82bf74e07bb8b7337ca2be49bfd9fb6313/GitPython-2.1.5-py2.py3-none-any.whl.asc > gitpython-signature.asc
130 curl https://pypi.python.org/packages/5b/38/0433c06feebbfbb51d644129dbe334031c33d55af0524326266f847ae907/GitPython-2.1.8-py2.py3-none-any.whl#md5=6b73ae86ee2dbab6da8652b2d875013a > gitpython.whl
131 curl https://pypi.python.org/packages/5b/38/0433c06feebbfbb51d644129dbe334031c33d55af0524326266f847ae907/GitPython-2.1.8-py2.py3-none-any.whl.asc > gitpython-signature.asc
136132 gpg --verify gitpython-signature.asc gitpython.whl
137133 ```
138134
139135 which outputs
140136
141137 ```
142 gpg: Signature made Sat Jun 10 20:22:49 2017 CEST using RSA key ID 3B07188F
143 gpg: Good signature from "Sebastian Thiel (In Rust I trust!) <byronimo@gmail.com>" [unknown]
144 gpg: WARNING: This key is not certified with a trusted signature!
145 gpg: There is no indication that the signature belongs to the owner.
146 Primary key fingerprint: 4477 ADC5 977D 7C60 D2A7 E378 9FEE 1C6A 3B07 188F
138 gpg: Signature made Mon Dec 11 17:34:17 2017 CET
139 gpg: using RSA key C3BC52BD76E2C23BAC6EC06A665F99FA9D99966C
140 gpg: issuer "byronimo@gmail.com"
141 gpg: Good signature from "Sebastian Thiel (I do trust in Rust!) <byronimo@gmail.com>" [ultimate]
147142 ```
148143
149144 You can verify that the keyid indeed matches the release-signature key provided in this
163158
164159 ```
165160 gpg --import ./release-verification-key.asc
166 gpg --edit-key 9FEE1C6A3B07188F
161 gpg --edit-key 88710E60
162
167163 > sign
168164 > save
169 ```
170
171 Afterwards verifying the tarball will yield the following:
172 ```
173 $ gpg --verify gitpython-signature.asc gitpython.whl
174 gpg: Signature made Sat Jun 10 20:22:49 2017 CEST using RSA key ID 3B07188F
175 gpg: Good signature from "Sebastian Thiel (In Rust I trust!) <byronimo@gmail.com>" [ultimate]
176165 ```
177166
178167 ### LICENSE
0 2.1.8
0 2.1.9
11 Changelog
22 =========
33
4 2.1.9 - Dropping support for Python 2.6
5 =======================================
6
7 see the following for (most) details:
8 https://github.com/gitpython-developers/gitpython/milestone/24?closed=1
9
10 or run have a look at the difference between tags v2.1.8 and v2.1.9:
11 https://github.com/gitpython-developers/GitPython/compare/2.1.8...2.1.9
12
13
414 2.1.8 - bugfixes
515 ====================================
616
7 See the following for (most) details:
8 https://github.com/gitpython-developers/GitPython/milestone/23?closed=1
17 see the following for (most) details:
18 https://github.com/gitpython-developers/gitpython/milestone/23?closed=1
919
1020 or run have a look at the difference between tags v2.1.7 and v2.1.8:
1121 https://github.com/gitpython-developers/GitPython/compare/2.1.7...2.1.8
160170 with large repositories.
161171 * CRITICAL: fixed incorrect `Commit` object serialization when authored or commit date had timezones which were not
162172 divisiblej by 3600 seconds. This would happen if the timezone was something like `+0530` for instance.
163 * A list of all additional fixes can be found `on github <https://github.com/gitpython-developers/GitPython/issues?q=milestone%3A%22v1.0.2+-+Fixes%22+is%3Aclosed>`_
173 * A list of all additional fixes can be found `on GitHub <https://github.com/gitpython-developers/GitPython/issues?q=milestone%3A%22v1.0.2+-+Fixes%22+is%3Aclosed>`_
164174 * CRITICAL: `Tree.cache` was removed without replacement. It is technically impossible to change individual trees and expect their serialization results to be consistent with what *git* expects. Instead, use the `IndexFile` facilities to adjust the content of the staging area, and write it out to the respective tree objects using `IndexFile.write_tree()` instead.
165175
166176 1.0.1 - Fixes
167177 =============
168178
169 * A list of all issues can be found `on github <https://github.com/gitpython-developers/GitPython/issues?q=milestone%3A%22v1.0.1+-+Fixes%22+is%3Aclosed>`_
179 * A list of all issues can be found `on GitHub <https://github.com/gitpython-developers/GitPython/issues?q=milestone%3A%22v1.0.1+-+Fixes%22+is%3Aclosed>`_
170180
171181 1.0.0 - Notes
172182 =============
190200
191201 - Those who support **GUI on windows** will now have to set `git.Git.USE_SHELL = True` to get the previous behaviour.
192202
193 * A list of all issues can be found `on github <https://github.com/gitpython-developers/GitPython/issues?q=milestone%3A%22v0.3.7+-+Fixes%22+is%3Aclosed>`_
203 * A list of all issues can be found `on GitHub <https://github.com/gitpython-developers/GitPython/issues?q=milestone%3A%22v0.3.7+-+Fixes%22+is%3Aclosed>`_
194204
195205
196206 0.3.6 - Features
206216 * Repo.working_tree_dir now returns None if it is bare. Previously it raised AssertionError.
207217 * IndexFile.add() previously raised AssertionError when paths where used with bare repository, now it raises InvalidGitRepositoryError
208218
209 * Added `Repo.merge_base()` implementation. See the `respective issue on github <https://github.com/gitpython-developers/GitPython/issues/169>`_
219 * Added `Repo.merge_base()` implementation. See the `respective issue on GitHub <https://github.com/gitpython-developers/GitPython/issues/169>`_
210220 * `[include]` sections in git configuration files are now respected
211221 * Added `GitConfigParser.rename_section()`
212222 * Added `Submodule.rename()`
213 * A list of all issues can be found `on github <https://github.com/gitpython-developers/GitPython/issues?q=milestone%3A%22v0.3.6+-+Features%22+>`_
223 * A list of all issues can be found `on GitHub <https://github.com/gitpython-developers/GitPython/issues?q=milestone%3A%22v0.3.6+-+Features%22+>`_
214224
215225 0.3.5 - Bugfixes
216226 ================
1313 ============
1414
1515 * `Python`_ 2.7 or newer
16 Since GitPython 2.0.0. Please note that python 2.6 is still reasonably well supported, but might
17 deteriorate over time. Support is provided on a best-effort basis only.
1816 * `Git`_ 1.7.0 or newer
1917 It should also work with older versions, but it may be that some operations
2018 involving remotes will not work as expected.
7472 Another way assure proper cleanup of resources is to factor out GitPython into a
7573 separate process which can be dropped periodically.
7674
77 Best-effort for Python 2.6 and Windows support
78 ----------------------------------------------
79
80 This means that support for these platforms is likely to worsen over time
81 as they are kept alive solely by their users, or not.
82
8375 Getting Started
8476 ===============
8577
123115
124116 Issue Tracker
125117 =============
126 The issue tracker is hosted by github:
118 The issue tracker is hosted by GitHub:
127119
128120 https://github.com/gitpython-developers/GitPython/issues
129121
11 #######
22 Roadmap
33 #######
4 The full list of milestones including associated tasks can be found on github:
4 The full list of milestones including associated tasks can be found on GitHub:
55 https://github.com/gitpython-developers/GitPython/issues
66
77 Select the respective milestone to filter the list of issues accordingly.
1111 import os.path as osp
1212
1313
14 __version__ = '2.1.8'
14 __version__ = '2.1.9'
1515
1616
1717 #{ Initialization
1818 def _init_externals():
1919 """Initialize external projects by putting them into the path"""
20 if __version__ == '2.1.8':
20 if __version__ == '2.1.9':
2121 sys.path.insert(0, osp.join(osp.dirname(__file__), 'ext', 'gitdb'))
2222
2323 try:
1616 import subprocess
1717 import sys
1818 import threading
19 from collections import OrderedDict
1920 from textwrap import dedent
2021
2122 from git.compat import (
3031 is_win,
3132 )
3233 from git.exc import CommandError
33 from git.odict import OrderedDict
3434 from git.util import is_cygwin_git, cygpath, expand_path
3535
3636 from .exc import (
4343 )
4444
4545
46 execute_kwargs = set(('istream', 'with_extended_output',
47 'with_exceptions', 'as_process', 'stdout_as_string',
48 'output_stream', 'with_stdout', 'kill_after_timeout',
49 'universal_newlines', 'shell', 'env'))
46 execute_kwargs = {'istream', 'with_extended_output', 'with_exceptions',
47 'as_process', 'stdout_as_string', 'output_stream',
48 'with_stdout', 'kill_after_timeout', 'universal_newlines',
49 'shell', 'env'}
5050
5151 log = logging.getLogger(__name__)
5252 log.addHandler(logging.NullHandler())
124124
125125
126126 def slots_to_dict(self, exclude=()):
127 return dict((s, getattr(self, s)) for s in self.__slots__ if s not in exclude)
127 return {s: getattr(self, s) for s in self.__slots__ if s not in exclude}
128128
129129
130130 def dict_to_slots_and__excluded_are_none(self, d, excluded=()):
142142 ## CREATE_NEW_PROCESS_GROUP is needed to allow killing it afterwards,
143143 # see https://docs.python.org/3/library/subprocess.html#subprocess.Popen.send_signal
144144 PROC_CREATIONFLAGS = (CREATE_NO_WINDOW | subprocess.CREATE_NEW_PROCESS_GROUP
145 if is_win and sys.version_info >= (2, 7)
146 else 0)
145 if is_win else 0)
147146
148147
149148 class Git(LazyMixin):
485484
486485 def readlines(self, size=-1):
487486 if self._nbr == self._size:
488 return list()
487 return []
489488
490489 # leave all additional logic to our readline method, we just check the size
491 out = list()
490 out = []
492491 nbr = 0
493492 while True:
494493 line = self.readline()
894893
895894 def transform_kwargs(self, split_single_char_options=True, **kwargs):
896895 """Transforms Python style kwargs into git command line options."""
897 args = list()
896 args = []
898897 kwargs = OrderedDict(sorted(kwargs.items(), key=lambda x: x[0]))
899898 for k, v in kwargs.items():
900899 if isinstance(v, (list, tuple)):
913912 return [arg_list.encode(defenc)]
914913 return [str(arg_list)]
915914
916 outlist = list()
915 outlist = []
917916 for arg in arg_list:
918917 if isinstance(arg_list, (list, tuple)):
919918 outlist.extend(cls.__unpack_args(arg))
972971 :return: Same as ``execute``"""
973972 # Handle optional arguments prior to calling transform_kwargs
974973 # otherwise these'll end up in args, which is bad.
975 exec_kwargs = dict((k, v) for k, v in kwargs.items() if k in execute_kwargs)
976 opts_kwargs = dict((k, v) for k, v in kwargs.items() if k not in execute_kwargs)
974 exec_kwargs = {k: v for k, v in kwargs.items() if k in execute_kwargs}
975 opts_kwargs = {k: v for k, v in kwargs.items() if k not in execute_kwargs}
977976
978977 insert_after_this_arg = opts_kwargs.pop('insert_kwargs_after', None)
979978
1111 import logging
1212 import os
1313 import re
14 from collections import OrderedDict
1415
1516 from git.compat import (
1617 string_types,
2021 with_metaclass,
2122 PY3
2223 )
23 from git.odict import OrderedDict
2424 from git.util import LockFile
2525
2626 import os.path as osp
6060 :note:
6161 Subclasses require a repo member as it is the case for Object instances, for practical
6262 reasons we do not derive from Object."""
63 __slots__ = tuple()
63 __slots__ = ()
6464
6565 # standin indicating you want to diff against the index
6666 class Index(object):
105105 :note:
106106 On a bare repository, 'other' needs to be provided as Index or as
107107 as Tree/Commit, or a git command error will occur"""
108 args = list()
108 args = []
109109 args.append("--abbrev=40") # we need full shas
110110 args.append("--full-index") # get full index paths, not only filenames
111111
77 import os
88 from stat import S_ISLNK
99 import subprocess
10 import sys
1110 import tempfile
1211
1312 from git.compat import (
1716 force_bytes,
1817 defenc,
1918 mviter,
20 is_win
2119 )
2220 from git.exc import (
2321 GitCommandError,
120118 ok = True
121119 except OSError:
122120 # in new repositories, there may be no index, which means we are empty
123 self.entries = dict()
121 self.entries = {}
124122 return
125123 finally:
126124 if not ok:
127125 lfd.rollback()
128126 # END exception handling
129127
130 # Here it comes: on windows in python 2.5, memory maps aren't closed properly
131 # Hence we are in trouble if we try to delete a file that is memory mapped,
132 # which happens during read-tree.
133 # In this case, we will just read the memory in directly.
134 # Its insanely bad ... I am disappointed !
135 allow_mmap = (is_win or sys.version_info[1] > 5)
136 stream = file_contents_ro(fd, stream=True, allow_mmap=allow_mmap)
128 stream = file_contents_ro(fd, stream=True, allow_mmap=True)
137129
138130 try:
139131 self._deserialize(stream)
323315 if len(treeish) == 0 or len(treeish) > 3:
324316 raise ValueError("Please specify between 1 and 3 treeish, got %i" % len(treeish))
325317
326 arg_list = list()
318 arg_list = []
327319 # ignore that working tree and index possibly are out of date
328320 if len(treeish) > 1:
329321 # drop unmerged entries when reading our index and merging
470462 are at stage 3 will not have a stage 3 entry.
471463 """
472464 is_unmerged_blob = lambda t: t[0] != 0
473 path_map = dict()
465 path_map = {}
474466 for stage, blob in self.iter_blobs(is_unmerged_blob):
475 path_map.setdefault(blob.path, list()).append((stage, blob))
467 path_map.setdefault(blob.path, []).append((stage, blob))
476468 # END for each unmerged blob
477469 for l in mviter(path_map):
478470 l.sort()
575567
576568 def _preprocess_add_items(self, items):
577569 """ Split the items into two lists of path strings and BaseEntries. """
578 paths = list()
579 entries = list()
570 paths = []
571 entries = []
580572
581573 for item in items:
582574 if isinstance(item, string_types):
609601 @unbare_repo
610602 @git_working_dir
611603 def _entries_for_paths(self, paths, path_rewriter, fprogress, entries):
612 entries_added = list()
604 entries_added = []
613605 if path_rewriter:
614606 for path in paths:
615607 if osp.isabs(path):
741733 # automatically
742734 # paths can be git-added, for everything else we use git-update-index
743735 paths, entries = self._preprocess_add_items(items)
744 entries_added = list()
736 entries_added = []
745737 # This code needs a working tree, therefore we try not to run it unless required.
746738 # That way, we are OK on a bare repository as well.
747739 # If there are no paths, the rewriter has nothing to do either
808800 def _items_to_rela_paths(self, items):
809801 """Returns a list of repo-relative paths from the given items which
810802 may be absolute or relative paths, entries or blobs"""
811 paths = list()
803 paths = []
812804 for item in items:
813805 if isinstance(item, (BaseIndexEntry, (Blob, Submodule))):
814806 paths.append(self._to_relative_path(item.path))
857849 been removed effectively.
858850 This is interesting to know in case you have provided a directory or
859851 globs. Paths are relative to the repository. """
860 args = list()
852 args = []
861853 if not working_tree:
862854 args.append("--cached")
863855 args.append("--")
896888
897889 :raise ValueError: If only one item was given
898890 GitCommandError: If git could not handle your request"""
899 args = list()
891 args = []
900892 if skip_errors:
901893 args.append('-k')
902894
909901
910902 # first execute rename in dryrun so the command tells us what it actually does
911903 # ( for later output )
912 out = list()
904 out = []
913905 mvlines = self.repo.git.mv(args, paths, **kwargs).splitlines()
914906
915907 # parse result - first 0:n/2 lines are 'checking ', the remaining ones
10401032 # line contents:
10411033 stderr = stderr.decode(defenc)
10421034 # git-checkout-index: this already exists
1043 failed_files = list()
1044 failed_reasons = list()
1045 unknown_lines = list()
1035 failed_files = []
1036 failed_reasons = []
1037 unknown_lines = []
10461038 endings = (' already exists', ' is not in the cache', ' does not exist at stage', ' is unmerged')
10471039 for line in stderr.splitlines():
10481040 if not line.startswith("git checkout-index: ") and not line.startswith("git-checkout-index: "):
11051097 proc = self.repo.git.checkout_index(args, **kwargs)
11061098 # FIXME: Reading from GIL!
11071099 make_exc = lambda: GitCommandError(("git-checkout-index",) + tuple(args), 128, proc.stderr.read())
1108 checked_out_files = list()
1100 checked_out_files = []
11091101
11101102 for path in paths:
11111103 co_path = to_native_path_linux(self._to_relative_path(path))
186186 * content_sha is a 20 byte sha on all cache file contents"""
187187 version, num_entries = read_header(stream)
188188 count = 0
189 entries = dict()
189 entries = {}
190190
191191 read = stream.read
192192 tell = stream.tell
235235 :param sl: slice indicating the range we should process on the entries list
236236 :return: tuple(binsha, list(tree_entry, ...)) a tuple of a sha and a list of
237237 tree entries being a tuple of hexsha, mode, name"""
238 tree_items = list()
238 tree_items = []
239239 tree_items_append = tree_items.append
240240 ci = sl.start
241241 end = sl.stop
294294 :param tree_shas: 1, 2 or 3 trees as identified by their binary 20 byte shas
295295 If 1 or two, the entries will effectively correspond to the last given tree
296296 If 3 are given, a 3 way merge is performed"""
297 out = list()
297 out = []
298298 out_append = out.append
299299
300300 # one and two way is the same for us, as we don't have to handle an existing
1919 file_mode = 0o100644
2020 link_mode = 0o120000
2121
22 __slots__ = tuple()
22 __slots__ = ()
2323
2424 @property
2525 def mime_type(self):
315315 parent_commits = [repo.head.commit]
316316 except ValueError:
317317 # empty repositories have no head commit
318 parent_commits = list()
318 parent_commits = []
319319 # END handle parent commits
320320 else:
321321 for p in parent_commits:
449449 readline = stream.readline
450450 self.tree = Tree(self.repo, hex_to_bin(readline().split()[1]), Tree.tree_id << 12, '')
451451
452 self.parents = list()
452 self.parents = []
453453 next_line = None
454454 while True:
455455 parent_line = readline()
4949 space_ord = ord(' ')
5050 len_data = len(data)
5151 i = 0
52 out = list()
52 out = []
5353 while i < len_data:
5454 mode = 0
5555
131131 :param path_prefix: a prefix to be added to the returned paths on this level,
132132 set it '' for the first iteration
133133 :note: The ordering of the returned items will be partially lost"""
134 trees_data = list()
134 trees_data = []
135135 nt = len(tree_shas)
136136 for tree_sha in tree_shas:
137137 if tree_sha is None:
138 data = list()
138 data = []
139139 else:
140140 data = tree_entries_from_data(odb.stream(tree_sha).read())
141141 # END handle muted trees
142142 trees_data.append(data)
143143 # END for each sha to get data for
144144
145 out = list()
145 out = []
146146 out_append = out.append
147147
148148 # find all matching entries and recursively process them together if the match
192192 * [1] mode as int
193193 * [2] path relative to the repository
194194 :param path_prefix: prefix to prepend to the front of all returned paths"""
195 entries = list()
195 entries = []
196196 data = tree_entries_from_data(odb.stream(tree_sha).read())
197197
198198 # unpacking/packing is faster than accessing individual items
22 import logging
33 import os
44 import stat
5 try:
6 from unittest import SkipTest
7 except ImportError:
8 from unittest2 import SkipTest
5 from unittest import SkipTest
96 import uuid
107
118 import git
6259 CLONE, FETCH, UPDWKTREE = [1 << x for x in range(RemoteProgress._num_op_codes, RemoteProgress._num_op_codes + 3)]
6360 _num_op_codes = RemoteProgress._num_op_codes + 3
6461
65 __slots__ = tuple()
62 __slots__ = ()
6663
6764
6865 BEGIN = UpdateProgress.BEGIN
141138 try:
142139 return type(self).list_items(item.module())
143140 except InvalidGitRepositoryError:
144 return list()
141 return []
145142 # END handle intermediate items
146143
147144 @classmethod
2121 1 << x for x in range(UpdateProgress._num_op_codes, UpdateProgress._num_op_codes + 4)]
2222 _num_op_codes = UpdateProgress._num_op_codes + 4
2323
24 __slots__ = tuple()
24 __slots__ = ()
2525
2626
2727 BEGIN = RootUpdateProgress.BEGIN
3737 """A (virtual) Root of all submodules in the given repository. It can be used
3838 to more easily traverse all submodules of the master repository"""
3939
40 __slots__ = tuple()
40 __slots__ = ()
4141
4242 k_root_name = '__ROOT__'
4343
188188 def _get_intermediate_items(cls, index_object):
189189 if index_object.type == "tree":
190190 return tuple(index_object._iter_convert_to_object(index_object._cache))
191 return tuple()
191 return ()
192192
193193 def _set_cache_(self, attr):
194194 if attr == "_cache":
152152 offset = utctz_to_altz(offset)
153153
154154 # now figure out the date and time portion - split time
155 date_formats = list()
155 date_formats = []
156156 splitter = -1
157157 if ',' in string_date:
158158 date_formats.append("%a, %d %b %Y")
247247 into one direction.
248248 Subclasses only need to implement one function.
249249 Instances of the Subclass must be hashable"""
250 __slots__ = tuple()
250 __slots__ = ()
251251
252252 @classmethod
253253 def _get_intermediate_items(cls, item):
343343 class Serializable(object):
344344
345345 """Defines methods to serialize and deserialize objects from and into a data stream"""
346 __slots__ = tuple()
346 __slots__ = ()
347347
348348 def _serialize(self, stream):
349349 """Serialize the data of this object into the given data stream
+0
-10
git/odict.py less more
0 try:
1 from collections import OrderedDict
2 except ImportError:
3 try:
4 from ordereddict import OrderedDict
5 except ImportError:
6 import warnings
7 warnings.warn("git-python needs the ordereddict module installed in python below 2.6 and below.")
8 warnings.warn("Using standard dictionary as substitute, and cause reordering when writing git config")
9 OrderedDict = dict
1919 HEAD reference."""
2020 _HEAD_NAME = 'HEAD'
2121 _ORIG_HEAD_NAME = 'ORIG_HEAD'
22 __slots__ = tuple()
22 __slots__ = ()
2323
2424 def __init__(self, repo, path=_HEAD_NAME):
2525 if path != self._HEAD_NAME:
3131
3232 """Named tuple allowing easy access to the revlog data fields"""
3333 _re_hexsha_only = re.compile('^[0-9A-Fa-f]{40}$')
34 __slots__ = tuple()
34 __slots__ = ()
3535
3636 def __repr__(self):
3737 """Representation of ourselves in git reflog format"""
4747 """:return: a string suitable to be placed in a reflog file"""
4848 act = self.actor
4949 time = self.time
50 return u"{0} {1} {2} <{3}> {4!s} {5}\t{6}\n".format(self.oldhexsha,
51 self.newhexsha,
52 act.name,
53 act.email,
54 time[0],
55 altz_to_utctz_str(time[1]),
56 self.message)
50 return u"{} {} {} <{}> {!s} {}\t{}\n".format(self.oldhexsha,
51 self.newhexsha,
52 act.name,
53 act.email,
54 time[0],
55 altz_to_utctz_str(time[1]),
56 self.message)
5757
5858 @property
5959 def oldhexsha(self):
2626
2727 """Represents a named reference to any object. Subclasses may apply restrictions though,
2828 i.e. Heads can only point to commits."""
29 __slots__ = tuple()
29 __slots__ = ()
3030 _points_to_commits_only = False
3131 _resolve_ref_on_create = True
3232 _common_path_default = "refs"
443443 pack_file_path = cls._get_packed_refs_path(repo)
444444 try:
445445 with open(pack_file_path, 'rb') as reader:
446 new_lines = list()
446 new_lines = []
447447 made_change = False
448448 dropped_last_line = False
449449 for line in reader:
1616 if tagref.tag is not None:
1717 print(tagref.tag.message)"""
1818
19 __slots__ = tuple()
19 __slots__ = ()
2020 _common_path_default = "refs/tags"
2121
2222 @property
541541 if ' Push URL:' in line:
542542 yield line.split(': ')[-1]
543543 except GitCommandError as ex:
544 if any([msg in str(ex) for msg in ['correct access rights', 'cannot run ssh']]):
544 if any(msg in str(ex) for msg in ['correct access rights', 'cannot run ssh']):
545545 # If ssh is not setup to access this repository, see issue 694
546546 result = Git().execute(
547547 ['git', 'config', '--get', 'remote.%s.url' % self.name]
662662 # lines which are no progress are fetch info lines
663663 # this also waits for the command to finish
664664 # Skip some progress lines that don't provide relevant information
665 fetch_info_lines = list()
665 fetch_info_lines = []
666666 # Basically we want all fetch info lines which appear to be in regular form, and thus have a
667667 # command character. Everything else we ignore,
668668 cmds = set(FetchInfo._flag_map.keys())
484484 def iter_commits(self, rev=None, paths='', **kwargs):
485485 """A list of Commit objects representing the history of a given ref/commit
486486
487 :parm rev:
487 :param rev:
488488 revision specifier, see git-rev-parse for viable options.
489489 If None, the active branch will be used.
490490
491 :parm paths:
491 :param paths:
492492 is an optional path or a list of paths to limit the returned commits to
493493 Commits that do not contain that path or the paths will not be returned.
494494
495 :parm kwargs:
495 :param kwargs:
496496 Arguments to be passed to git-rev-list - common ones are
497497 max_count and skip
498498
518518 raise ValueError("Please specify at least two revs, got only %i" % len(rev))
519519 # end handle input
520520
521 res = list()
521 res = []
522522 try:
523523 lines = self.git.merge_base(*rev, **kwargs).splitlines()
524524 except GitCommandError as err:
579579 alts = f.read().decode(defenc)
580580 return alts.strip().splitlines()
581581 else:
582 return list()
582 return []
583583
584584 def _set_alternates(self, alts):
585585 """Sets the alternates
586586
587 :parm alts:
587 :param alts:
588588 is the array of string paths representing the alternates at which
589589 git should look for objects, i.e. /home/user/repo/.git/objects
590590
663663 **kwargs)
664664 # Untracked files preffix in porcelain mode
665665 prefix = "?? "
666 untracked_files = list()
666 untracked_files = []
667667 for line in proc.stdout:
668668 line = line.decode(defenc)
669669 if not line.startswith(prefix):
694694 Unlike .blame(), this does not return the actual file's contents, only
695695 a stream of BlameEntry tuples.
696696
697 :parm rev: revision specifier, see git-rev-parse for viable options.
697 :param rev: revision specifier, see git-rev-parse for viable options.
698698 :return: lazy iterator of BlameEntry tuples, where the commit
699699 indicates the commit to blame for the line, and range
700700 indicates a span of line numbers in the resulting file.
703703 should get a continuous range spanning all line numbers in the file.
704704 """
705705 data = self.git.blame(rev, '--', file, p=True, incremental=True, stdout_as_string=False, **kwargs)
706 commits = dict()
706 commits = {}
707707
708708 stream = (line for line in data.split(b'\n') if line)
709709 while True:
715715 if hexsha not in commits:
716716 # Now read the next few lines and build up a dict of properties
717717 # for this commit
718 props = dict()
718 props = {}
719719 while True:
720720 line = next(stream)
721721 if line == b'boundary':
756756 def blame(self, rev, file, incremental=False, **kwargs):
757757 """The blame information for the given file at the given revision.
758758
759 :parm rev: revision specifier, see git-rev-parse for viable options.
759 :param rev: revision specifier, see git-rev-parse for viable options.
760760 :return:
761761 list: [git.Commit, list: [<line>]]
762762 A list of tuples associating a Commit object with a list of lines that
766766 return self.blame_incremental(rev, file, **kwargs)
767767
768768 data = self.git.blame(rev, '--', file, p=True, stdout_as_string=False, **kwargs)
769 commits = dict()
770 blames = list()
769 commits = {}
770 blames = []
771771 info = None
772772
773773 keepends = True
870870 or None in which case the repository will be created in the current
871871 working directory
872872
873 :parm mkdir:
873 :param mkdir:
874874 if specified will create the repository directory if it doesn't
875875 already exists. Creates the directory with a mode=0755.
876876 Only effective if a path is explicitly given
885885 can lead to information disclosure, allowing attackers to
886886 access the contents of environment variables
887887
888 :parm kwargs:
888 :param kwargs:
889889 keyword arguments serving as additional options to the git-init command
890890
891891 :return: ``git.Repo`` (the newly created repo)"""
983983 def archive(self, ostream, treeish=None, prefix=None, **kwargs):
984984 """Archive the tree at the given revision.
985985
986 :parm ostream: file compatible stream object to which the archive will be written as bytes
987 :parm treeish: is the treeish name/id, defaults to active branch
988 :parm prefix: is the optional prefix to prepend to each filename in the archive
989 :parm kwargs: Additional arguments passed to git-archive
986 :param ostream: file compatible stream object to which the archive will be written as bytes
987 :param treeish: is the treeish name/id, defaults to active branch
988 :param prefix: is the optional prefix to prepend to each filename in the archive
989 :param kwargs: Additional arguments passed to git-archive
990990
991991 * Use the 'format' argument to define the kind of format. Use
992992 specialized ostreams to write any format supported by python.
10001000 if prefix and 'prefix' not in kwargs:
10011001 kwargs['prefix'] = prefix
10021002 kwargs['output_stream'] = ostream
1003 path = kwargs.pop('path', list())
1003 path = kwargs.pop('path', [])
10041004 if not isinstance(path, (tuple, list)):
10051005 path = [path]
10061006 # end assure paths is list
1414 import tempfile
1515 import textwrap
1616 import time
17 import unittest
1718
1819 from git.compat import string_types, is_win
1920 from git.util import rmtree, cwd
2122
2223 import os.path as osp
2324
24
25 if sys.version_info[0:2] == (2, 6):
26 import unittest2 as unittest
27 else:
28 import unittest
2925
3026 TestCase = unittest.TestCase
3127 SkipTest = unittest.SkipTest
347343 of the project history ( to assure tests don't fail for others ).
348344 """
349345
350 # On py26, unittest2 has assertRaisesRegex
351346 # On py3, unittest has assertRaisesRegex
352347 # On py27, we use unittest, which names it differently:
353348 if sys.version_info[0:2] == (2, 7):
2727 # GET TREES
2828 # walk all trees of all commits
2929 st = time()
30 blobs_per_commit = list()
30 blobs_per_commit = []
3131 nt = 0
3232 for commit in commits:
3333 tree = commit.tree
34 blobs = list()
34 blobs = []
3535 for item in tree.traverse():
3636 nt += 1
3737 if item.type == 'blob':
6868
6969 # reading in chunks of 1 MiB
7070 cs = 512 * 1000
71 chunks = list()
71 chunks = []
7272 st = time()
7373 ostream = ldb.stream(binsha)
7474 while True:
66 import os
77 import sys
88 import tempfile
9 try:
10 from unittest import SkipTest, skipIf
11 except ImportError:
12 from unittest2 import SkipTest, skipIf
9 from unittest import SkipTest, skipIf
1310
1411 from git import (
1512 Blob,
216216
217217 def test_diff_interface(self):
218218 # test a few variations of the main diff routine
219 assertion_map = dict()
219 assertion_map = {}
220220 for i, commit in enumerate(self.rorepo.iter_commits('0.1.6', max_count=2)):
221221 diff_item = commit
222222 if i % 2 == 0:
172172
173173 # [14-test_init_repo_object]
174174 # create a new submodule and check it out on the spot, setup to track master branch of `bare_repo`
175 # As our GitPython repository has submodules already that point to github, make sure we don't
175 # As our GitPython repository has submodules already that point to GitHub, make sure we don't
176176 # interact with them
177177 for sm in cloned_repo.submodules:
178178 assert not sm.remove().exists() # after removal, the sm doesn't exist anymore
11 from stat import S_IFDIR, S_IFREG, S_IFLNK
22 from os import stat
33 import os.path as osp
4
5 try:
6 from unittest import skipIf, SkipTest
7 except ImportError:
8 from unittest2 import skipIf, SkipTest
4 from unittest import skipIf, SkipTest
95
106 from git import Git
117 from git.compat import PY3
214210 def _assert_tree_entries(self, entries, num_trees):
215211 for entry in entries:
216212 assert len(entry) == num_trees
217 paths = set(e[2] for e in entry if e)
213 paths = {e[2] for e in entry if e}
218214
219215 # only one path per set of entries
220216 assert len(paths) == 1
9090
9191 # order is undefined
9292 res = self.git.transform_kwargs(**{'s': True, 't': True})
93 self.assertEqual(set(['-s', '-t']), set(res))
93 self.assertEqual({'-s', '-t'}, set(res))
9494
9595 def test_it_executes_git_to_shell_and_returns_result(self):
9696 assert_match(r'^git version [\d\.]{2}.*$', self.git.execute(["git", "version"]))
1010 S_ISLNK,
1111 ST_MODE
1212 )
13 import sys
1413 import tempfile
15 try:
16 from unittest import skipIf
17 except ImportError:
18 from unittest2 import skipIf
14 from unittest import skipIf
1915
2016 from git import (
2117 IndexFile,
10096
10197 def _reset_progress(self):
10298 # maps paths to the count of calls
103 self._fprogress_map = dict()
99 self._fprogress_map = {}
104100
105101 def _assert_entries(self, entries):
106102 for entry in entries:
130126 # test stage
131127 index_merge = IndexFile(self.rorepo, fixture_path("index_merge"))
132128 self.assertEqual(len(index_merge.entries), 106)
133 assert len(list(e for e in index_merge.entries.values() if e.stage != 0))
129 assert len([e for e in index_merge.entries.values() if e.stage != 0])
134130
135131 # write the data - it must match the original
136132 tmpfile = tempfile.mktemp()
144140 if isinstance(tree, str):
145141 tree = self.rorepo.commit(tree).tree
146142
147 blist = list()
143 blist = []
148144 for blob in tree.traverse(predicate=lambda e, d: e.type == "blob", branch_first=False):
149145 assert (blob.path, 0) in index.entries
150146 blist.append(blob)
151147 # END for each blob in tree
152148 if len(blist) != len(index.entries):
153 iset = set(k[0] for k in index.entries.keys())
154 bset = set(b.path for b in blist)
149 iset = {k[0] for k in index.entries.keys()}
150 bset = {b.path for b in blist}
155151 raise AssertionError("CMP Failed: Missing entries in index: %s, missing in tree: %s" %
156152 (bset - iset, iset - bset))
157153 # END assertion message
167163 except Exception as ex:
168164 msg_py3 = "required argument is not an integer"
169165 msg_py2 = "cannot convert argument to integer"
170 msg_py26 = "unsupported operand type(s) for &: 'str' and 'long'"
171 assert msg_py2 in str(ex) or msg_py3 in str(ex) or \
172 msg_py26 in str(ex), str(ex)
166 assert msg_py2 in str(ex) or msg_py3 in str(ex)
173167
174168 ## 2nd time should not fail due to stray lock file
175169 try:
179173
180174 @with_rw_repo('0.1.6')
181175 def test_index_file_from_tree(self, rw_repo):
182 if sys.version_info < (2, 7):
183 ## Skipped, not `assertRaisesRegexp` in py2.6
184 return
185176 common_ancestor_sha = "5117c9c8a4d3af19a9958677e45cda9269de1541"
186177 cur_sha = "4b43ca7ff72d5f535134241e7c797ddc9c7a3573"
187178 other_sha = "39f85c4358b7346fee22169da9cad93901ea9eb9"
198189
199190 # merge three trees - here we have a merge conflict
200191 three_way_index = IndexFile.from_tree(rw_repo, common_ancestor_sha, cur_sha, other_sha)
201 assert len(list(e for e in three_way_index.entries.values() if e.stage != 0))
192 assert len([e for e in three_way_index.entries.values() if e.stage != 0])
202193
203194 # ITERATE BLOBS
204195 merge_required = lambda t: t[0] != 0
234225 def test_index_merge_tree(self, rw_repo):
235226 # A bit out of place, but we need a different repo for this:
236227 self.assertNotEqual(self.rorepo, rw_repo)
237 self.assertEqual(len(set((self.rorepo, self.rorepo, rw_repo, rw_repo))), 2)
228 self.assertEqual(len({self.rorepo, self.rorepo, rw_repo, rw_repo}), 2)
238229
239230 # SINGLE TREE MERGE
240231 # current index is at the (virtual) cur_commit
535526
536527 # same index, no parents
537528 commit_message = "index without parents"
538 commit_no_parents = index.commit(commit_message, parent_commits=list(), head=True)
529 commit_no_parents = index.commit(commit_message, parent_commits=[], head=True)
539530 self.assertEqual(commit_no_parents.message, commit_message)
540531 self.assertEqual(len(commit_no_parents.parents), 0)
541532 self.assertEqual(cur_head.commit, commit_no_parents)
890881 _make_hook(
891882 index.repo.git_dir,
892883 'commit-msg',
893 'echo -n " {0}" >> "$1"'.format(from_hook_message)
884 'echo -n " {}" >> "$1"'.format(from_hook_message)
894885 )
895886 new_commit = index.commit(commit_message)
896 self.assertEqual(new_commit.message, u"{0} {1}".format(commit_message, from_hook_message))
887 self.assertEqual(new_commit.message, u"{} {}".format(commit_message, from_hook_message))
897888
898889 @with_rw_repo('HEAD', bare=True)
899890 def test_commit_msg_hook_fail(self, rw_repo):
4444 TagReference(self.rorepo, "refs/invalid/tag", check_path=False)
4545
4646 def test_tag_base(self):
47 tag_object_refs = list()
47 tag_object_refs = []
4848 for tag in self.rorepo.tags:
4949 assert "refs/tags" in tag.path
5050 assert tag.name
55
66 import random
77 import tempfile
8 try:
9 from unittest import skipIf
10 except ImportError:
11 from unittest2 import skipIf
8 from unittest import skipIf
129
1310 from git import (
1411 RemoteProgress,
4643
4744 def __init__(self):
4845 super(TestRemoteProgress, self).__init__()
49 self._seen_lines = list()
50 self._stages_per_op = dict()
46 self._seen_lines = []
47 self._stages_per_op = {}
5148 self._num_progress_messages = 0
5249
5350 def _parse_progress_line(self, line):
88 import itertools
99 import os
1010 import pickle
11 import sys
1211 import tempfile
13 try:
14 from unittest import skipIf, SkipTest
15 except ImportError:
16 from unittest2 import skipIf, SkipTest
12 from unittest import skipIf, SkipTest
1713
1814 try:
1915 import pathlib
363359
364360 @patch.object(Git, '_call_process')
365361 def test_should_display_blame_information(self, git):
366 if sys.version_info < (2, 7):
367 ## Skipped, not `assertRaisesRegexp` in py2.6
368 return
369362 git.return_value = fixture('blame')
370363 b = self.rorepo.blame('master', 'lib/git.py')
371364 assert_equal(13, len(b))
521514 # this is only a preliminary test, more testing done in test_index
522515 self.assertEqual(self.rorepo, self.rorepo)
523516 self.assertFalse(self.rorepo != self.rorepo)
524 self.assertEqual(len(set((self.rorepo, self.rorepo))), 1)
517 self.assertEqual(len({self.rorepo, self.rorepo}), 1)
525518
526519 @with_rw_directory
527520 def test_tilde_and_env_vars_in_repo_path(self, rw_dir):
791784
792785 def test_repo_odbtype(self):
793786 target_type = GitCmdObjectDB
794 if sys.version_info[:2] < (2, 5):
795 target_type = GitCmdObjectDB
796787 self.assertIsInstance(self.rorepo.odb, target_type)
797788
798789 def test_submodules(self):
22 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
33 import os
44 import sys
5 try:
6 from unittest import skipIf
7 except ImportError:
8 from unittest2 import skipIf
5 from unittest import skipIf
96
107 import git
118 from git.cmd import Git
266263 self.failUnlessRaises(ValueError, csm.remove, module=False, configuration=False)
267264
268265 # module() is supposed to point to gitdb, which has a child-submodule whose URL is still pointing
269 # to github. To save time, we will change it to
266 # to GitHub. To save time, we will change it to
270267 csm.set_parent_commit(csm.repo.head.commit)
271268 with csm.config_writer() as cw:
272269 cw.set_value('url', self._small_repo_url())
55
66 from io import BytesIO
77 import sys
8 try:
9 from unittest import skipIf
10 except ImportError:
11 from unittest2 import skipIf
8 from unittest import skipIf
129
1310 from git import (
1411 Tree,
6360 def test_traverse(self):
6461 root = self.rorepo.tree('0.1.6')
6562 num_recursive = 0
66 all_items = list()
63 all_items = []
6764 for obj in root.traverse():
6865 if "/" in obj.path:
6966 num_recursive += 1
8178 # only choose trees
8279 trees_only = lambda i, d: i.type == "tree"
8380 trees = list(root.traverse(predicate=trees_only))
84 assert len(trees) == len(list(i for i in root.traverse() if trees_only(i, 0)))
81 assert len(trees) == len([i for i in root.traverse() if trees_only(i, 0)])
8582
8683 # test prune
8784 lib_folder = lambda t, d: t.path == "lib"
9087
9188 # trees and blobs
9289 assert len(set(trees) | set(root.trees)) == len(trees)
93 assert len(set(b for b in root if isinstance(b, Blob)) | set(root.blobs)) == len(root.blobs)
90 assert len({b for b in root if isinstance(b, Blob)} | set(root.blobs)) == len(root.blobs)
9491 subitem = trees[0][0]
9592 assert "/" in subitem.path
9693 assert subitem.name == osp.basename(subitem.path)
55
66 import tempfile
77 import time
8 try:
9 from unittest import skipIf
10 except ImportError:
11 from unittest2 import skipIf
8 from unittest import skipIf
129
1310
1411 import ddt
1313 import shutil
1414 import stat
1515 import time
16 try:
17 from unittest import SkipTest
18 except ImportError:
19 from unittest2 import SkipTest
16 from unittest import SkipTest
2017
2118 from gitdb.util import (# NOQA @IgnorePep8
2219 make_sha,
371368 re_op_relative = re.compile(r"(remote: )?([\w\s]+):\s+(\d+)% \((\d+)/(\d+)\)(.*)")
372369
373370 def __init__(self):
374 self._seen_ops = list()
371 self._seen_ops = []
375372 self._cur_line = None
376373 self.error_lines = []
377374 self.other_lines = []
394391 return []
395392
396393 sub_lines = line.split('\r')
397 failed_lines = list()
394 failed_lines = []
398395 for sline in sub_lines:
399396 # find escape characters and cut them away - regex will not work with
400397 # them as they are non-ascii. As git might expect a tty, it will send them
672669 """Create a Stat object from output retrieved by git-diff.
673670
674671 :return: git.Stat"""
675 hsh = {'total': {'insertions': 0, 'deletions': 0, 'lines': 0, 'files': 0}, 'files': dict()}
672 hsh = {'total': {'insertions': 0, 'deletions': 0, 'lines': 0, 'files': 0}, 'files': {}}
676673 for line in text.splitlines():
677674 (raw_insertions, raw_deletions, filename) = line.split("\t")
678675 insertions = raw_insertions != '-' and int(raw_insertions) or 0
801798 def __init__(self, file_path, check_interval_s=0.3, max_block_time_s=MAXSIZE):
802799 """Configure the instance
803800
804 :parm check_interval_s:
801 :param check_interval_s:
805802 Period of time to sleep until the lock is checked the next time.
806803 By default, it waits a nearly unlimited time
807804
808 :parm max_block_time_s: Maximum amount of seconds we may lock"""
805 :param max_block_time_s: Maximum amount of seconds we may lock"""
809806 super(BlockingLockFile, self).__init__(file_path)
810807 self._check_interval = check_interval_s
811808 self._max_block_time = max_block_time_s
919916
920917 """Defines an interface for iterable items which is to assure a uniform
921918 way to retrieve and iterate items within the git repository"""
922 __slots__ = tuple()
919 __slots__ = ()
923920 _id_attribute_ = "attribute that most suitably identifies your instance"
924921
925922 @classmethod
00 gitdb>=0.6.4
11 ddt>=1.1.1
2 unittest2; python_version < '2.7'
88
99 from distutils.command.build_py import build_py as _build_py
1010 from setuptools.command.sdist import sdist as _sdist
11 import pkg_resources
12 import logging
1311 import os
1412 import sys
1513 from os import path
4644
4745
4846 def _stamp_version(filename):
49 found, out = False, list()
47 found, out = False, []
5048 try:
5149 with open(filename, 'r') as f:
5250 for line in f:
6563
6664
6765 install_requires = ['gitdb2 >= 2.0.0']
68 extras_require = {
69 ':python_version == "2.6"': ['ordereddict'],
70 }
7166 test_requires = ['ddt>=1.1.1']
72 if sys.version_info[:2] < (2, 7):
73 test_requires.append('mock')
74
75 try:
76 if 'bdist_wheel' not in sys.argv:
77 for key, value in extras_require.items():
78 if key.startswith(':') and pkg_resources.evaluate_marker(key[1:]):
79 install_requires.extend(value)
80 except Exception:
81 logging.getLogger(__name__).exception(
82 'Something went wrong calculating platform specific dependencies, so '
83 "you're getting them all!"
84 )
85 for key, value in extras_require.items():
86 if key.startswith(':'):
87 install_requires.extend(value)
8867 # end
8968
9069 setup(
10079 package_data={'git.test': ['fixtures/*']},
10180 package_dir={'git': 'git'},
10281 license="BSD License",
103 python_requires='>=2.6, !=3.0.*, !=3.1.*, !=3.2.*',
82 python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*',
10483 requires=['gitdb2 (>=2.0.0)'],
10584 install_requires=install_requires,
10685 test_requirements=test_requires + install_requires,
125104 "Operating System :: MacOS :: MacOS X",
126105 "Programming Language :: Python",
127106 "Programming Language :: Python :: 2",
128 "Programming Language :: Python :: 2.6",
129107 "Programming Language :: Python :: 2.7",
130108 "Programming Language :: Python :: 3",
131 "Programming Language :: Python :: 3.3",
132109 "Programming Language :: Python :: 3.4",
133110 "Programming Language :: Python :: 3.5",
134111 "Programming Language :: Python :: 3.6",