diff --git a/MANIFEST.in b/MANIFEST.in
index 95b2e883f..4c02e39a3 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -4,7 +4,7 @@ include CHANGES
 include AUTHORS
 include README
 include requirements.txt
+include scripts/ssh_wrapper.py
 
 graft git/test/fixtures
 graft git/test/performance
-
diff --git a/doc/source/tutorial.rst b/doc/source/tutorial.rst
index c6e5626b5..6ca0fd877 100644
--- a/doc/source/tutorial.rst
+++ b/doc/source/tutorial.rst
@@ -383,6 +383,12 @@ You can easily access configuration information for a remote by accessing option
 Change configuration for a specific remote only::
     
     o.config_writer.set("pushurl", "other_url")
+
+You can also specify an SSH key to use for any operations on the remotes:
+
+    private_key_file = project_dir+'id_rsa_deployment_key'
+    with repo.git.sshkey(private_key_file):
+        o.fetch()
     
     
 Submodule Handling
diff --git a/git/cmd.py b/git/cmd.py
index 55ed74dd0..914424706 100644
--- a/git/cmd.py
+++ b/git/cmd.py
@@ -5,6 +5,7 @@
 # the BSD License: http://www.opensource.org/licenses/bsd-license.php
 
 import os
+import os.path
 import sys
 import select
 import logging
@@ -12,6 +13,7 @@
 import errno
 import mmap
 
