summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Thiel <byronimo@gmail.com>2015-01-21 18:34:58 +0100
committerSebastian Thiel <byronimo@gmail.com>2015-01-21 18:34:58 +0100
commite4d3809161fc54d6913c0c2c7f6a7b51eebe223f (patch)
tree1eebc9f43a1302c537da84e9a7219918da131f45
parente48e52001d5abad7b28a4ecadde63c78c3946339 (diff)
downloadgitpython-e4d3809161fc54d6913c0c2c7f6a7b51eebe223f.tar.gz
Added advance usage examples to tutorial and made minor fixes.
GIT_PYTHON_TRACE would actually fail (now) if we debugged archive operations. Related to #239
-rw-r--r--README.md2
-rw-r--r--doc/source/reference.rst2
-rw-r--r--doc/source/tutorial.rst97
-rw-r--r--git/cmd.py9
-rw-r--r--git/objects/base.py2
-rw-r--r--git/objects/commit.py9
-rw-r--r--git/objects/submodule/base.py2
-rw-r--r--git/refs/reference.py5
-rw-r--r--git/remote.py29
-rw-r--r--git/repo/base.py6
-rw-r--r--git/test/fixtures/diff_rename4
-rw-r--r--git/test/test_diff.py6
-rw-r--r--git/test/test_docs.py142
-rw-r--r--git/test/test_remote.py4
-rw-r--r--tox.ini3
15 files changed, 270 insertions, 52 deletions
diff --git a/README.md b/README.md
index 57e9bbc9..bdc455b6 100644
--- a/README.md
+++ b/README.md
@@ -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
diff --git a/doc/source/reference.rst b/doc/source/reference.rst
index 8e0e296b..7a73fc71 100644
--- a/doc/source/reference.rst
+++ b/doc/source/reference.rst
@@ -17,6 +17,7 @@ Objects.Blob
.. automodule:: git.objects.blob
:members:
:undoc-members:
+ :special-members:
Objects.Commit
--------------
@@ -24,6 +25,7 @@ Objects.Commit
.. automodule:: git.objects.commit
:members:
:undoc-members:
+ :special-members:
Objects.Tag
-----------
diff --git a/doc/source/tutorial.rst b/doc/source/tutorial.rst
index adce5910..c6e5626b 100644
--- a/doc/source/tutorial.rst
+++ b/doc/source/tutorial.rst
@@ -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
********************
@@ -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
********************
@@ -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
***************************************
diff --git a/git/cmd.py b/git/cmd.py
index d6b29d91..55ed74dd 100644
--- a/git/cmd.py
+++ b/git/cmd.py
@@ -579,11 +579,16 @@ class Git(LazyMixin):
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
diff --git a/git/objects/base.py b/git/objects/base.py
index 42876fc8..77d0ed63 100644
--- a/git/objects/base.py
+++ b/git/objects/base.py
@@ -135,7 +135,7 @@ class IndexObject(Object):
: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:
diff --git a/git/objects/commit.py b/git/objects/commit.py
index f2ce91ca..b9718694 100644
--- a/git/objects/commit.py
+++ b/git/objects/commit.py
@@ -69,6 +69,7 @@ class Commit(base.Object, Iterable, Diffable, Traversable, Serializable):
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
@@ -97,7 +98,8 @@ class Commit(base.Object, Iterable, Diffable, Traversable, Serializable):
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)
@@ -296,6 +298,11 @@ class Commit(base.Object, Iterable, Diffable, Traversable, Serializable):
# 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
diff --git a/git/objects/submodule/base.py b/git/objects/submodule/base.py
index ebb66495..cd7d4ec4 100644
--- a/git/objects/submodule/base.py
+++ b/git/objects/submodule/base.py
@@ -781,7 +781,7 @@ class Submodule(util.IndexObject, Iterable, Traversable):
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)
diff --git a/git/refs/reference.py b/git/refs/reference.py
index 8741ebb9..3e132aef 100644
--- a/git/refs/reference.py
+++ b/git/refs/reference.py
@@ -51,7 +51,8 @@ class Reference(SymbolicReference, LazyMixin, Iterable):
#{ 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
@@ -78,6 +79,8 @@ class Reference(SymbolicReference, LazyMixin, Iterable):
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
diff --git a/git/remote.py b/git/remote.py
index dbb82796..fcec5228 100644
--- a/git/remote.py
+++ b/git/remote.py
@@ -378,6 +378,8 @@ class Remote(LazyMixin, Iterable):
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)
@@ -475,8 +477,13 @@ class Remote(LazyMixin, Iterable):
@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
@@ -489,11 +496,8 @@ class Remote(LazyMixin, Iterable):
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):
@@ -662,6 +666,13 @@ class Remote(LazyMixin, Iterable):
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):
"""
@@ -676,9 +687,5 @@ class Remote(LazyMixin, Iterable):
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())
diff --git a/git/repo/base.py b/git/repo/base.py
index ef12473b..ce8db7f7 100644
--- a/git/repo/base.py
+++ b/git/repo/base.py
@@ -209,10 +209,8 @@ class Repo(object):
@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
diff --git a/git/test/fixtures/diff_rename b/git/test/fixtures/diff_rename
index 13abae0e..2d5241e3 100644
--- a/git/test/fixtures/diff_rename
+++ b/git/test/fixtures/diff_rename
@@ -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
diff --git a/git/test/test_diff.py b/git/test/test_diff.py
index 42972603..f2ce1447 100644
--- a/git/test/test_diff.py
+++ b/git/test/test_diff.py
@@ -1,3 +1,4 @@
+#-*-coding:utf-8-*-
# test_diff.py
# Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors
#
@@ -53,8 +54,9 @@ class TestDiff(TestBase):
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)
diff --git a/git/test/test_docs.py b/git/test/test_docs.py
index 6befb9ea..9a04784d 100644
--- a/git/test/test_docs.py
+++ b/git/test/test_docs.py
@@ -21,14 +21,14 @@ class Tutorials(TestBase):
# For all you know, the first argument to Repo is a path to the repository
# you want to work with
repo = Repo(self.rorepo.working_tree_dir)
- assert repo.bare == False
+ assert not repo.bare
# ![1-test_init_repo_object]
# [2-test_init_repo_object]
- bare_empty_repo = Repo.init(join(rw_dir, 'bare-repo'), bare=True)
- assert bare_empty_repo.bare == True
+ bare_repo = Repo.init(join(rw_dir, 'bare-repo'), bare=True)
+ assert bare_repo.bare
# ![2-test_init_repo_object]
-
+
# [3-test_init_repo_object]
repo.config_reader() # get a config reader for read-only access
cw = repo.config_writer() # get a config writer to change configuration
@@ -41,16 +41,142 @@ class Tutorials(TestBase):
repo.untracked_files
# ['my_untracked_file']
# ![4-test_init_repo_object]
-
+
# [5-test_init_repo_object]
- assert repo.clone(join(rw_dir, 'to/this/path')).__class__ is Repo
+ cloned_repo = repo.clone(join(rw_dir, 'to/this/path'))
+ assert cloned_repo.__class__ is Repo # clone an existing repository
assert Repo.init(join(rw_dir, 'path/for/new/repo')).__class__ is Repo
# ![5-test_init_repo_object]
-
+
# [6-test_init_repo_object]
- repo.archive(open(join(rw_dir, 'repo.tar'), 'w'))
+ repo.archive(open(join(rw_dir, 'repo.tar'), 'wb'))
# ![6-test_init_repo_object]
+ # repository paths
+ # [7-test_init_repo_object]
+ assert os.path.isdir(cloned_repo.working_tree_dir) # directory with your work files
+ assert cloned_repo.git_dir.startswith(cloned_repo.working_tree_dir) # directory containing the git repository
+ assert bare_repo.working_tree_dir is None # bare repositories have no working tree
+ # ![7-test_init_repo_object]
+
+ # heads, tags and references
+ # heads are branches in git-speak
+ # [8-test_init_repo_object]
+ assert repo.head.ref == repo.heads.master # head is a symbolic reference pointing to master
+ assert repo.tags['0.3.5'] == repo.tag('refs/tags/0.3.5') # you can access tags in various ways too
+ assert repo.refs.master == repo.heads['master'] # .refs provides access to all refs, i.e. heads ...
+ assert repo.refs['origin/master'] == repo.remotes.origin.refs.master # ... remotes ...
+ assert repo.refs['0.3.5'] == repo.tags['0.3.5'] # ... and tags
+ # ![8-test_init_repo_object]
+
+ # create a new head/branch
+ # [9-test_init_repo_object]
+ new_branch = cloned_repo.create_head('feature') # create a new branch ...
+ assert cloned_repo.active_branch != new_branch # which wasn't checked out yet ...
+ assert new_branch.commit == cloned_repo.active_branch.commit # and which points to the checked-out commit
+ # It's easy to let a branch point to the previous commit, without affecting anything else
+ # Each reference provides access to the git object it points to, usually commits
+ assert new_branch.set_commit('HEAD~1').commit == cloned_repo.active_branch.commit.parents[0]
+ # ![9-test_init_repo_object]
+
+ # create a new tag reference
+ # [10-test_init_repo_object]
+ past = cloned_repo.create_tag('past', ref=new_branch,
+ message="This is a tag-object pointing to %s" % new_branch.name)
+ assert past.commit == new_branch.commit # the tag points to the specified commit
+ assert past.tag.message.startswith("This is") # and its object carries the message provided
+
+ now = cloned_repo.create_tag('now') # This is a tag-reference. It may not carry meta-data
+ assert now.tag is None
+ # ![10-test_init_repo_object]
+
+ # Object handling
+ # [11-test_init_repo_object]
+ assert now.commit.message != past.commit.message
+ # You can read objects directly through binary streams, no working tree required
+ assert (now.commit.tree / 'VERSION').data_stream.read().decode('ascii').startswith('0')
+
+ # You can traverse trees as well to handle all contained files of a particular commit
+ file_count = 0
+ tree_count = 0
+ tree = past.commit.tree
+ for item in tree.traverse():
+ file_count += item.type == 'blob'
+ tree_count += item.type == 'tree'
+ assert file_count and tree_count # we have accumulated all directories and files
+ assert len(tree.blobs) + len(tree.trees) == len(tree) # a tree is iterable itself to traverse its children
+ # ![11-test_init_repo_object]
+
+ # remotes allow handling push, pull and fetch operations
+ # [12-test_init_repo_object]
+ from git import RemoteProgress
+
+ class MyProgressPrinter(RemoteProgress):
+ def update(self, op_code, cur_count, max_count=None, message=''):
+ print(op_code, cur_count, max_count, cur_count / (max_count or 100.0), message or "NO MESSAGE")
+ # end
+
+ assert len(cloned_repo.remotes) == 1 # we have been cloned, so there should be one remote
+ assert len(bare_repo.remotes) == 0 # this one was just initialized
+ origin = bare_repo.create_remote('origin', url=cloned_repo.working_tree_dir)
+ assert origin.exists()
+ for fetch_info in origin.fetch(progress=MyProgressPrinter()):
+ print("Updated %s to %s" % (fetch_info.ref, fetch_info.commit))
+ # create a local branch at the latest fetched master. We specify the name statically, but you have all
+ # information to do it programatically as well.
+ bare_master = bare_repo.create_head('master', origin.refs.master)
+ bare_repo.head.set_reference(bare_master)
+ assert not bare_repo.delete_remote(origin).exists()
+ # push and pull behave very similarly
+ # ![12-test_init_repo_object]
+
+ # index
+ # [13-test_init_repo_object]
+ assert new_branch.checkout() == cloned_repo.active_branch # checking out a branch adjusts the working tree
+ assert new_branch.commit == past.commit # Now the past is checked out
+
+ new_file_path = os.path.join(cloned_repo.working_tree_dir, 'my-new-file')
+ open(new_file_path, 'wb').close() # create new file in working tree
+ cloned_repo.index.add([new_file_path]) # add it to the index
+ # Commit the changes to deviate masters history
+ cloned_repo.index.commit("Added a new file in the past - for later merege")
+
+ # prepare a merge
+ master = cloned_repo.heads.master # right-hand side is ahead of us, in the future
+ merge_base = cloned_repo.merge_base(new_branch, master) # allwos for a three-way merge
+ cloned_repo.index.merge_tree(master, base=merge_base) # write the merge result into index
+ cloned_repo.index.commit("Merged past and now into future ;)",
+ parent_commits=(new_branch.commit, master.commit))
+
+ # now new_branch is ahead of master, which probably should be checked out and reset softly.
+ # note that all these operations didn't touch the working tree, as we managed it ourselves.
+ # This definitely requires you to know what you are doing :) !
+ assert os.path.basename(new_file_path) in new_branch.commit.tree # new file is now in tree
+ master.commit = new_branch.commit # let master point to most recent commit
+ cloned_repo.head.reference = master # we adjusted just the reference, not the working tree or index
+ # ![13-test_init_repo_object]
+
+ # submodules
+
+ # [14-test_init_repo_object]
+ # create a new submodule and check it out on the spot, setup to track master branch of `bare_repo`
+ # As our GitPython repository has submodules already that point to github, make sure we don't
+ # interact with them
+ for sm in cloned_repo.submodules:
+ assert not sm.remove().exists() # after removal, the sm doesn't exist anymore
+ sm = cloned_repo.create_submodule('mysubrepo', 'path/to/subrepo', url=bare_repo.git_dir, branch='master')
+
+ # .gitmodules was written and added to the index, which is now being committed
+ cloned_repo.index.commit("Added submodule")
+ assert sm.exists() and sm.module_exists() # this submodule is defintely available
+ sm.remove(module=True, configuration=False) # remove the working tree
+ assert sm.exists() and not sm.module_exists() # the submodule itself is still available
+
+ # update all submodules, non-recursively to save time, this method is very powerful, go have a look
+ cloned_repo.submodule_update(recursive=False)
+ assert sm.module_exists() # The submodules working tree was checked out by update
+ # ![14-test_init_repo_object]
+
@with_rw_directory
def test_add_file_and_commit(self, rw_dir):
import git
diff --git a/git/test/test_remote.py b/git/test/test_remote.py
index 110f1fa5..d4a92ed4 100644
--- a/git/test/test_remote.py
+++ b/git/test/test_remote.py
@@ -451,11 +451,15 @@ class TestRemote(TestBase):
remote = Remote.create(bare_rw_repo, *arg_list)
assert remote.name == "test_new_one"
assert remote in bare_rw_repo.remotes
+ assert remote.exists()
# create same one again
self.failUnlessRaises(GitCommandError, Remote.create, bare_rw_repo, *arg_list)
Remote.remove(bare_rw_repo, new_name)
+ assert remote.exists() # We still have a cache that doesn't know we were deleted by name
+ remote._clear_cache()
+ assert not remote.exists() # Cache should be renewed now. This is an issue ...
for remote in bare_rw_repo.remotes:
if remote.name == new_name:
diff --git a/tox.ini b/tox.ini
index a3509756..bb1e9a85 100644
--- a/tox.ini
+++ b/tox.ini
@@ -18,6 +18,7 @@ commands = {posargs}
[flake8]
#show-source = True
# E265 = comment blocks like @{ section, which it can't handle
-ignore = E265
+# W293 = Blank line contains whitespace
+ignore = E265,W293
max-line-length = 120
exclude = .tox,.venv,build,dist,doc,git/ext/