From 794dbe7b9cb5475e6c98d5e51abe6b10a7c7151c Mon Sep 17 00:00:00 2001
From: Matthew Duggan <mgithub@guarana.org>
Date: Mon, 18 Aug 2014 18:22:45 +0900
Subject: [PATCH] set callbacks just before fetch, clear them after (fixes
 #403).

---
 pygit2/decl.h    |  2 ++
 pygit2/remote.py | 44 ++++++++++++++++++++++++++------------------
 2 files changed, 28 insertions(+), 18 deletions(-)

diff --git a/pygit2/decl.h b/pygit2/decl.h
index 5573ecd..0676b67 100644
--- a/pygit2/decl.h
+++ b/pygit2/decl.h
@@ -12,6 +12,7 @@ typedef ... git_index_conflict_iterator;
 
 #define GIT_OID_RAWSZ ...
 #define GIT_PATH_MAX ...
+#define GIT_REMOTE_CALLBACKS_VERSION ...
 
 typedef struct git_oid {
 	unsigned char id[20];
@@ -136,6 +137,7 @@ int git_remote_add_push(git_remote *remote, const char *refspec);
 int git_remote_add_fetch(git_remote *remote, const char *refspec);
 int git_remote_save(const git_remote *remote);
 int git_remote_set_callbacks(git_remote *remote, const git_remote_callbacks *callbacks);
+int git_remote_init_callbacks(git_remote_callbacks *opts, unsigned int version);
 size_t git_remote_refspec_count(git_remote *remote);
 const git_refspec * git_remote_get_refspec(git_remote *remote, size_t n);
 
diff --git a/pygit2/remote.py b/pygit2/remote.py
index b2fdec2..dfeb4d7 100644
--- a/pygit2/remote.py
+++ b/pygit2/remote.py
@@ -127,20 +127,6 @@ class Remote(object):
         self._remote = ptr
         self._stored_exception = None
 
-        # Build the callback structure
-        callbacks = ffi.new('git_remote_callbacks *')
-        callbacks.version = 1
-        callbacks.sideband_progress = self._sideband_progress_cb
-        callbacks.transfer_progress = self._transfer_progress_cb
-        callbacks.update_tips = self._update_tips_cb
-        callbacks.credentials = self._credentials_cb
-        # We need to make sure that this handle stays alive
-        self._self_handle = ffi.new_handle(self)
-        callbacks.payload = self._self_handle
-
-        err = C.git_remote_set_callbacks(self._remote, callbacks)
-        check_error(err)
-
     def __del__(self):
         C.git_remote_free(self._remote)
 
@@ -205,17 +191,39 @@ class Remote(object):
         Perform a fetch against this remote.
         """
 
+        defaultcallbacks = ffi.new('git_remote_callbacks *')
+        err = C.git_remote_init_callbacks(defaultcallbacks,
+                                          C.GIT_REMOTE_CALLBACKS_VERSION)
+
+        # Build the callback structure
+        callbacks = ffi.new('git_remote_callbacks *')
+        callbacks.version = 1
+        callbacks.sideband_progress = self._sideband_progress_cb
+        callbacks.transfer_progress = self._transfer_progress_cb
+        callbacks.update_tips = self._update_tips_cb
+        callbacks.credentials = self._credentials_cb
+        callbacks.payload = ffi.new_handle(self)
+
+        err = C.git_remote_set_callbacks(self._remote, callbacks)
+        check_error(err)
+
         if signature:
             ptr = signature._pointer[:]
         else:
             ptr = ffi.NULL
 
         self._stored_exception = None
-        err = C.git_remote_fetch(self._remote, ptr, to_bytes(message))
-        if self._stored_exception:
-            raise self._stored_exception
 
-        check_error(err)
+        try:
+            err = C.git_remote_fetch(self._remote, ptr, to_bytes(message))
+            if self._stored_exception:
+                raise self._stored_exception
+
+            check_error(err)
+        finally:
+            # Even on error, clear stored callbacks and reset to default
+            err = C.git_remote_set_callbacks(self._remote, defaultcallbacks)
+            check_error(err)
 
         return TransferProgress(C.git_remote_stats(self._remote))