Skip to content

Commit

Permalink
Added advance usage examples to tutorial and made minor fixes.
Browse files Browse the repository at this point in the history
GIT_PYTHON_TRACE would actually fail (now) if we debugged archive operations.

Related to #239
  • Loading branch information
Byron committed Jan 21, 2015
1 parent e48e520 commit e4d3809
Show file tree
Hide file tree
Showing 15 changed files with 270 additions and 52 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ New BSD License. See the LICENSE file.
[![Build Status](https://travis-ci.org/gitpython-developers/GitPython.svg?branch=0.3)](https://travis-ci.org/gitpython-developers/GitPython)
[![Coverage Status](https://coveralls.io/repos/gitpython-developers/GitPython/badge.png?branch=master)](https://coveralls.io/r/gitpython-developers/GitPython?branch=master)
[![Documentation Status](https://readthedocs.org/projects/gitpython/badge/?version=stable)](https://readthedocs.org/projects/gitpython/?badge=stable)
[![Issue Stats](http://www.issuestats.com/github/gitpython-developers/GitPython/badge/pr)](http://www.issuestats.com/github/gitpython-developers/GitPython)
[![Issue Stats](http://www.issuestats.com/github/gitpython-developers/GitPython/badge/issue)](http://www.issuestats.com/github/gitpython-developers/GitPython)

Now that there seems to be a massive user base, this should be motivation enough to let git-python return to a proper state, which means

Expand Down
2 changes: 2 additions & 0 deletions doc/source/reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@ Objects.Blob
.. automodule:: git.objects.blob
:members:
:undoc-members:
:special-members:

Objects.Commit
--------------

.. automodule:: git.objects.commit
:members:
:undoc-members:
:special-members:

Objects.Tag
-----------
Expand Down
97 changes: 79 additions & 18 deletions doc/source/tutorial.rst
Original file line number Diff line number Diff line change
Expand Up @@ -55,26 +55,67 @@ Archive the repository contents to a tar file.
:start-after: # [6-test_init_repo_object]
:end-before: # ![6-test_init_repo_object]

.. todo repo paths, heads, remotes, submodules
Object Databases
****************
``Repo`` instances are powered by its object database instance which will be used when extracting any data, or when writing new objects.
Advanced Repo Usage
===================

The type of the database determines certain performance characteristics, such as the quantity of objects that can be read per second, the resource usage when reading large data files, as well as the average memory footprint of your application.
And of course, there is much more you can do with this type, most of the following will be explained in greater detail in specific tutorials.

GitDB
=====
The GitDB is a pure-python implementation of the git object database. It is the default database to use in GitPython 0.3. Its uses less memory when handling huge files, but will be 2 to 5 times slower when extracting large quantities small of objects from densely packed repositories::
repo = Repo("path/to/repo", odbt=GitDB)
Query relevant repository paths ...

.. literalinclude:: ../../git/test/test_docs.py
:language: python
:start-after: # [7-test_init_repo_object]
:end-before: # ![7-test_init_repo_object]

:class:`Heads <git.refs.head.Head>` Heads are branches in git-speak. :class:`References <git.refs.reference.Reference>` are pointers to a specific commit or to other references. Heads and :class:`Tags <git.refs.tag.TagReference>` are a kind of references. GitPython allows you to query them rather intuitively.

.. literalinclude:: ../../git/test/test_docs.py
:language: python
:start-after: # [8-test_init_repo_object]
:end-before: # ![8-test_init_repo_object]

You can also create new heads ...

.. literalinclude:: ../../git/test/test_docs.py
:language: python
:start-after: # [9-test_init_repo_object]
:end-before: # ![9-test_init_repo_object]

... and tags ...

.. literalinclude:: ../../git/test/test_docs.py
:language: python
:start-after: # [10-test_init_repo_object]
:end-before: # ![10-test_init_repo_object]

You can traverse down to :class:`git objects <git.objects.base.Object>` through references and other objects. Some objects like :class:`commits <git.objects.commit.Commit>` have additional meta-data to query.

.. literalinclude:: ../../git/test/test_docs.py
:language: python
:start-after: # [11-test_init_repo_object]
:end-before: # ![11-test_init_repo_object]

:class:`Remotes <git.remote.Remote>` allow to handle fetch, pull and push operations, while providing optional real-time progress information to :class:`progress delegates <git.util.RemoteProgress>`.

.. literalinclude:: ../../git/test/test_docs.py
:language: python
:start-after: # [12-test_init_repo_object]
:end-before: # ![12-test_init_repo_object]

The :class:`index <git.index.base.IndexFile>` is also called stage in git-speak. It is used to prepare new commits, and can be used to keep results of merge operations. Our index implementation allows to stream date into the index, which is useful for bare repositories that do not have a working tree.

.. literalinclude:: ../../git/test/test_docs.py
:language: python
:start-after: # [13-test_init_repo_object]
:end-before: # ![13-test_init_repo_object]

:class:`Submodules <git.objects.submodule.Submodule>` represent all aspects of git submodules, which allows you query all of their related information, and manipulate in various ways.

.. literalinclude:: ../../git/test/test_docs.py
:language: python
:start-after: # [14-test_init_repo_object]
:end-before: # ![14-test_init_repo_object]

GitCmdObjectDB
==============
The git command database uses persistent git-cat-file instances to read repository information. These operate very fast under all conditions, but will consume additional memory for the process itself. When extracting large files, memory usage will be much higher than the one of the ``GitDB``::
repo = Repo("path/to/repo", odbt=GitCmdObjectDB)

Examining References
********************
Expand Down Expand Up @@ -107,7 +148,7 @@ Access the reflog easily::
log[0] # first (i.e. oldest) reflog entry
log[-1] # last (i.e. most recent) reflog entry
For more information on the reflog, see the ``RefLog`` type's documentation.
For more information on the reflog, see the :class:`git.RefLog <git.refs.log.RefLog>` type's documentation.

Modifying References
********************
Expand Down Expand Up @@ -454,6 +495,26 @@ The special notion ``git.command(flag=True)`` will create a flag without value l

If ``None`` is found in the arguments, it will be dropped silently. Lists and tuples passed as arguments will be unpacked recursively to individual arguments. Objects are converted to strings using the str(...) function.


Object Databases
****************
:class:`git.Repo <git.repo.base.Repo>` instances are powered by its object database instance which will be used when extracting any data, or when writing new objects.

The type of the database determines certain performance characteristics, such as the quantity of objects that can be read per second, the resource usage when reading large data files, as well as the average memory footprint of your application.

GitDB
=====
The GitDB is a pure-python implementation of the git object database. It is the default database to use in GitPython 0.3. Its uses less memory when handling huge files, but will be 2 to 5 times slower when extracting large quantities small of objects from densely packed repositories::
repo = Repo("path/to/repo", odbt=GitDB)


GitCmdObjectDB
==============
The git command database uses persistent git-cat-file instances to read repository information. These operate very fast under all conditions, but will consume additional memory for the process itself. When extracting large files, memory usage will be much higher than the one of the ``GitDB``::
repo = Repo("path/to/repo", odbt=GitCmdObjectDB)

Git Command Debugging and Customization
***************************************

Expand Down
9 changes: 7 additions & 2 deletions git/cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -579,11 +579,16 @@ def execute(self, command,

if self.GIT_PYTHON_TRACE == 'full':
cmdstr = " ".join(command)

def as_text(stdout_value):
return not output_stream and stdout_value.decode(defenc) or '<OUTPUT_STREAM>'
# end

if stderr_value:
log.info("%s -> %d; stdout: '%s'; stderr: '%s'",
cmdstr, status, stdout_value.decode(defenc), stderr_value.decode(defenc))
cmdstr, status, as_text(stdout_value), stderr_value.decode(defenc))
elif stdout_value:
log.info("%s -> %d; stdout: '%s'", cmdstr, status, stdout_value.decode(defenc))
log.info("%s -> %d; stdout: '%s'", cmdstr, status, as_text(stdout_value))
else:
log.info("%s -> %d", cmdstr, status)
# END handle debug printing
Expand Down
2 changes: 1 addition & 1 deletion git/objects/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ def __init__(self, repo, binsha, mode=None, path=None):
:param repo: is the Repo we are located in
:param binsha: 20 byte sha1
:param mode:
:param mode:
is the stat compatible file mode as int, use the stat module
to evaluate the infomration
:param path:
Expand Down
9 changes: 8 additions & 1 deletion git/objects/commit.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ def __init__(self, repo, binsha, tree=None, author=None, authored_date=None, aut
message=None, parents=None, encoding=None, gpgsig=None):
"""Instantiate a new Commit. All keyword arguments taking None as default will
be implicitly set on first query.
:param binsha: 20 byte sha1
:param parents: tuple( Commit, ... )
is a tuple of commit ids or actual Commits
Expand Down Expand Up @@ -97,7 +98,8 @@ def __init__(self, repo, binsha, tree=None, author=None, authored_date=None, aut
dependency graph
:return: git.Commit
:note: Timezone information is in the same format and in the same sign
:note:
Timezone information is in the same format and in the same sign
as what time.altzone returns. The sign is inverted compared to git's
UTC timezone."""
super(Commit, self).__init__(repo, binsha)
Expand Down Expand Up @@ -296,6 +298,11 @@ def create_from_tree(cls, repo, tree, message, parent_commits=None, head=False,
# empty repositories have no head commit
parent_commits = list()
# END handle parent commits
else:
for p in parent_commits:
if not isinstance(p, cls):
raise ValueError("Parent commit '%r' must be of type %s" % (p, cls))
# end check parent commit types
# END if parent commits are unset

# retrieve all additional information, create a commit object, and
Expand Down
2 changes: 1 addition & 1 deletion git/objects/submodule/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -781,7 +781,7 @@ def remove(self, module=True, force=False, configuration=True, dry_run=False):
csm.remove(module, force, configuration, dry_run)
del(csm)
# end
if not dry_run and nc > 0:
if configuration and not dry_run and nc > 0:
# Assure we don't leave the parent repository in a dirty state, and commit our changes
# It's important for recursive, unforced, deletions to work as expected
self.module().index.commit("Removed submodule '%s'" % self.name)
Expand Down
5 changes: 4 additions & 1 deletion git/refs/reference.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ def __str__(self):
#{ Interface

def set_object(self, object, logmsg=None):
"""Special version which checks if the head-log needs an update as well"""
"""Special version which checks if the head-log needs an update as well
:return: self"""
oldbinsha = None
if logmsg is not None:
head = self.repo.head
Expand All @@ -78,6 +79,8 @@ def set_object(self, object, logmsg=None):
self.repo.head.log_append(oldbinsha, logmsg)
# END check if the head

return self

# NOTE: Don't have to overwrite properties as the will only work without a the log

@property
Expand Down
29 changes: 18 additions & 11 deletions git/remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,8 @@ def _config_section_name(self):

def _set_cache_(self, attr):
if attr == "_config_reader":
# NOTE: This is cached as __getattr__ is overridden to return remote config values implicitly, such as
# in print(r.pushurl)
self._config_reader = SectionConstraint(self.repo.config_reader(), self._config_section_name())
else:
super(Remote, self)._set_cache_(attr)
Expand Down Expand Up @@ -475,8 +477,13 @@ def create(cls, repo, name, url, **kwargs):

@classmethod
def remove(cls, repo, name):
"""Remove the remote with the given name"""
"""Remove the remote with the given name
:return: the passed remote name to remove
"""
repo.git.remote("rm", name)
if isinstance(name, cls):
name._clear_cache()
return name

# alias
rm = remove
Expand All @@ -489,11 +496,8 @@ def rename(self, new_name):

self.repo.git.remote("rename", self.name, new_name)
self.name = new_name
try:
del(self._config_reader) # it contains cached values, section names are different now
except AttributeError:
pass
# END handle exception
self._clear_cache()

return self

def update(self, **kwargs):
Expand Down Expand Up @@ -662,6 +666,13 @@ def config_reader(self):
Hence you may simple type config.get("pushurl") to obtain the information"""
return self._config_reader

def _clear_cache(self):
try:
del(self._config_reader)
except AttributeError:
pass
# END handle exception

@property
def config_writer(self):
"""
Expand All @@ -676,9 +687,5 @@ def config_writer(self):
writer = self.repo.config_writer()

# clear our cache to assure we re-read the possibly changed configuration
try:
del(self._config_reader)
except AttributeError:
pass
# END handle exception
self._clear_cache()
return SectionConstraint(writer, self._config_section_name())
6 changes: 2 additions & 4 deletions git/repo/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,10 +209,8 @@ def _set_description(self, descr):

@property
def working_tree_dir(self):
""":return: The working tree directory of our git repository
:raise AssertionError: If we are a bare repository"""
if self._working_tree_dir is None:
raise AssertionError("Repository at %r is bare and does not have a working tree directory" % self.git_dir)
""":return: The working tree directory of our git repository. If this is a bare repository, None is returned.
"""
return self._working_tree_dir

@property
Expand Down
4 changes: 2 additions & 2 deletions git/test/fixtures/diff_rename
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ committer Michael Trier <mtrier@gmail.com> 1229389391 -0500

diff --git a/AUTHORS b/CONTRIBUTORS
similarity index 100%
rename from AUTHORS
rename to CONTRIBUTORS
rename from Jérôme
rename to müller
6 changes: 4 additions & 2 deletions git/test/test_diff.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#-*-coding:utf-8-*-
# test_diff.py
# Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors
#
Expand Down Expand Up @@ -53,8 +54,9 @@ def test_diff_with_rename(self):

diff = diffs[0]
assert_true(diff.renamed)
assert_equal(diff.rename_from, 'AUTHORS')
assert_equal(diff.rename_to, 'CONTRIBUTORS')
assert_equal(diff.rename_from, u'Jérôme')
assert_equal(diff.rename_to, u'müller')
assert isinstance(str(diff), str)

output = StringProcessAdapter(fixture('diff_rename_raw'))
diffs = Diff._index_from_raw_format(self.rorepo, output.stdout)
Expand Down
Loading

0 comments on commit e4d3809

Please sign in to comment.