Commit f184836bd281efe8a656e3a9c6c2f9c040b88119

Carlos Martín Nieto 2012-04-25T12:13:20

remote: run a callback when updating the branch tips This allows the caller to update an internal structure or update the user output with the tips that were updated. While in the area, only try to update the ref if the value is different from its old one.

diff --git a/examples/network/Makefile b/examples/network/Makefile
index ed0c209..c21869a 100644
--- a/examples/network/Makefile
+++ b/examples/network/Makefile
@@ -2,7 +2,7 @@ default: all
 
 CC = gcc
 CFLAGS += -g
-CFLAGS += -I../../include -L../../ -lgit2
+CFLAGS += -I../../include -L../../ -lgit2 -lpthread
 
 OBJECTS = \
   git2.o \
diff --git a/examples/network/fetch.c b/examples/network/fetch.c
index f7a6064..d4a3974 100644
--- a/examples/network/fetch.c
+++ b/examples/network/fetch.c
@@ -39,6 +39,25 @@ exit:
 	pthread_exit(&data->ret);
 }
 
+int update_cb(const char *refname, const git_oid *a, const git_oid *b)
+{
+	const char *action;
+	char a_str[GIT_OID_HEXSZ+1], b_str[GIT_OID_HEXSZ+1];
+
+	git_oid_fmt(b_str, b);
+	b_str[GIT_OID_HEXSZ] = '\0';
+
+	if (git_oid_iszero(a)) {
+		printf("[new]     %.20s %s\n", b_str, refname);
+	} else {
+		git_oid_fmt(a_str, a);
+		a_str[GIT_OID_HEXSZ] = '\0';
+		printf("[updated] %.10s..%.10s %s\n", a_str, b_str, refname);
+	}
+
+	return 0;
+}
+
 int fetch(git_repository *repo, int argc, char **argv)
 {
   git_remote *remote = NULL;
@@ -78,7 +97,7 @@ int fetch(git_repository *repo, int argc, char **argv)
   // right commits. This may be needed even if there was no packfile
   // to download, which can happen e.g. when the branches have been
   // changed but all the neede objects are available locally.
-  if (git_remote_update_tips(remote) < 0)
+  if (git_remote_update_tips(remote, update_cb) < 0)
 	  return -1;
 
   git_remote_free(remote);
diff --git a/include/git2/remote.h b/include/git2/remote.h
index 8f49fdd..09b927e 100644
--- a/include/git2/remote.h
+++ b/include/git2/remote.h
@@ -183,12 +183,10 @@ GIT_EXTERN(void) git_remote_free(git_remote *remote);
 /**
  * Update the tips to the new state
  *
- * Make sure that you only call this once you've successfully indexed
- * or expanded the packfile.
- *
  * @param remote the remote to update
+ * @param cb callback to run on each ref update. 'a' is the old value, 'b' is then new value
  */
-GIT_EXTERN(int) git_remote_update_tips(git_remote *remote);
+GIT_EXTERN(int) git_remote_update_tips(git_remote *remote, int (*cb)(const char *refname, const git_oid *a, const git_oid *b));
 
 /**
  * Return whether a string is a valid remote URL
diff --git a/src/remote.c b/src/remote.c
index bbb491d..e1937df 100644
--- a/src/remote.c
+++ b/src/remote.c
@@ -309,11 +309,12 @@ int git_remote_download(git_remote *remote, git_off_t *bytes, git_indexer_stats 
 	return git_fetch_download_pack(remote, bytes, stats);
 }
 
-int git_remote_update_tips(git_remote *remote)
+int git_remote_update_tips(git_remote *remote, int (*cb)(const char *refname, const git_oid *a, const git_oid *b))
 {
 	int error = 0;
 	unsigned int i = 0;
 	git_buf refname = GIT_BUF_INIT;
+	git_oid old;
 	git_vector *refs = &remote->refs;
 	git_remote_head *head;
 	git_reference *ref;
@@ -338,17 +339,36 @@ int git_remote_update_tips(git_remote *remote)
 		head = refs->contents[i];
 
 		if (git_refspec_transform_r(&refname, spec, head->name) < 0)
-			break;
+			goto on_error;
+
+		error = git_reference_name_to_oid(&old, remote->repo, refname.ptr);
+		if (error < 0 && error != GIT_ENOTFOUND)
+			goto on_error;
+
+		if (error == GIT_ENOTFOUND)
+			memset(&old, 0, GIT_OID_RAWSZ);
+
+		if (!git_oid_cmp(&old, &head->oid))
+			continue;
 
 		if (git_reference_create_oid(&ref, remote->repo, refname.ptr, &head->oid, 1) < 0)
 			break;
 
 		git_reference_free(ref);
+
+		if (cb != NULL) {
+			if (cb(refname.ptr, &old, &head->oid) < 0)
+				goto on_error;
+		}
 	}
 
 	git_buf_free(&refname);
+	return 0;
+
+on_error:
+	git_buf_free(&refname);
+	return -1;
 
-	return error;
 }
 
 int git_remote_connected(git_remote *remote)