+from contextlib import contextmanager
 from subprocess import (
     call,
     Popen,
@@ -139,7 +141,7 @@ def deplete_buffer(fno, handler, buf_list, wg=None):
 
     if hasattr(select, 'poll'):
         # poll is preferred, as select is limited to file handles up to 1024 ... . This could otherwise be
-        # an issue for us, as it matters how many handles or own process has
+        # an issue for us, as it matters how many handles our own process has
         poll = select.poll()
         READ_ONLY = select.POLLIN | select.POLLPRI | select.POLLHUP | select.POLLERR
         CLOSED = select.POLLHUP | select.POLLERR
@@ -223,7 +225,7 @@ class Git(LazyMixin):
         Set its value to 'full' to see details about the returned values.
     """
     __slots__ = ("_working_dir", "cat_file_all", "cat_file_header", "_version_info",
-                 "_git_options")
+                 "_git_options", "_environment")
 
     # CONFIGURATION
     # The size in bytes read from stdout when copying git's output to another stream
@@ -413,6 +415,9 @@ def __init__(self, working_dir=None):
         self._working_dir = working_dir
         self._git_options = ()
 
+        # Extra environment variables to pass to git commands
+        self._environment = {}
+
         # cached command slots
         self.cat_file_header = None
         self.cat_file_all = None
@@ -536,6 +541,8 @@ def execute(self, command,
         # Start the process
         env = os.environ.copy()
         env["LC_MESSAGES"] = "C"
+        env.update(self._environment)
+
         proc = Popen(command,
                      env=env,
                      cwd=cwd,
@@ -608,6 +615,76 @@ def as_text(stdout_value):
         else:
             return stdout_value
 
+    def environment(self):
+        return self._environment
+
+    def update_environment(self, **kwargs):
+        """
+        Set environment variables for future git invocations. Return all changed
+        values in a format that can be passed back into this function to revert
+        the changes:
+
+        ``Examples``::
+
+            old_env = self.update_environment(PWD='/tmp')
+            self.update_environment(**old_env)
+
+        :param kwargs: environment variables to use for git processes
+        :return: dict that maps environment variables to their old values
+        """
+        old_env = {}
+        for key, value in kwargs.iteritems():
+            # set value if it is None
+            if value is not None:
+                if key in self._environment:
+                    old_env[key] = self._environment[key]
+                else:
+                    old_env[key] = None
+                self._environment[key] = value
+            # remove key from environment if its value is None
+            elif key in self._environment:
+                old_env[key] = self._environment[key]
+                del self._environment[key]
+        return old_env
+
+    @contextmanager
+    def with_environment(self, **kwargs):
+        """
+        A context manager around the above update_environment to restore the
+        environment back to its previous state after operation.
+
+        ``Examples``::
+
+            with self.with_environment(GIT_SSH='/bin/ssh_wrapper'):
+                repo.remotes.origin.fetch()
+
+        :param kwargs: see update_environment
+        """
+        old_env = self.update_environment(**kwargs)
+        try:
+            yield
+        finally:
+            self.update_environment(**old_env)
+
+    @contextmanager
+    def sshkey(self, sshkey_file):
+        """
+        A context manager to temporarily set an SSH key for all operations that
+        run inside it.
+
+        ``Examples``::
+
+            with self.environment(GIT_SSH=project_dir+'deployment_key'):
+                repo.remotes.origin.fetch()
+
+        :param sshkey_file: Path to a private SSH key file
+        """
+        this_dir = os.path.dirname(__file__)
+        ssh_wrapper = os.path.join(this_dir, '..', 'scripts', 'ssh_wrapper.py')
+
+        with self.with_environment(GIT_SSH_KEY_FILE=sshkey_file, GIT_SSH=ssh_wrapper):
+            yield
+
     def transform_kwargs(self, split_single_char_options=False, **kwargs):
         """Transforms Python style kwargs into git command line options."""
         args = list()
@@ -731,7 +808,7 @@ def make_call():
                         import warnings
                         msg = "WARNING: Automatically switched to use git.cmd as git executable"
                         msg += ", which reduces performance by ~70%."
-                        msg += "Its recommended to put git.exe into the PATH or to "
+                        msg += "It is recommended to put git.exe into the PATH or to "
                         msg += "set the %s " % self._git_exec_env_var
                         msg += "environment variable to the executable's location"
                         warnings.warn(msg)
diff --git a/git/remote.py b/git/remote.py
index fcec52285..c176b43b7 100644
--- a/git/remote.py
+++ b/git/remote.py
@@ -354,7 +354,7 @@ def __init__(self, repo, name):
             # that it has the config_writer property, but instead calls __getattr__
             # which will not yield the expected results. 'pinging' the members
             # with a dir call creates the config_writer property that we require
-            # ... bugs like these make me wonder wheter python really wants to be used
+            # ... bugs like these make me wonder whether python really wants to be used
             # for production. It doesn't happen on linux though.
             dir(self)
         # END windows special handling
diff --git a/git/test/test_git.py b/git/test/test_git.py
index f25fa21a8..85ee56c6b 100644
--- a/git/test/test_git.py
+++ b/git/test/test_git.py
@@ -153,3 +153,23 @@ def test_env_vars_passed_to_git(self):
         editor = 'non_existant_editor'
         with mock.patch.dict('os.environ', {'GIT_EDITOR': editor}):
             assert self.git.var("GIT_EDITOR") == editor
+
+    def test_environment(self):
+        # sanity check
+        assert self.git.environment() == {}
+
+        # make sure the context manager works and cleans up after itself
+        with self.git.with_environment(PWD='/tmp'):
+            assert self.git.environment() == {'PWD': '/tmp'}
+
+        assert self.git.environment() == {}
+
+        old_env = self.git.update_environment(VARKEY='VARVALUE')
+        # The returned dict can be used to revert the change, hence why it has
+        # an entry with value 'None'.
+        assert old_env == {'VARKEY': None}
+        assert self.git.environment() == {'VARKEY': 'VARVALUE'}
+
+        new_env = self.git.update_environment(**old_env)
+        assert new_env == {'VARKEY': 'VARVALUE'}
+        assert self.git.environment() == {}
diff --git a/git/test/test_remote.py b/git/test/test_remote.py
index d4a92ed4d..bf2f76a86 100644
--- a/git/test/test_remote.py
+++ b/git/test/test_remote.py
@@ -163,11 +163,11 @@ def fetch_and_test(remote, **kwargs):
         def get_info(res, remote, name):
             return res["%s/%s" % (remote, name)]
 
-        # put remote head to master as it is garantueed to exist
+        # put remote head to master as it is guaranteed to exist
         remote_repo.head.reference = remote_repo.heads.master
 
         res = fetch_and_test(remote)
-        # all uptodate
+        # all up to date
         for info in res:
             assert info.flags & info.HEAD_UPTODATE
 
diff --git a/scripts/ssh_wrapper.py b/scripts/ssh_wrapper.py
new file mode 100755
index 000000000..af657f606
--- /dev/null
+++ b/scripts/ssh_wrapper.py
@@ -0,0 +1,9 @@
+#!/usr/bin/env python
+
+import os
+import subprocess
+import sys
+
+ssh_options = ['-i', os.environ['GIT_SSH_KEY_FILE']]
+ret_code = subprocess.call(['ssh'] + ssh_options + sys.argv[1:])
+sys.exit(ret_code)