Blob Blame History Raw
From 81520c9c626e092bc45f9fc8ba138eefa4d1beb2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= <cmn@dwim.me>
Date: Mon, 8 Jun 2015 12:19:01 +0200
Subject: [PATCH] Update to libgit2 v0.23

---
 .travis.sh           |   2 +-
 pygit2/__init__.py   |   8 +--
 pygit2/config.py     |  43 ++++++++++-----
 pygit2/decl.h        | 129 +++++++++++++++++++++++++++++++--------------
 pygit2/remote.py     | 144 ++++++++++++++++++---------------------------------
 pygit2/repository.py |  63 +++++++++++-----------
 pygit2/utils.py      |   5 ++
 src/branch.c         |   2 +-
 src/pygit2.c         |   3 +-
 src/reference.c      |  22 +++-----
 src/repository.c     |  12 ++---
 src/types.h          |   4 +-
 test/test_merge.py   |   2 +-
 test/test_refs.py    |   3 +-
 test/test_remote.py  |  65 ++++++-----------------
 15 files changed, 252 insertions(+), 255 deletions(-)

diff --git a/pygit2/__init__.py b/pygit2/__init__.py
index d963bca..709adca 100644
--- a/pygit2/__init__.py
+++ b/pygit2/__init__.py
@@ -278,12 +278,12 @@ def clone_repository(
 
     opts.bare = bare
     if credentials:
-        opts.remote_callbacks.credentials = _credentials_cb
-        opts.remote_callbacks.payload = d_handle
+        opts.fetch_opts.callbacks.credentials = _credentials_cb
+        opts.fetch_opts.callbacks.payload = d_handle
 
     if certificate:
-        opts.remote_callbacks.certificate_check = _certificate_cb
-        opts.remote_callbacks.payload = d_handle
+        opts.fetch_opts.callbacks.certificate_check = _certificate_cb
+        opts.fetch_opts.callbacks.payload = d_handle
 
     err = C.git_clone(crepo, to_bytes(url), to_bytes(path), opts)
 
diff --git a/pygit2/config.py b/pygit2/config.py
index 33cc6da..a01fdf6 100644
--- a/pygit2/config.py
+++ b/pygit2/config.py
@@ -101,19 +101,19 @@ class Config(object):
     def _get(self, key):
         assert_string(key, "key")
 
-        cstr = ffi.new('char **')
-        err = C.git_config_get_string(cstr, self._config, to_bytes(key))
+        entry = ffi.new('git_config_entry **')
+        err = C.git_config_get_entry(entry, self._config, to_bytes(key))
 
-        return err, cstr
+        return err, ConfigEntry._from_c(entry[0])
 
-    def _get_string(self, key):
-        err, cstr = self._get(key)
+    def _get_entry(self, key):
+        err, entry = self._get(key)
 
         if err == C.GIT_ENOTFOUND:
             raise KeyError(key)
 
         check_error(err)
-        return cstr[0]
+        return entry
 
     def __contains__(self, key):
         err, cstr = self._get(key)
@@ -126,9 +126,9 @@ class Config(object):
         return True
 
     def __getitem__(self, key):
-        val = self._get_string(key)
+        entry = self._get_entry(key)
 
-        return ffi.string(val).decode('utf-8')
+        return ffi.string(entry.value).decode('utf-8')
 
     def __setitem__(self, key, value):
         assert_string(key, "key")
@@ -192,9 +192,10 @@ class Config(object):
         Truthy values are: 'true', 1, 'on' or 'yes'. Falsy values are: 'false',
         0, 'off' and 'no'
         """
-        val = self._get_string(key)
+
+        entry = self._get_entry(key)
         res = ffi.new('int *')
-        err = C.git_config_parse_bool(res, val)
+        err = C.git_config_parse_bool(res, entry.value)
         check_error(err)
 
         return res[0] != 0
@@ -206,9 +207,10 @@ class Config(object):
         A value can have a suffix 'k', 'm' or 'g' which stand for 'kilo',
         'mega' and 'giga' respectively.
         """
-        val = self._get_string(key)
+
+        entry = self._get_entry(key)
         res = ffi.new('int64_t *')
-        err = C.git_config_parse_int64(res, val)
+        err = C.git_config_parse_int64(res, entry.value)
         check_error(err)
 
         return res[0]
@@ -283,3 +285,20 @@ class Config(object):
         """Return a <Config> object representing the global configuration file.
         """
         return Config._from_found_config(C.git_config_find_xdg)
+
+class ConfigEntry(object):
+    """An entry in a configuation object
+    """
+
+    @classmethod
+    def _from_c(cls, ptr):
+        entry = cls.__new__(cls)
+        entry._entry = ptr
+        return entry
+
+    def __del__(self):
+        C.git_config_entry_free(self._entry)
+
+    @property
+    def value(self):
+        return self._entry.value
diff --git a/pygit2/decl.h b/pygit2/decl.h
index 2ea73f2..61afe33 100644
--- a/pygit2/decl.h
+++ b/pygit2/decl.h
@@ -1,6 +1,7 @@
 typedef ... git_repository;
 typedef ... git_submodule;
 typedef ... git_remote;
+typedef ... git_transport;
 typedef ... git_refspec;
 typedef ... git_cred;
 typedef ... git_object;
@@ -51,7 +52,7 @@ typedef enum {
 	GIT_EUNMERGED = -10,
 	GIT_ENONFASTFORWARD = -11,
 	GIT_EINVALIDSPEC = -12,
-	GIT_EMERGECONFLICT = -13,
+	GIT_ECONFLICT = -13,
 	GIT_ELOCKED = -14,
 
 	GIT_PASSTHROUGH = -30,
@@ -118,6 +119,7 @@ typedef enum {
 } git_credtype_t;
 
 typedef enum git_cert_t {
+	GIT_CERT_NONE,
 	GIT_CERT_X509,
 	GIT_CERT_HOSTKEY_LIBSSH2,
 } git_cert_t;
@@ -165,6 +167,16 @@ typedef int (*git_push_transfer_progress)(
 	size_t bytes,
 	void* payload);
 
+typedef struct {
+	char *src_refname;
+	char *dst_refname;
+	git_oid src;
+	git_oid dst;
+} git_push_update;
+
+typedef int (*git_push_negotiation)(const git_push_update **updates, size_t len, void *payload);
+typedef int (*git_transport_cb)(git_transport **out, git_remote *owner, void *param);
+
 struct git_remote_callbacks {
 	unsigned int version;
 	git_transport_message_cb sideband_progress;
@@ -173,19 +185,51 @@ struct git_remote_callbacks {
     git_transport_certificate_check_cb certificate_check;
 	git_transfer_progress_cb transfer_progress;
 	int (*update_tips)(const char *refname, const git_oid *a, const git_oid *b, void *data);
-    git_packbuilder_progress pack_progress;
+	git_packbuilder_progress pack_progress;
 	git_push_transfer_progress push_transfer_progress;
 	int (*push_update_reference)(const char *refname, const char *status, void *data);
+	git_push_negotiation push_negotiation;
+	git_transport_cb transport;
 	void *payload;
 };
 
+#define GIT_REMOTE_CALLBACKS_VERSION ...
+
 typedef struct git_remote_callbacks git_remote_callbacks;
 
 typedef struct {
 	unsigned int version;
 	unsigned int pb_parallelism;
+	git_remote_callbacks callbacks;
 } git_push_options;
 
+#define GIT_PUSH_OPTIONS_VERSION ...
+int git_push_init_options(git_push_options *opts, unsigned int version);
+
+typedef enum {
+	GIT_FETCH_PRUNE_UNSPECIFIED,
+	GIT_FETCH_PRUNE,
+	GIT_FETCH_NO_PRUNE,
+} git_fetch_prune_t;
+
+typedef enum {
+	GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED = 0,
+	GIT_REMOTE_DOWNLOAD_TAGS_AUTO,
+	GIT_REMOTE_DOWNLOAD_TAGS_NONE,
+	GIT_REMOTE_DOWNLOAD_TAGS_ALL,
+} git_remote_autotag_option_t;
+
+typedef struct {
+	int version;
+	git_remote_callbacks callbacks;
+	git_fetch_prune_t prune;
+	int update_fetchhead;
+	git_remote_autotag_option_t download_tags;
+} git_fetch_options;
+
+#define GIT_FETCH_OPTIONS_VERSION ...
+int git_fetch_init_options(git_fetch_options *opts,	unsigned int version);
+
 int git_remote_list(git_strarray *out, git_repository *repo);
 int git_remote_lookup(git_remote **out, git_repository *repo, const char *name);
 int git_remote_create(
@@ -201,24 +245,20 @@ const char * git_remote_name(const git_remote *remote);
 
 int git_remote_rename(git_strarray *problems, git_repository *repo, const char *name, const char *new_name);
 const char * git_remote_url(const git_remote *remote);
-int git_remote_set_url(git_remote *remote, const char* url);
+int git_remote_set_url(git_repository *repo, const char *remote, const char* url);
 const char * git_remote_pushurl(const git_remote *remote);
-int git_remote_set_pushurl(git_remote *remote, const char* url);
-int git_remote_fetch(git_remote *remote, const git_strarray *refspecs, const git_signature *signature, const char *reflog_message);
-int git_remote_push(git_remote *remote,	git_strarray *refspecs,	const git_push_options *opts, const git_signature *signature, const char *reflog_message);
+int git_remote_set_pushurl(git_repository *repo, const char *remote, const char* url);
+int git_remote_fetch(git_remote *remote, const git_strarray *refspecs, const git_fetch_options *opts, const char *reflog_message);
+int git_remote_push(git_remote *remote, const git_strarray *refspecs, const git_push_options *opts);
 const git_transfer_progress * git_remote_stats(git_remote *remote);
-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_add_push(git_repository *repo, const char *remote, const char *refspec);
+int git_remote_add_fetch(git_repository *repo, const char *remote, const char *refspec);
 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);
 
 int git_remote_get_fetch_refspecs(git_strarray *array, git_remote *remote);
-int git_remote_set_fetch_refspecs(git_remote *remote, git_strarray *array);
 int git_remote_get_push_refspecs(git_strarray *array, git_remote *remote);
-int git_remote_set_push_refspecs(git_remote *remote, git_strarray *array);
 
 void git_remote_free(git_remote *remote);
 
@@ -253,13 +293,12 @@ int git_cred_ssh_key_from_agent(
  */
 
 typedef enum {
-	GIT_SUBMODULE_IGNORE_RESET     = -1,
+	GIT_SUBMODULE_IGNORE_UNSPECIFIED     = -1,
 
 	GIT_SUBMODULE_IGNORE_NONE      = 1,
 	GIT_SUBMODULE_IGNORE_UNTRACKED = 2,
 	GIT_SUBMODULE_IGNORE_DIRTY     = 3,
 	GIT_SUBMODULE_IGNORE_ALL       = 4,
-	GIT_SUBMODULE_IGNORE_DEFAULT   = 0
 } git_submodule_ignore_t;
 
 typedef enum {
@@ -348,32 +387,37 @@ typedef void (*git_checkout_progress_cb)(
 	size_t total_steps,
 	void *payload);
 
+typedef struct {
+	size_t mkdir_calls;
+	size_t stat_calls;
+	size_t chmod_calls;
+} git_checkout_perfdata;
+
+typedef void (*git_checkout_perfdata_cb)(
+	const git_checkout_perfdata *perfdata,
+	void *payload);
+
 typedef struct git_checkout_options {
 	unsigned int version;
-
 	unsigned int checkout_strategy;
-
 	int disable_filters;
 	unsigned int dir_mode;
 	unsigned int file_mode;
 	int file_open_flags;
-
 	unsigned int notify_flags;
 	git_checkout_notify_cb notify_cb;
 	void *notify_payload;
-
 	git_checkout_progress_cb progress_cb;
 	void *progress_payload;
-
 	git_strarray paths;
-
 	git_tree *baseline;
-
+	git_index *baseline_index;
 	const char *target_directory;
-
 	const char *ancestor_label;
 	const char *our_label;
 	const char *their_label;
+	git_checkout_perfdata_cb perfdata_cb;
+	void *perfdata_payload;
 } git_checkout_options;
 
 int git_checkout_init_options(git_checkout_options *opts, unsigned int version);
@@ -408,11 +452,10 @@ typedef enum {
 typedef struct git_clone_options {
 	unsigned int version;
 	git_checkout_options checkout_opts;
-	git_remote_callbacks remote_callbacks;
+	git_fetch_options fetch_opts;
 	int bare;
 	git_clone_local_t local;
 	const char* checkout_branch;
-	git_signature *signature;
 	git_repository_create_cb repository_cb;
 	void *repository_cb_payload;
 	git_remote_create_cb remote_cb;
@@ -443,16 +486,21 @@ typedef enum {
 	GIT_CONFIG_HIGHEST_LEVEL = -1,
 } git_config_level_t;
 
-typedef struct {
+typedef struct git_config_entry {
 	const char *name;
 	const char *value;
 	git_config_level_t level;
+	void (*free)(struct git_config_entry *entry);
+	void *payload;
 } git_config_entry;
 
+void git_config_entry_free(git_config_entry *);
+
 int git_repository_config(git_config **out, git_repository *repo);
 int git_repository_config_snapshot(git_config **out, git_repository *repo);
 void git_config_free(git_config *cfg);
 
+int git_config_get_entry(git_config_entry **out, const git_config *cfg, const char *name);
 int git_config_get_string(const char **out, const git_config *cfg, const char *name);
 int git_config_set_string(git_config *cfg, const char *name, const char *value);
 int git_config_set_bool(git_config *cfg, const char *name, int value);
@@ -535,8 +583,10 @@ int git_repository_init_ext(
 	const char *repo_path,
 	git_repository_init_options *opts);
 
-int git_repository_set_head(git_repository *repo, const char *refname, const git_signature *signature, const char *log_message);
-int git_repository_set_head_detached(git_repository *repo, const git_oid *commitish, const git_signature *signature, const char *log_message);
+int git_repository_set_head(git_repository *repo, const char *refname);
+int git_repository_set_head_detached(git_repository *repo, const git_oid *commitish);
+int git_repository_ident(const char **name, const char **email, const git_repository *repo);
+int git_repository_set_ident(git_repository *repo, const char *name, const char *email);
 int git_graph_ahead_behind(size_t *ahead, size_t *behind, git_repository *repo, const git_oid *local, const git_oid *upstream);
 
 /*
@@ -557,25 +607,25 @@ const char *git_submodule_branch(git_submodule *subm);
 typedef int64_t git_time_t;
 
 typedef struct {
-	git_time_t seconds;
-	unsigned int nanoseconds;
+	int32_t seconds;
+	uint32_t nanoseconds;
 } git_index_time;
 
 typedef struct git_index_entry {
 	git_index_time ctime;
 	git_index_time mtime;
 
-	unsigned int dev;
-	unsigned int ino;
-	unsigned int mode;
-	unsigned int uid;
-	unsigned int gid;
-	git_off_t file_size;
+	uint32_t dev;
+	uint32_t ino;
+	uint32_t mode;
+	uint32_t uid;
+	uint32_t gid;
+	uint32_t file_size;
 
 	git_oid id;
 
-	unsigned short flags;
-	unsigned short flags_extended;
+	uint16_t flags;
+	uint16_t flags_extended;
 
 	const char *path;
 } git_index_entry;
@@ -664,13 +714,16 @@ typedef enum {
 
 typedef struct {
 	unsigned int version;
-	git_merge_tree_flag_t flags;
+	git_merge_tree_flag_t tree_flags;
 	unsigned int rename_threshold;
 	unsigned int target_limit;
 	git_diff_similarity_metric *metric;
 	git_merge_file_favor_t file_favor;
+	unsigned int file_flags;
 } git_merge_options;
 
+#define GIT_MERGE_OPTIONS_VERSION 1
+
 typedef struct {
 	unsigned int automergeable;
 	const char *path;
diff --git a/pygit2/remote.py b/pygit2/remote.py
index 8d2416b..7ec5bd4 100644
--- a/pygit2/remote.py
+++ b/pygit2/remote.py
@@ -153,74 +153,44 @@ class Remote(object):
 
         return maybe_string(C.git_remote_url(self._remote))
 
-    @url.setter
-    def url(self, value):
-        err = C.git_remote_set_url(self._remote, to_bytes(value))
-        check_error(err)
-
     @property
     def push_url(self):
         """Push url of the remote"""
 
         return maybe_string(C.git_remote_pushurl(self._remote))
 
-    @push_url.setter
-    def push_url(self, value):
-        err = C.git_remote_set_pushurl(self._remote, to_bytes(value))
-        check_error(err)
-
     def save(self):
         """Save a remote to its repository's configuration."""
 
         err = C.git_remote_save(self._remote)
         check_error(err)
 
-    def fetch(self, signature=None, message=None):
+    def fetch(self, refspecs=None, message=None):
         """Perform a fetch against this remote. Returns a <TransferProgress>
         object.
         """
 
-        # Get the default callbacks first
-        defaultcallbacks = ffi.new('git_remote_callbacks *')
-        err = C.git_remote_init_callbacks(defaultcallbacks, 1)
-        check_error(err)
+        fetch_opts = ffi.new('git_fetch_options *')
+        err = C.git_fetch_init_options(fetch_opts, C.GIT_FETCH_OPTIONS_VERSION)
 
-        # Build custom 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
+        fetch_opts.callbacks.sideband_progress = self._sideband_progress_cb
+        fetch_opts.callbacks.transfer_progress = self._transfer_progress_cb
+        fetch_opts.callbacks.update_tips = self._update_tips_cb
+        fetch_opts.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)
-        try:
-            check_error(err)
-        except:
-            self._self_handle = None
-            raise
-
-        if signature:
-            ptr = signature._pointer[:]
-        else:
-            ptr = ffi.NULL
+        fetch_opts.callbacks.payload = self._self_handle
 
         self._stored_exception = None
 
         try:
-            err = C.git_remote_fetch(self._remote, ffi.NULL, ptr, to_bytes(message))
-            if self._stored_exception:
-                raise self._stored_exception
-
-            check_error(err)
+            with StrArray(refspecs) as arr:
+                err = C.git_remote_fetch(self._remote, arr, fetch_opts, 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
             self._self_handle = None
-            err = C.git_remote_set_callbacks(self._remote, defaultcallbacks)
-            check_error(err)
 
         return TransferProgress(C.git_remote_stats(self._remote))
 
@@ -245,12 +215,6 @@ class Remote(object):
 
         return strarray_to_strings(specs)
 
-    @fetch_refspecs.setter
-    def fetch_refspecs(self, l):
-        with StrArray(l) as arr:
-            err = C.git_remote_set_fetch_refspecs(self._remote, arr)
-            check_error(err)
-
     @property
     def push_refspecs(self):
         """Refspecs that will be used for pushing"""
@@ -261,64 +225,28 @@ class Remote(object):
 
         return strarray_to_strings(specs)
 
-    @push_refspecs.setter
-    def push_refspecs(self, l):
-        with StrArray(l) as arr:
-            err = C.git_remote_set_push_refspecs(self._remote, arr)
-            check_error(err)
-
-    def add_fetch(self, refspec):
-        """Add a fetch refspec (str) to the remote."""
-        err = C.git_remote_add_fetch(self._remote, to_bytes(refspec))
-        check_error(err)
-
-    def add_push(self, refspec):
-        """Add a push refspec (str) to the remote."""
-        err = C.git_remote_add_push(self._remote, to_bytes(refspec))
-        check_error(err)
-
-    def push(self, specs, signature=None, message=None):
+    def push(self, specs):
         """Push the given refspec to the remote. Raises ``GitError`` on
         protocol error or unpack failure.
 
         :param [str] specs: push refspecs to use
-        :param Signature signature: signature to use when updating the tips (optional)
-        :param str message: message to use when updating the tips (optional)
         """
-        # Get the default callbacks first
-        defaultcallbacks = ffi.new('git_remote_callbacks *')
-        err = C.git_remote_init_callbacks(defaultcallbacks, 1)
-        check_error(err)
-
-        if signature:
-            sig_cptr = ffi.new('git_signature **')
-            ffi.buffer(sig_cptr)[:] = signature._pointer[:]
-            sig_ptr = sig_cptr[0]
-        else:
-            sig_ptr = ffi.NULL
+        push_opts = ffi.new('git_push_options *')
+        err = C.git_push_init_options(push_opts, C.GIT_PUSH_OPTIONS_VERSION)
 
         # Build custom 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.push_update_reference = self._push_update_reference_cb
+        push_opts.callbacks.sideband_progress = self._sideband_progress_cb
+        push_opts.callbacks.transfer_progress = self._transfer_progress_cb
+        push_opts.callbacks.update_tips = self._update_tips_cb
+        push_opts.callbacks.credentials = self._credentials_cb
+        push_opts.callbacks.push_update_reference = self._push_update_reference_cb
         # We need to make sure that this handle stays alive
         self._self_handle = ffi.new_handle(self)
-        callbacks.payload = self._self_handle
-
-        try:
-            err = C.git_remote_set_callbacks(self._remote, callbacks)
-            check_error(err)
-        except:
-            self._self_handle = None
-            raise
+        push_opts.callbacks.payload = self._self_handle
 
         try:
             with StrArray(specs) as refspecs:
-                err = C.git_remote_push(self._remote, refspecs, ffi.NULL, sig_ptr, to_bytes(message))
+                err = C.git_remote_push(self._remote, refspecs, ffi.NULL)
                 check_error(err)
         finally:
             self._self_handle = None
@@ -551,3 +479,29 @@ class RemoteCollection(object):
         """
         err = C.git_remote_delete(self._repo._repo, to_bytes(name))
         check_error(err)
+
+    def set_url(self, name, url):
+        """ Set the URL for a remote
+        """
+        err = C.git_remote_set_url(self._repo._repo, to_bytes(name), to_bytes(url))
+        check_error(err)
+
+    def set_push_url(self, name, url):
+        """Set the push-URL for a remote
+        """
+        err = C.git_remote_set_pushurl(self._repo._repo, to_bytes(name), to_bytes(url))
+        check_error(err)
+
+    def add_fetch(self, name, refspec):
+        """Add a fetch refspec (str) to the remote
+        """
+
+        err = C.git_remote_add_fetch(self._repo._repo, to_bytes(name), to_bytes(refspec))
+        check_error(err)
+
+    def add_push(self, name, refspec):
+        """Add a push refspec (str) to the remote
+        """
+
+        err = C.git_remote_add_push(self._repo._repo, to_bytes(name), to_bytes(refspec))
+        check_error(err)
diff --git a/pygit2/repository.py b/pygit2/repository.py
index 64c08f9..b92a3a2 100644
--- a/pygit2/repository.py
+++ b/pygit2/repository.py
@@ -40,7 +40,7 @@ else:
 # Import from pygit2
 from _pygit2 import Repository as _Repository
 from _pygit2 import Oid, GIT_OID_HEXSZ, GIT_OID_MINPREFIXLEN
-from _pygit2 import GIT_CHECKOUT_SAFE_CREATE, GIT_DIFF_NORMAL
+from _pygit2 import GIT_CHECKOUT_SAFE, GIT_CHECKOUT_RECREATE_MISSING, GIT_DIFF_NORMAL
 from _pygit2 import GIT_FILEMODE_LINK
 from _pygit2 import Reference, Tree, Commit, Blob
 
@@ -190,8 +190,8 @@ class Repository(_Repository):
         # References we need to keep to strings and so forth
         refs = []
 
-        # pygit2's default is SAFE_CREATE
-        copts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE
+        # pygit2's default is SAFE | RECREATE_MISSING
+        copts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_RECREATE_MISSING
         # and go through the arguments to see what the user wanted
         if strategy:
             copts.checkout_strategy = strategy
@@ -235,7 +235,7 @@ class Repository(_Repository):
         Checkout the given reference using the given strategy, and update
         the HEAD.
         The reference may be a reference name or a Reference object.
-        The default strategy is GIT_CHECKOUT_SAFE_CREATE.
+        The default strategy is GIT_CHECKOUT_SAFE | GIT_CHECKOUT_RECREATE_MISSING.
 
         To checkout from the HEAD, just pass 'HEAD'::
 
@@ -251,7 +251,7 @@ class Repository(_Repository):
           the current branch will be switched to this one.
 
         :param int strategy: A ``GIT_CHECKOUT_`` value. The default is
-          ``GIT_CHECKOUT_SAFE_CREATE``.
+          ``GIT_CHECKOUT_SAFE``.
 
         :param str directory: Alternative checkout path to workdir.
 
@@ -281,50 +281,29 @@ class Repository(_Repository):
         else:
             from_ = head.target.hex
 
-        try:
-            signature = self.default_signature
-        except Exception:
-            signature = None
-
-        reflog_text = "checkout: moving from %s to %s" % (from_, reference)
-        self.set_head(refname, signature, reflog_text)
+        self.set_head(refname)
 
     #
     # Setting HEAD
     #
-    def set_head(self, target, signature=None, message=None):
+    def set_head(self, target):
         """Set HEAD to point to the given target
 
         Arguments:
 
         target
             The new target for HEAD. Can be a string or Oid (to detach)
-
-        signature
-            Signature to use for the reflog. If not provided, the repository's
-            default will be used
-
-        message
-            Message to use for the reflog
         """
 
-        sig_ptr = ffi.new('git_signature **')
-        if signature:
-            ffi.buffer(sig_ptr)[:] = signature._pointer[:]
-
-        message_ptr = ffi.NULL
-        if message_ptr:
-            message_ptr = to_bytes(message)
-
         if isinstance(target, Oid):
             oid = ffi.new('git_oid *')
             ffi.buffer(oid)[:] = target.raw[:]
-            err = C.git_repository_set_head_detached(self._repo, oid, sig_ptr[0], message_ptr)
+            err = C.git_repository_set_head_detached(self._repo, oid)
             check_error(err)
             return
 
         # if it's a string, then it's a reference name
-        err = C.git_repository_set_head(self._repo, to_bytes(target), sig_ptr[0], message_ptr)
+        err = C.git_repository_set_head(self._repo, to_bytes(target))
         check_error(err)
 
     #
@@ -802,3 +781,27 @@ class Repository(_Repository):
             return ffi.string(cvalue[0]).decode('utf-8')
 
         assert False, "the attribute value from libgit2 is invalid"
+
+    #
+    # Identity for reference operations
+    #
+    @property
+    def ident(self):
+        cname = ffi.new('char **')
+        cemail = ffi.new('char **')
+
+        err = C.git_repository_ident(cname, cemail, self._repo)
+        check_error(err)
+
+        return (ffi.string(cname).decode('utf-8'), ffi.string(cemail).decode('utf-8'))
+
+    def set_ident(self, name, email):
+        """Set the identity to be used for reference operations
+
+        Updates to some references also append data to their
+        reflog. You can use this method to set what identity will be
+        used. If none is set, it will be read from the configuration.
+        """
+
+        err = C.git_repository_set_ident(self._repo, to_bytes(name), to_bytes(email))
+        check_error(err)
diff --git a/pygit2/utils.py b/pygit2/utils.py
index 89bc7ee..5b6a365 100644
--- a/pygit2/utils.py
+++ b/pygit2/utils.py
@@ -61,6 +61,11 @@ class StrArray(object):
     """
 
     def __init__(self, l):
+        # Allow passing in None as lg2 typically considers them the same as empty
+        if l is None:
+            self.array = ffi.NULL
+            return
+
         if not isinstance(l, list):
             raise TypeError("Value must be a list")
 
diff --git a/src/branch.c b/src/branch.c
index 1793cea..d725ab1 100644
--- a/src/branch.c
+++ b/src/branch.c
@@ -101,7 +101,7 @@ Branch_rename(Branch *self, PyObject *args)
     if (!PyArg_ParseTuple(args, "s|i", &c_name, &force))
         return NULL;
 
-    err = git_branch_move(&c_out, self->reference, c_name, force, NULL, NULL);
+    err = git_branch_move(&c_out, self->reference, c_name, force);
     if (err == GIT_OK)
         return wrap_branch(c_out, self->repo);
     else
diff --git a/src/pygit2.c b/src/pygit2.c
index eedff26..12d365f 100644
--- a/src/pygit2.c
+++ b/src/pygit2.c
@@ -273,10 +273,11 @@ moduleinit(PyObject* m)
     ADD_CONSTANT_INT(m, GIT_STATUS_WT_MODIFIED)
     ADD_CONSTANT_INT(m, GIT_STATUS_WT_DELETED)
     ADD_CONSTANT_INT(m, GIT_STATUS_IGNORED) /* Flags for ignored files */
+    ADD_CONSTANT_INT(m, GIT_STATUS_CONFLICTED)
     /* Different checkout strategies */
     ADD_CONSTANT_INT(m, GIT_CHECKOUT_NONE)
     ADD_CONSTANT_INT(m, GIT_CHECKOUT_SAFE)
-    ADD_CONSTANT_INT(m, GIT_CHECKOUT_SAFE_CREATE)
+    ADD_CONSTANT_INT(m, GIT_CHECKOUT_RECREATE_MISSING)
     ADD_CONSTANT_INT(m, GIT_CHECKOUT_FORCE)
     ADD_CONSTANT_INT(m, GIT_CHECKOUT_ALLOW_CONFLICTS)
     ADD_CONSTANT_INT(m, GIT_CHECKOUT_REMOVE_UNTRACKED)
diff --git a/src/reference.c b/src/reference.c
index 4d8e56e..2a20cca 100644
--- a/src/reference.c
+++ b/src/reference.c
@@ -163,7 +163,7 @@ Reference_rename(Reference *self, PyObject *py_name)
         return NULL;
 
     /* Rename */
-    err = git_reference_rename(&new_reference, self->reference, c_name, 0, NULL, NULL);
+    err = git_reference_rename(&new_reference, self->reference, c_name, 0, NULL);
     git_reference_free(self->reference);
     free(c_name);
     if (err < 0)
@@ -228,7 +228,7 @@ Reference_target__get__(Reference *self)
 }
 
 PyDoc_STRVAR(Reference_set_target__doc__,
-    "set_target(target, [signature, message])\n"
+    "set_target(target, [message])\n"
     "\n"
     "Set the target of this reference.\n"
     "\n"
@@ -240,9 +240,6 @@ PyDoc_STRVAR(Reference_set_target__doc__,
     "\n"
     "target\n"
     "    The new target for this reference\n"
-    "signature\n"
-    "    The signature to use for the reflog. If left out, the repository's\n"
-    "    default identity will be used.\n"
     "message\n"
     "    Message to use for the reflog.\n");
 
@@ -253,28 +250,23 @@ Reference_set_target(Reference *self, PyObject *args, PyObject *kwds)
     char *c_name;
     int err;
     git_reference *new_ref;
-    const git_signature *sig = NULL;
     PyObject *py_target = NULL;
-    Signature *py_signature = NULL;
     const char *message = NULL;
-    char *keywords[] = {"target", "signature", "message", NULL};
+    char *keywords[] = {"target", "message", NULL};
 
     CHECK_REFERENCE(self);
 
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O!s", keywords,
-                                     &py_target, &SignatureType, &py_signature, &message))
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|s", keywords,
+                                     &py_target, &message))
         return NULL;
 
-    if (py_signature)
-        sig = py_signature->signature;
-
     /* Case 1: Direct */
     if (GIT_REF_OID == git_reference_type(self->reference)) {
         err = py_oid_to_git_oid_expand(self->repo->repo, py_target, &oid);
         if (err < 0)
             goto error;
 
-        err = git_reference_set_target(&new_ref, self->reference, &oid, sig, message);
+        err = git_reference_set_target(&new_ref, self->reference, &oid, message);
         if (err < 0)
             goto error;
 
@@ -288,7 +280,7 @@ Reference_set_target(Reference *self, PyObject *args, PyObject *kwds)
     if (c_name == NULL)
         return NULL;
 
-    err = git_reference_symbolic_set_target(&new_ref, self->reference, c_name, sig, message);
+    err = git_reference_symbolic_set_target(&new_ref, self->reference, c_name, message);
     free(c_name);
     if (err < 0)
         goto error;
diff --git a/src/repository.c b/src/repository.c
index de93bb3..0195c01 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -637,7 +637,7 @@ Repository_merge(Repository *self, PyObject *py_oid)
     if (err < 0)
         return Error_set(err);
 
-    checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE;
+    checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_RECREATE_MISSING;
     err = git_merge(self->repo,
                     (const git_annotated_commit **)&commit, 1,
                     &merge_opts, &checkout_opts);
@@ -677,7 +677,7 @@ Repository_cherrypick(Repository *self, PyObject *py_oid)
     if (err < 0)
         return Error_set(err);
 
-    cherrypick_opts.checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE;
+    cherrypick_opts.checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE;
     err = git_cherrypick(self->repo,
                     commit,
                     (const git_cherrypick_options *)&cherrypick_opts);
@@ -989,7 +989,7 @@ Repository_create_branch(Repository *self, PyObject *args)
     if (!PyArg_ParseTuple(args, "sO!|i", &c_name, &CommitType, &py_commit, &force))
         return NULL;
 
-    err = git_branch_create(&c_reference, self->repo, c_name, py_commit->commit, force, NULL, NULL);
+    err = git_branch_create(&c_reference, self->repo, c_name, py_commit->commit, force);
     if (err < 0)
         return Error_set(err);
 
@@ -1194,7 +1194,7 @@ Repository_create_reference_direct(Repository *self,  PyObject *args,
     if (err < 0)
         return NULL;
 
-    err = git_reference_create(&c_reference, self->repo, c_name, &oid, force, NULL, NULL);
+    err = git_reference_create(&c_reference, self->repo, c_name, &oid, force, NULL);
     if (err < 0)
         return Error_set(err);
 
@@ -1228,7 +1228,7 @@ Repository_create_reference_symbolic(Repository *self,  PyObject *args,
         return NULL;
 
     err = git_reference_symbolic_create(&c_reference, self->repo, c_name,
-                                        c_target, force, NULL, NULL);
+                                        c_target, force, NULL);
     if (err < 0)
         return Error_set(err);
 
@@ -1513,7 +1513,7 @@ Repository_reset(Repository *self, PyObject* args)
 
     err = git_object_lookup_prefix(&target, self->repo, &oid, len,
                                    GIT_OBJ_ANY);
-    err = err < 0 ? err : git_reset(self->repo, target, reset_type, NULL, NULL, NULL);
+    err = err < 0 ? err : git_reset(self->repo, target, reset_type, NULL);
     git_object_free(target);
     if (err < 0)
         return Error_set_oid(err, &oid, len);
diff --git a/src/types.h b/src/types.h
index f82ad47..f3c1858 100644
--- a/src/types.h
+++ b/src/types.h
@@ -32,8 +32,8 @@
 #include <Python.h>
 #include <git2.h>
 
-#if !(LIBGIT2_VER_MAJOR == 0 && LIBGIT2_VER_MINOR == 22)
-#error You need a compatible libgit2 version (v0.22.x)
+#if !(LIBGIT2_VER_MAJOR == 0 && LIBGIT2_VER_MINOR == 23)
+#error You need a compatible libgit2 version (v0.23.x)
 #endif
 
 /*
diff --git a/test/test_merge.py b/test/test_merge.py
index 7719d6d..86d1eea 100644
--- a/test/test_merge.py
+++ b/test/test_merge.py
@@ -82,7 +82,7 @@ class MergeTestBasic(utils.RepoTestCaseForMerging):
 
         self.repo.merge(branch_id)
         self.assertTrue(self.repo.index.conflicts is not None)
-        status = pygit2.GIT_STATUS_WT_NEW | pygit2.GIT_STATUS_INDEX_DELETED
+        status = pygit2.GIT_STATUS_CONFLICTED
         # Asking twice to assure the reference counting is correct
         self.assertEqual({'.gitignore': status}, self.repo.status())
         self.assertEqual({'.gitignore': status}, self.repo.status())
diff --git a/test/test_refs.py b/test/test_refs.py
index 1e78eb5..0d362c7 100644
--- a/test/test_refs.py
+++ b/test/test_refs.py
@@ -114,8 +114,9 @@ class ReferencesTest(utils.RepoTestCase):
         reference = self.repo.lookup_reference('HEAD')
         self.assertEqual(reference.target, 'refs/heads/master')
         sig = Signature('foo', 'bar')
+        self.repo.set_ident('foo', 'bar')
         msg = 'Hello log'
-        reference.set_target('refs/heads/i18n', signature=sig, message=msg)
+        reference.set_target('refs/heads/i18n', message=msg)
         self.assertEqual(reference.target, 'refs/heads/i18n')
         self.assertEqual(list(reference.log())[0].message, msg)
         self.assertEqualSignature(list(reference.log())[0].committer, sig)
diff --git a/test/test_remote.py b/test/test_remote.py
index 751cddc..c2e4f8f 100644
--- a/test/test_remote.py
+++ b/test/test_remote.py
@@ -100,22 +100,23 @@ class RepositoryTest(utils.RepoTestCase):
 
 
     def test_remote_set_url(self):
-        remote = self.repo.remotes[0]
-
+        remote = self.repo.remotes["origin"]
         self.assertEqual(REMOTE_URL, remote.url)
+
         new_url = 'git://github.com/cholin/pygit2.git'
-        remote.url = new_url
+        self.repo.remotes.set_url("origin", new_url)
+        remote = self.repo.remotes["origin"]
         self.assertEqual(new_url, remote.url)
 
-        self.assertRaisesAssign(ValueError, remote, 'url', '')
+        self.assertRaises(ValueError, self.repo.remotes.set_url, "origin", "")
 
-        remote.push_url = new_url
+        self.repo.remotes.set_push_url("origin", new_url)
+        remote = self.repo.remotes["origin"]
         self.assertEqual(new_url, remote.push_url)
-        self.assertRaisesAssign(ValueError, remote, 'push_url', '')
-
+        self.assertRaises(ValueError, self.repo.remotes.set_push_url, "origin", "")
 
     def test_refspec(self):
-        remote = self.repo.remotes[0]
+        remote = self.repo.remotes["origin"]
 
         self.assertEqual(remote.refspec_count, 1)
         refspec = remote.get_refspec(0)
@@ -140,34 +141,20 @@ class RepositoryTest(utils.RepoTestCase):
         self.assertEqual(list, type(push_specs))
         self.assertEqual(0, len(push_specs))
 
-        remote.fetch_refspecs = ['+refs/*:refs/remotes/*']
-        self.assertEqual('+refs/*:refs/remotes/*', remote.fetch_refspecs[0])
+        self.repo.remotes.add_fetch("origin", '+refs/test/*:refs/test/remotes/*')
+        remote = self.repo.remotes["origin"]
 
         fetch_specs = remote.fetch_refspecs
         self.assertEqual(list, type(fetch_specs))
-        self.assertEqual(1, len(fetch_specs))
-        self.assertEqual('+refs/*:refs/remotes/*', fetch_specs[0])
-
-        remote.fetch_refspecs = ['+refs/*:refs/remotes/*',
-                                 '+refs/test/*:refs/test/remotes/*']
-        self.assertEqual('+refs/*:refs/remotes/*', remote.fetch_refspecs[0])
-        self.assertEqual('+refs/test/*:refs/test/remotes/*',
-                         remote.fetch_refspecs[1])
+        self.assertEqual(2, len(fetch_specs))
+        self.assertEqual(['+refs/heads/*:refs/remotes/origin/*', '+refs/test/*:refs/test/remotes/*'], fetch_specs)
 
-        remote.push_refspecs = ['+refs/*:refs/remotes/*',
-                                '+refs/test/*:refs/test/remotes/*']
+        self.repo.remotes.add_push("origin", '+refs/test/*:refs/test/remotes/*')
 
-        self.assertRaises(TypeError, setattr, remote, 'push_refspecs',
-                          '+refs/*:refs/*')
-        self.assertRaises(TypeError, setattr, remote, 'fetch_refspecs',
-                          '+refs/*:refs/*')
-        self.assertRaises(TypeError, setattr, remote, 'fetch_refspecs',
-                          ['+refs/*:refs/*', 5])
-
-        self.assertEqual('+refs/*:refs/remotes/*', remote.push_refspecs[0])
-        self.assertEqual('+refs/test/*:refs/test/remotes/*',
-                         remote.push_refspecs[1])
+        self.assertRaises(TypeError, self.repo.remotes.add_fetch, ['+refs/*:refs/*', 5])
 
+        remote = self.repo.remotes["origin"]
+        self.assertEqual(['+refs/test/*:refs/test/remotes/*'], remote.push_refspecs)
 
     def test_remote_list(self):
         self.assertEqual(1, len(self.repo.remotes))
@@ -193,15 +180,6 @@ class RepositoryTest(utils.RepoTestCase):
         remote = self.repo.remotes.create(name, url)
         self.assertTrue(remote.name in [x.name for x in self.repo.remotes])
 
-
-    def test_remote_save(self):
-        remote = self.repo.remotes[0]
-        remote.url = 'http://example.com/test.git'
-        remote.save()
-
-        self.assertEqual('http://example.com/test.git',
-                         self.repo.remotes[0].url)
-
     @unittest.skipIf(__pypy__ is not None, "skip refcounts checks in pypy")
     def test_remote_refcount(self):
         start = sys.getrefcount(self.repo)
@@ -210,15 +188,6 @@ class RepositoryTest(utils.RepoTestCase):
         end = sys.getrefcount(self.repo)
         self.assertEqual(start, end)
 
-    def test_add_refspec(self):
-        remote = self.repo.create_remote('test_add_refspec', REMOTE_URL)
-        remote.add_push('refs/heads/*:refs/heads/test_refspec/*')
-        self.assertEqual('refs/heads/*:refs/heads/test_refspec/*',
-                         remote.push_refspecs[0])
-        remote.add_fetch('+refs/heads/*:refs/remotes/test_refspec/*')
-        self.assertEqual('+refs/heads/*:refs/remotes/test_refspec/*',
-                         remote.fetch_refspecs[1])
-
     def test_remote_callback_typecheck(self):
         remote = self.repo.remotes[0]
         remote.progress = 5
-- 
2.5.0