summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml3
-rw-r--r--README.md10
-rw-r--r--VERSION2
-rw-r--r--doc/source/changes.rst14
-rw-r--r--doc/source/intro.rst8
-rw-r--r--doc/source/tutorial.rst8
-rw-r--r--git/cmd.py9
-rw-r--r--git/config.py6
-rw-r--r--git/objects/commit.py2
-rw-r--r--git/test/fixtures/.gitconfig3
-rw-r--r--git/test/lib/helper.py10
-rw-r--r--git/test/test_config.py15
-rw-r--r--git/test/test_docs.py2
-rw-r--r--git/test/test_remote.py5
-rw-r--r--git/util.py7
15 files changed, 72 insertions, 32 deletions
diff --git a/.travis.yml b/.travis.yml
index b53228ca..7aaf9f94 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -25,6 +25,9 @@ install:
# as commits are performed with the default user, it needs to be set for travis too
- git config --global user.email "travis@ci.com"
- git config --global user.name "Travis Runner"
+ # If we rewrite the user's config by accident, we will mess it up
+ # and cause subsequent tests to fail
+ - cat git/test/fixtures/.gitconfig >> ~/.gitconfig
script:
# Make sure we limit open handles to see if we are leaking them
- ulimit -n 96
diff --git a/README.md b/README.md
index 1895635f..3bd6508e 100644
--- a/README.md
+++ b/README.md
@@ -77,6 +77,7 @@ New BSD License. See the LICENSE file.
### DEVELOPMENT STATUS
[![Build Status](https://travis-ci.org/gitpython-developers/GitPython.svg?branch=0.3)](https://travis-ci.org/gitpython-developers/GitPython)
+[![Code Climate](https://codeclimate.com/github/gitpython-developers/GitPython/badges/gpa.svg)](https://codeclimate.com/github/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)
@@ -87,14 +88,5 @@ Now that there seems to be a massive user base, this should be motivation enough
* no open pull requests
* no open issues describing bugs
-#### FUTURE GOALS
-
-There has been a lot of work in the master branch, which is the direction I want git-python to go. Namely, it should be able to freely mix and match the back-end used, depending on your requirements and environment.
-
-* make new master work similarly to 0.3, but with the option to swap for at least one additional backend
-* make a 1.0 release
-* add backends as required
-
-
[twitch-channel]: http://www.twitch.tv/byronimo/profile
[youtube-playlist]: https://www.youtube.com/playlist?list=PLMHbQxe1e9MnoEcLhn6Yhv5KAvpWkJbL0 \ No newline at end of file
diff --git a/VERSION b/VERSION
index 0f826853..7dea76ed 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.3.7
+1.0.1
diff --git a/doc/source/changes.rst b/doc/source/changes.rst
index d9f44a86..e6d7b09b 100644
--- a/doc/source/changes.rst
+++ b/doc/source/changes.rst
@@ -2,6 +2,18 @@
Changelog
=========
+1.0.1 - Fixes
+=============
+
+* 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>`_
+
+1.0.0 - Notes
+=============
+
+This version is equivalent to v0.3.7, but finally acknowledges that GitPython is stable and production ready.
+
+It follows the `semantic version scheme <http://semver.org>`_, and thus will not break its existing API unless it goes 2.0.
+
0.3.7 - Fixes
=============
* `IndexFile.add()` will now write the index without any extension data by default. However, you may override this behaviour with the new `write_extension_data` keyword argument.
@@ -353,7 +365,7 @@ General
a treeish git cowardly refuses to pick one and asks for the command to use
the unambiguous syntax where '--' seperates the treeish from the paths.
-* ``Repo.commits``, ``Repo.commits_between``, ``Reop.commits_since``,
+* ``Repo.commits``, ``Repo.commits_between``, ``Repo.commits_since``,
``Repo.commit_count``, ``Repo.commit``, ``Commit.count`` and
``Commit.find_all`` all now optionally take a path argument which
constrains the lookup by path. This changes the order of the positional
diff --git a/doc/source/intro.rst b/doc/source/intro.rst
index b767ccd7..78d40344 100644
--- a/doc/source/intro.rst
+++ b/doc/source/intro.rst
@@ -90,9 +90,11 @@ Finally verify the installation by running the `nose powered <http://code.google
$ nosetests
-Mailing List
-============
-http://groups.google.com/group/git-python
+Questions and Answers
+=====================
+Please use stackoverflow for questions, and don't forget to tag it with `gitpython` to assure the right people see the question in a timely manner.
+
+http://stackoverflow.com/questions/tagged/gitpython
Issue Tracker
=============
diff --git a/doc/source/tutorial.rst b/doc/source/tutorial.rst
index 632d2d0c..7cc296d8 100644
--- a/doc/source/tutorial.rst
+++ b/doc/source/tutorial.rst
@@ -343,6 +343,14 @@ This one sets a custom script to be executed in place of `ssh`, and can be used
with repo.git.custom_environment(GIT_SSH=ssh_executable):
repo.remotes.origin.fetch()
+Here's an example executable that can be used in place of the `ssh_executable` above::
+
+ #!/bin/sh
+ ID_RSA=/var/lib/openshift/5562b947ecdd5ce939000038/app-deployments/id_rsa
+ exec /usr/bin/ssh -o StrictHostKeyChecking=no -i $ID_RSA "$@"
+
+Please note that the script must be executable (i.e. `chomd +x script.sh`). `StrictHostKeyChecking=no` is used to avoid prompts asking to save the hosts key to `~/.ssh/known_hosts`, which happens in case you run this as daemon.
+
You might also have a look at `Git.update_environment(...)` in case you want to setup a changed environment more permanently.
Submodule Handling
diff --git a/git/cmd.py b/git/cmd.py
index 429046be..87e482d8 100644
--- a/git/cmd.py
+++ b/git/cmd.py
@@ -530,7 +530,7 @@ class Git(LazyMixin):
* output_stream if extended_output = False
* tuple(int(status), output_stream, str(stderr)) if extended_output = True
- Note git is executed with LC_MESSAGES="C" to ensure consitent
+ Note git is executed with LC_MESSAGES="C" to ensure consistent
output regardless of system language.
:raise GitCommandError:
@@ -549,7 +549,12 @@ class Git(LazyMixin):
# Start the process
env = os.environ.copy()
- env["LC_MESSAGES"] = "C"
+ # Attempt to force all output to plain ascii english, which is what some parsing code
+ # may expect.
+ # According to stackoverflow (http://goo.gl/l74GC8), we are setting LANGUAGE as well
+ # just to be sure.
+ env["LANGUAGE"] = "C"
+ env["LC_ALL"] = "C"
env.update(self._environment)
if sys.platform == 'win32':
diff --git a/git/config.py b/git/config.py
index 38dd1b44..a6a25c7b 100644
--- a/git/config.py
+++ b/git/config.py
@@ -81,6 +81,7 @@ def set_dirty_and_flush_changes(non_const_func):
def flush_changes(self, *args, **kwargs):
rval = non_const_func(self, *args, **kwargs)
+ self._dirty = True
self.write()
return rval
# END wrapper method
@@ -190,6 +191,7 @@ class GitConfigParser(with_metaclass(MetaParserBuilder, cp.RawConfigParser, obje
self._file_or_files = file_or_files
self._read_only = read_only
+ self._dirty = False
self._is_initialized = False
self._merge_includes = merge_includes
self._lock = None
@@ -304,7 +306,7 @@ class GitConfigParser(with_metaclass(MetaParserBuilder, cp.RawConfigParser, obje
if mo:
# We might just have handled the last line, which could contain a quotation we want to remove
optname, vi, optval = mo.group('option', 'vi', 'value')
- if vi in ('=', ':') and ';' in optval:
+ if vi in ('=', ':') and ';' in optval and not optval.strip().startswith('"'):
pos = optval.find(';')
if pos != -1 and optval[pos - 1].isspace():
optval = optval[:pos]
@@ -433,6 +435,8 @@ class GitConfigParser(with_metaclass(MetaParserBuilder, cp.RawConfigParser, obje
:raise IOError: if this is a read-only writer instance or if we could not obtain
a file lock"""
self._assure_writable("write")
+ if not self._dirty:
+ return
if isinstance(self._file_or_files, (list, tuple)):
raise AssertionError("Cannot write back if there is not exactly a single file to write to, have %i files"
diff --git a/git/objects/commit.py b/git/objects/commit.py
index f13760fd..ac381cd9 100644
--- a/git/objects/commit.py
+++ b/git/objects/commit.py
@@ -445,7 +445,7 @@ class Commit(base.Object, Iterable, Diffable, Traversable, Serializable):
next_line = readline()
while next_line.startswith(b'mergetag '):
next_line = readline()
- while next_line.startswith(' '):
+ while next_line.startswith(b' '):
next_line = readline()
# end skip mergetags
diff --git a/git/test/fixtures/.gitconfig b/git/test/fixtures/.gitconfig
new file mode 100644
index 00000000..6a0459f6
--- /dev/null
+++ b/git/test/fixtures/.gitconfig
@@ -0,0 +1,3 @@
+[alias]
+ rbi = "!g() { git rebase -i origin/${1:-master} ; } ; g"
+ expush = "!f() { git branch -f tmp ; { git rbi $1 && git push ; } ; git reset --hard tmp ; git rebase origin/${1:-master}; } ; f" \ No newline at end of file
diff --git a/git/test/lib/helper.py b/git/test/lib/helper.py
index 541b972d..8be2881c 100644
--- a/git/test/lib/helper.py
+++ b/git/test/lib/helper.py
@@ -18,10 +18,11 @@ from git.compat import string_types
osp = os.path.dirname
GIT_REPO = os.environ.get("GIT_PYTHON_TEST_GIT_REPO_BASE", osp(osp(osp(osp(__file__)))))
+GIT_DAEMON_PORT = os.environ.get("GIT_PYTHON_TEST_GIT_DAEMON_PORT", "9418")
__all__ = (
'fixture_path', 'fixture', 'absolute_project_path', 'StringProcessAdapter',
- 'with_rw_repo', 'with_rw_and_rw_remote_repo', 'TestBase', 'TestCase', 'GIT_REPO'
+ 'with_rw_repo', 'with_rw_and_rw_remote_repo', 'TestBase', 'TestCase', 'GIT_REPO', 'GIT_DAEMON_PORT'
)
#{ Routines
@@ -193,14 +194,15 @@ def with_rw_and_rw_remote_repo(working_tree_ref):
# by the user, not by us
d_remote = Remote.create(rw_repo, "daemon_origin", remote_repo_dir)
d_remote.fetch()
- remote_repo_url = "git://localhost%s" % remote_repo_dir
+ remote_repo_url = "git://localhost:%s%s" % (GIT_DAEMON_PORT, remote_repo_dir)
d_remote.config_writer.set('url', remote_repo_url)
temp_dir = osp(_mktemp())
# On windows, this will fail ... we deal with failures anyway and default to telling the user to do it
try:
- gd = Git().daemon(temp_dir, enable='receive-pack', as_process=True)
+ gd = Git().daemon(temp_dir, enable='receive-pack', listen='127.0.0.1', port=GIT_DAEMON_PORT,
+ as_process=True)
# yes, I know ... fortunately, this is always going to work if sleep time is just large enough
time.sleep(0.5)
except Exception:
@@ -223,6 +225,8 @@ def with_rw_and_rw_remote_repo(working_tree_ref):
raise AssertionError(msg)
else:
msg = 'Please start a git-daemon to run this test, execute: git daemon --enable=receive-pack "%s"'
+ msg += 'You can also run the daemon on a different port by passing --port=<port>'
+ msg += 'and setting the environment variable GIT_PYTHON_TEST_GIT_DAEMON_PORT to <port>'
msg %= temp_dir
raise AssertionError(msg)
# END make assertion
diff --git a/git/test/test_config.py b/git/test/test_config.py
index fc2b87b6..7758a094 100644
--- a/git/test/test_config.py
+++ b/git/test/test_config.py
@@ -18,7 +18,6 @@ from git.compat import (
)
import io
import os
-from copy import copy
from git.config import cp
@@ -30,21 +29,18 @@ class TestBase(TestCase):
sio.name = file_path
return sio
- def _parsers_equal_or_raise(self, lhs, rhs):
- pass
-
def test_read_write(self):
# writer must create the exact same file as the one read before
for filename in ("git_config", "git_config_global"):
file_obj = self._to_memcache(fixture_path(filename))
- file_obj_orig = copy(file_obj)
w_config = GitConfigParser(file_obj, read_only=False)
w_config.read() # enforce reading
assert w_config._sections
w_config.write() # enforce writing
# we stripped lines when reading, so the results differ
- assert file_obj.getvalue() and file_obj.getvalue() != file_obj_orig.getvalue()
+ assert file_obj.getvalue()
+ self.assertEqual(file_obj.getvalue(), self._to_memcache(fixture_path(filename)).getvalue())
# creating an additional config writer must fail due to exclusive access
self.failUnlessRaises(IOError, GitConfigParser, file_obj, read_only=False)
@@ -207,3 +203,10 @@ class TestBase(TestCase):
assert not cw.has_section('core')
assert len(cw.items(nn)) == 4
cw.release()
+
+ def test_complex_aliases(self):
+ file_obj = self._to_memcache(fixture_path('.gitconfig'))
+ w_config = GitConfigParser(file_obj, read_only=False)
+ self.assertEqual(w_config.get('alias', 'rbi'), '"!g() { git rebase -i origin/${1:-master} ; } ; g"')
+ w_config.release()
+ self.assertEqual(file_obj.getvalue(), self._to_memcache(fixture_path('.gitconfig')).getvalue())
diff --git a/git/test/test_docs.py b/git/test/test_docs.py
index 586f0ce4..5b8aa817 100644
--- a/git/test/test_docs.py
+++ b/git/test/test_docs.py
@@ -94,7 +94,7 @@ class Tutorials(TestBase):
# [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')
+ assert (now.commit.tree / 'VERSION').data_stream.read().decode('ascii').startswith('1')
# You can traverse trees as well to handle all contained files of a particular commit
file_count = 0
diff --git a/git/test/test_remote.py b/git/test/test_remote.py
index c419ecee..af854988 100644
--- a/git/test/test_remote.py
+++ b/git/test/test_remote.py
@@ -8,7 +8,8 @@ from git.test.lib import (
TestBase,
with_rw_repo,
with_rw_and_rw_remote_repo,
- fixture
+ fixture,
+ GIT_DAEMON_PORT
)
from git import (
RemoteProgress,
@@ -250,7 +251,7 @@ class TestRemote(TestBase):
# must clone with a local path for the repo implementation not to freak out
# as it wants local paths only ( which I can understand )
other_repo = remote_repo.clone(other_repo_dir, shared=False)
- remote_repo_url = "git://localhost%s" % remote_repo.git_dir
+ remote_repo_url = "git://localhost:%s%s" % (GIT_DAEMON_PORT, remote_repo.git_dir)
# put origin to git-url
other_origin = other_repo.remotes.origin
diff --git a/git/util.py b/git/util.py
index 1147cb53..fb459da1 100644
--- a/git/util.py
+++ b/git/util.py
@@ -164,8 +164,9 @@ class RemoteProgress(object):
Handler providing an interface to parse progress information emitted by git-push
and git-fetch and to dispatch callbacks allowing subclasses to react to the progress.
"""
- _num_op_codes = 7
- BEGIN, END, COUNTING, COMPRESSING, WRITING, RECEIVING, RESOLVING = [1 << x for x in range(_num_op_codes)]
+ _num_op_codes = 8
+ BEGIN, END, COUNTING, COMPRESSING, WRITING, RECEIVING, RESOLVING, FINDING_SOURCES = \
+ [1 << x for x in range(_num_op_codes)]
STAGE_MASK = BEGIN | END
OP_MASK = ~STAGE_MASK
@@ -227,6 +228,8 @@ class RemoteProgress(object):
op_code |= self.RECEIVING
elif op_name == 'Resolving deltas':
op_code |= self.RESOLVING
+ elif op_name == 'Finding sources':
+ op_code |= self.FINDING_SOURCES
else:
# Note: On windows it can happen that partial lines are sent
# Hence we get something like "CompreReceiving objects", which is