Git development
 help / color / mirror / Atom feed
* [PATCH 3/6] http-push: refactor remote file/directory processing
From: Nick Hengeveld @ 2006-03-11  4:18 UTC (permalink / raw)
  To: git

Replace single-use functions with one that can get a list of remote
collections and pass file/directory information to user-defined functions
for processing.

---

 http-push.c |  245 ++++++++++++++++++++++++++---------------------------------
 1 files changed, 107 insertions(+), 138 deletions(-)

05c0fc457388309cf12f3647a48071845acc2c70
diff --git a/http-push.c b/http-push.c
index 1b0b3a8..755bcb8 100644
--- a/http-push.c
+++ b/http-push.c
@@ -140,11 +140,23 @@ struct remote_lock
 	struct remote_lock *next;
 };
 
-struct remote_dentry
+/* Flags that control remote_ls processing */
+#define PROCESS_FILES (1u << 0)
+#define PROCESS_DIRS  (1u << 1)
+#define RECURSIVE     (1u << 2)
+
+/* Flags that remote_ls passes to callback functions */
+#define IS_DIR (1u << 0)
+
+struct remote_ls_ctx
 {
-	char *base;
-	char *name;
-	int is_dir;
+	char *path;
+	void (*userFunc)(struct remote_ls_ctx *ls);
+	void *userData;
+	int flags;
+	char *dentry_name;
+	int dentry_flags;
+	struct remote_ls_ctx *parent;
 };
 
 static void finish_request(struct transfer_request *request);
@@ -812,55 +824,6 @@ static void handle_new_lock_ctx(struct x
 }
 
 static void one_remote_ref(char *refname);
-static void crawl_remote_refs(char *path);
-
-static void handle_crawl_ref_ctx(struct xml_ctx *ctx, int tag_closed)
-{
-	struct remote_dentry *dentry = (struct remote_dentry *)ctx->userData;
-
-
-	if (tag_closed) {
-		if (!strcmp(ctx->name, DAV_PROPFIND_RESP) && dentry->name) {
-			if (dentry->is_dir) {
-				if (strcmp(dentry->name, dentry->base)) {
-					crawl_remote_refs(dentry->name);
-				}
-			} else {
-				one_remote_ref(dentry->name);
-			}
-		} else if (!strcmp(ctx->name, DAV_PROPFIND_NAME) && ctx->cdata) {
-			dentry->name = xmalloc(strlen(ctx->cdata) -
-					       remote->path_len + 1);
-			strcpy(dentry->name,
-			       ctx->cdata + remote->path_len);
-		} else if (!strcmp(ctx->name, DAV_PROPFIND_COLLECTION)) {
-			dentry->is_dir = 1;
-		}
-	} else if (!strcmp(ctx->name, DAV_PROPFIND_RESP)) {
-		dentry->name = NULL;
-		dentry->is_dir = 0;
-	}
-}
-
-static void handle_remote_object_list_ctx(struct xml_ctx *ctx, int tag_closed)
-{
-	char *path;
-	char *obj_hex;
-
-	if (tag_closed) {
-		if (!strcmp(ctx->name, DAV_PROPFIND_NAME) && ctx->cdata) {
-			path = ctx->cdata + remote->path_len;
-			if (strlen(path) != 50)
-				return;
-			path += 9;
-			obj_hex = xmalloc(strlen(path));
-			strncpy(obj_hex, path, 2);
-			strcpy(obj_hex + 2, path + 3);
-			one_remote_object(obj_hex);
-			free(obj_hex);
-		}
-	}
-}
 
 static void
 xml_start_tag(void *userData, const char *name, const char **atts)
@@ -1101,91 +1064,83 @@ static int unlock_remote(struct remote_l
 	return rc;
 }
 
-static void crawl_remote_refs(char *path)
-{
-	char *url;
-	struct active_request_slot *slot;
-	struct slot_results results;
-	struct buffer in_buffer;
-	struct buffer out_buffer;
-	char *in_data;
-	char *out_data;
-	XML_Parser parser = XML_ParserCreate(NULL);
-	enum XML_Status result;
-	struct curl_slist *dav_headers = NULL;
-	struct xml_ctx ctx;
-	struct remote_dentry dentry;
-
-	fprintf(stderr, "  %s\n", path);
+static void remote_ls(const char *path, int flags,
+		      void (*userFunc)(struct remote_ls_ctx *ls),
+		      void *userData);
 
-	dentry.base = path;
-	dentry.name = NULL;
-	dentry.is_dir = 0;
-
-	url = xmalloc(strlen(remote->url) + strlen(path) + 1);
-	sprintf(url, "%s%s", remote->url, path);
+static void process_ls_object(struct remote_ls_ctx *ls)
+{
+	unsigned int *parent = (unsigned int *)ls->userData;
+	char *path = ls->dentry_name;
+	char *obj_hex;
 
-	out_buffer.size = strlen(PROPFIND_ALL_REQUEST);
-	out_data = xmalloc(out_buffer.size + 1);
-	snprintf(out_data, out_buffer.size + 1, PROPFIND_ALL_REQUEST);
-	out_buffer.posn = 0;
-	out_buffer.buffer = out_data;
+	if (!strcmp(ls->path, ls->dentry_name) && (ls->flags & IS_DIR)) {
+		remote_dir_exists[*parent] = 1;
+		return;
+	}
 
-	in_buffer.size = 4096;
-	in_data = xmalloc(in_buffer.size);
-	in_buffer.posn = 0;
-	in_buffer.buffer = in_data;
+	if (strlen(path) != 49)
+		return;
+	path += 8;
+	obj_hex = xmalloc(strlen(path));
+	strncpy(obj_hex, path, 2);
+	strcpy(obj_hex + 2, path + 3);
+	one_remote_object(obj_hex);
+	free(obj_hex);
+}
 
-	dav_headers = curl_slist_append(dav_headers, "Depth: 1");
-	dav_headers = curl_slist_append(dav_headers, "Content-Type: text/xml");
+static void process_ls_ref(struct remote_ls_ctx *ls)
+{
+	if (!strcmp(ls->path, ls->dentry_name) && (ls->dentry_flags & IS_DIR)) {
+		fprintf(stderr, "  %s\n", ls->dentry_name);
+		return;
+	}
 
-	slot = get_active_slot();
-	slot->results = &results;
-	curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);
-	curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.size);
-	curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
-	curl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer);
-	curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
-	curl_easy_setopt(slot->curl, CURLOPT_URL, url);
-	curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 1);
-	curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PROPFIND);
-	curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
+	if (!(ls->dentry_flags & IS_DIR))
+		one_remote_ref(ls->dentry_name);
+}
 
-	if (start_active_slot(slot)) {
-		run_active_slot(slot);
-		if (results.curl_result == CURLE_OK) {
-			ctx.name = xcalloc(10, 1);
-			ctx.len = 0;
-			ctx.cdata = NULL;
-			ctx.userFunc = handle_crawl_ref_ctx;
-			ctx.userData = &dentry;
-			XML_SetUserData(parser, &ctx);
-			XML_SetElementHandler(parser, xml_start_tag,
-					      xml_end_tag);
-			XML_SetCharacterDataHandler(parser, xml_cdata);
-			result = XML_Parse(parser, in_buffer.buffer,
-					   in_buffer.posn, 1);
-			free(ctx.name);
+static void handle_remote_ls_ctx(struct xml_ctx *ctx, int tag_closed)
+{
+	struct remote_ls_ctx *ls = (struct remote_ls_ctx *)ctx->userData;
 
-			if (result != XML_STATUS_OK) {
-				fprintf(stderr, "XML error: %s\n",
-					XML_ErrorString(
-						XML_GetErrorCode(parser)));
+	if (tag_closed) {
+		if (!strcmp(ctx->name, DAV_PROPFIND_RESP) && ls->dentry_name) {
+			if (ls->dentry_flags & IS_DIR) {
+				if (ls->flags & PROCESS_DIRS) {
+					ls->userFunc(ls);
+				}
+				if (strcmp(ls->dentry_name, ls->path) &&
+				    ls->flags & RECURSIVE) {
+					remote_ls(ls->dentry_name,
+						  ls->flags,
+						  ls->userFunc,
+						  ls->userData);
+				}
+			} else if (ls->flags & PROCESS_FILES) {
+				ls->userFunc(ls);
 			}
+		} else if (!strcmp(ctx->name, DAV_PROPFIND_NAME) && ctx->cdata) {
+			ls->dentry_name = xmalloc(strlen(ctx->cdata) -
+						  remote->path_len + 1);
+			strcpy(ls->dentry_name, ctx->cdata + remote->path_len);
+		} else if (!strcmp(ctx->name, DAV_PROPFIND_COLLECTION)) {
+			ls->dentry_flags |= IS_DIR;
 		}
-	} else {
-		fprintf(stderr, "Unable to start request\n");
+	} else if (!strcmp(ctx->name, DAV_PROPFIND_RESP)) {
+		if (ls->dentry_name) {
+			free(ls->dentry_name);
+		}
+		ls->dentry_name = NULL;
+		ls->dentry_flags = 0;
 	}
-
-	free(url);
-	free(out_data);
-	free(in_buffer.buffer);
-	curl_slist_free_all(dav_headers);
 }
 
-static void get_remote_object_list(unsigned char parent)
+static void remote_ls(const char *path, int flags,
+		      void (*userFunc)(struct remote_ls_ctx *ls),
+		      void *userData)
 {
-	char *url;
+	char *url = xmalloc(strlen(remote->url) + strlen(path) + 1);
 	struct active_request_slot *slot;
 	struct slot_results results;
 	struct buffer in_buffer;
@@ -1196,13 +1151,15 @@ static void get_remote_object_list(unsig
 	enum XML_Status result;
 	struct curl_slist *dav_headers = NULL;
 	struct xml_ctx ctx;
-	char path[] = "/objects/XX/";
-	static const char hex[] = "0123456789abcdef";
-	unsigned int val = parent;
+	struct remote_ls_ctx ls;
+
+	ls.flags = flags;
+	ls.path = strdup(path);
+	ls.dentry_name = NULL;
+	ls.dentry_flags = 0;
+	ls.userData = userData;
+	ls.userFunc = userFunc;
 
-	path[9] = hex[val >> 4];
-	path[10] = hex[val & 0xf];
-	url = xmalloc(strlen(remote->url) + strlen(path) + 1);
 	sprintf(url, "%s%s", remote->url, path);
 
 	out_buffer.size = strlen(PROPFIND_ALL_REQUEST);
@@ -1218,7 +1175,7 @@ static void get_remote_object_list(unsig
 
 	dav_headers = curl_slist_append(dav_headers, "Depth: 1");
 	dav_headers = curl_slist_append(dav_headers, "Content-Type: text/xml");
-
+	
 	slot = get_active_slot();
 	slot->results = &results;
 	curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);
@@ -1234,11 +1191,11 @@ static void get_remote_object_list(unsig
 	if (start_active_slot(slot)) {
 		run_active_slot(slot);
 		if (results.curl_result == CURLE_OK) {
-			remote_dir_exists[parent] = 1;
 			ctx.name = xcalloc(10, 1);
 			ctx.len = 0;
 			ctx.cdata = NULL;
-			ctx.userFunc = handle_remote_object_list_ctx;
+			ctx.userFunc = handle_remote_ls_ctx;
+			ctx.userData = &ls;
 			XML_SetUserData(parser, &ctx);
 			XML_SetElementHandler(parser, xml_start_tag,
 					      xml_end_tag);
@@ -1252,19 +1209,31 @@ static void get_remote_object_list(unsig
 					XML_ErrorString(
 						XML_GetErrorCode(parser)));
 			}
-		} else {
-			remote_dir_exists[parent] = 0;
 		}
 	} else {
-		fprintf(stderr, "Unable to start request\n");
+		fprintf(stderr, "Unable to start PROPFIND request\n");
 	}
 
+	free(ls.path);
 	free(url);
 	free(out_data);
 	free(in_buffer.buffer);
 	curl_slist_free_all(dav_headers);
 }
 
+static void get_remote_object_list(unsigned char parent)
+{
+	char path[] = "objects/XX/";
+	static const char hex[] = "0123456789abcdef";
+	unsigned int val = parent;
+
+	path[8] = hex[val >> 4];
+	path[9] = hex[val & 0xf];
+	remote_dir_exists[val] = 0;
+	remote_ls(path, (PROCESS_FILES | PROCESS_DIRS),
+		  process_ls_object, &val);
+}
+
 static int locking_available(void)
 {
 	struct active_request_slot *slot;
@@ -1534,7 +1503,7 @@ static void get_local_heads(void)
 static void get_dav_remote_heads(void)
 {
 	remote_tail = &remote_refs;
-	crawl_remote_refs("refs/");
+	remote_ls("refs/", (PROCESS_FILES | PROCESS_DIRS | RECURSIVE), process_ls_ref, NULL);
 }
 
 static int is_zero_sha1(const unsigned char *sha1)
-- 
1.2.4.g8e81-dirty

^ permalink raw reply related

* [PATCH 5/6] http-push: support for updating remote info/refs
From: Nick Hengeveld @ 2006-03-11  4:18 UTC (permalink / raw)
  To: git

If info/refs exists on the remote, get a lock on info/refs, make sure that
there is a local copy of the object referenced in each remote ref (in case
someone else added a tag we don't have locally), do all the refspec updates,
and generate and send an updated info/refs file.

---

 http-push.c |  547 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 536 insertions(+), 11 deletions(-)

b29c6a3ec299241894a3effd8cea4d00ea117a8c
diff --git a/http-push.c b/http-push.c
index ece40da..65c6664 100644
--- a/http-push.c
+++ b/http-push.c
@@ -22,6 +22,7 @@ enum XML_Status {
 #define XML_STATUS_ERROR 0
 #endif
 
+#define PREV_BUF_SIZE 4096
 #define RANGE_HEADER_SIZE 30
 
 /* DAV methods */
@@ -58,9 +59,10 @@ enum XML_Status {
 
 /* bits #0-4 in revision.h */
 
-#define LOCAL   (1u << 5)
-#define REMOTE  (1u << 6)
-#define PUSHING (1u << 7)
+#define LOCAL    (1u << 5)
+#define REMOTE   (1u << 6)
+#define FETCHING (1u << 7)
+#define PUSHING  (1u << 8)
 
 static int pushing = 0;
 static int aborted = 0;
@@ -79,6 +81,9 @@ struct repo
 {
 	char *url;
 	int path_len;
+	int has_info_refs;
+	int can_update_info_refs;
+	int has_info_packs;
 	struct packed_git *packs;
 	struct remote_lock *locks;
 };
@@ -86,6 +91,9 @@ struct repo
 static struct repo *remote = NULL;
 
 enum transfer_state {
+	NEED_FETCH,
+	RUN_FETCH_LOOSE,
+	RUN_FETCH_PACKED,
 	NEED_PUSH,
 	RUN_MKCOL,
 	RUN_PUT,
@@ -104,6 +112,8 @@ struct transfer_request
 	struct buffer buffer;
 	char filename[PATH_MAX];
 	char tmpfile[PATH_MAX];
+	int local_fileno;
+	FILE *local_stream;
 	enum transfer_state state;
 	CURLcode curl_result;
 	char errorstr[CURL_ERROR_SIZE];
@@ -113,6 +123,7 @@ struct transfer_request
 	z_stream stream;
 	int zret;
 	int rename;
+	void *userData;
 	struct active_request_slot *slot;
 	struct transfer_request *next;
 };
@@ -159,6 +170,7 @@ struct remote_ls_ctx
 };
 
 static void finish_request(struct transfer_request *request);
+static void release_request(struct transfer_request *request);
 
 static void process_response(void *callback_data)
 {
@@ -168,6 +180,258 @@ static void process_response(void *callb
 	finish_request(request);
 }
 
+static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb,
+			       void *data)
+{
+	unsigned char expn[4096];
+	size_t size = eltsize * nmemb;
+	int posn = 0;
+	struct transfer_request *request = (struct transfer_request *)data;
+	do {
+		ssize_t retval = write(request->local_fileno,
+				       ptr + posn, size - posn);
+		if (retval < 0)
+			return posn;
+		posn += retval;
+	} while (posn < size);
+
+	request->stream.avail_in = size;
+	request->stream.next_in = ptr;
+	do {
+		request->stream.next_out = expn;
+		request->stream.avail_out = sizeof(expn);
+		request->zret = inflate(&request->stream, Z_SYNC_FLUSH);
+		SHA1_Update(&request->c, expn,
+			    sizeof(expn) - request->stream.avail_out);
+	} while (request->stream.avail_in && request->zret == Z_OK);
+	data_received++;
+	return size;
+}
+
+static void start_fetch_loose(struct transfer_request *request)
+{
+	char *hex = sha1_to_hex(request->obj->sha1);
+	char *filename;
+	char prevfile[PATH_MAX];
+	char *url;
+	char *posn;
+	int prevlocal;
+	unsigned char prev_buf[PREV_BUF_SIZE];
+	ssize_t prev_read = 0;
+	long prev_posn = 0;
+	char range[RANGE_HEADER_SIZE];
+	struct curl_slist *range_header = NULL;
+	struct active_request_slot *slot;
+
+	filename = sha1_file_name(request->obj->sha1);
+	snprintf(request->filename, sizeof(request->filename), "%s", filename);
+	snprintf(request->tmpfile, sizeof(request->tmpfile),
+		 "%s.temp", filename);
+
+	snprintf(prevfile, sizeof(prevfile), "%s.prev", request->filename);
+	unlink(prevfile);
+	rename(request->tmpfile, prevfile);
+	unlink(request->tmpfile);
+
+	if (request->local_fileno != -1)
+		error("fd leakage in start: %d", request->local_fileno);
+	request->local_fileno = open(request->tmpfile,
+				     O_WRONLY | O_CREAT | O_EXCL, 0666);
+	/* This could have failed due to the "lazy directory creation";
+	 * try to mkdir the last path component.
+	 */
+	if (request->local_fileno < 0 && errno == ENOENT) {
+		char *dir = strrchr(request->tmpfile, '/');
+		if (dir) {
+			*dir = 0;
+			mkdir(request->tmpfile, 0777);
+			*dir = '/';
+		}
+		request->local_fileno = open(request->tmpfile,
+					     O_WRONLY | O_CREAT | O_EXCL, 0666);
+	}
+
+	if (request->local_fileno < 0) {
+		request->state = ABORTED;
+		error("Couldn't create temporary file %s for %s: %s",
+		      request->tmpfile, request->filename, strerror(errno));
+		return;
+	}
+
+	memset(&request->stream, 0, sizeof(request->stream));
+
+	inflateInit(&request->stream);
+
+	SHA1_Init(&request->c);
+
+	url = xmalloc(strlen(remote->url) + 50);
+	request->url = xmalloc(strlen(remote->url) + 50);
+	strcpy(url, remote->url);
+	posn = url + strlen(remote->url);
+	strcpy(posn, "objects/");
+	posn += 8;
+	memcpy(posn, hex, 2);
+	posn += 2;
+	*(posn++) = '/';
+	strcpy(posn, hex + 2);
+	strcpy(request->url, url);
+
+	/* If a previous temp file is present, process what was already
+	   fetched. */
+	prevlocal = open(prevfile, O_RDONLY);
+	if (prevlocal != -1) {
+		do {
+			prev_read = read(prevlocal, prev_buf, PREV_BUF_SIZE);
+			if (prev_read>0) {
+				if (fwrite_sha1_file(prev_buf,
+						     1,
+						     prev_read,
+						     request) == prev_read) {
+					prev_posn += prev_read;
+				} else {
+					prev_read = -1;
+				}
+			}
+		} while (prev_read > 0);
+		close(prevlocal);
+	}
+	unlink(prevfile);
+
+	/* Reset inflate/SHA1 if there was an error reading the previous temp
+	   file; also rewind to the beginning of the local file. */
+	if (prev_read == -1) {
+		memset(&request->stream, 0, sizeof(request->stream));
+		inflateInit(&request->stream);
+		SHA1_Init(&request->c);
+		if (prev_posn>0) {
+			prev_posn = 0;
+			lseek(request->local_fileno, SEEK_SET, 0);
+			ftruncate(request->local_fileno, 0);
+		}
+	}
+
+	slot = get_active_slot();
+	slot->callback_func = process_response;
+	slot->callback_data = request;
+	request->slot = slot;
+
+	curl_easy_setopt(slot->curl, CURLOPT_FILE, request);
+	curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_sha1_file);
+	curl_easy_setopt(slot->curl, CURLOPT_ERRORBUFFER, request->errorstr);
+	curl_easy_setopt(slot->curl, CURLOPT_URL, url);
+	curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, no_pragma_header);
+
+	/* If we have successfully processed data from a previous fetch
+	   attempt, only fetch the data we don't already have. */
+	if (prev_posn>0) {
+		if (push_verbosely)
+			fprintf(stderr,
+				"Resuming fetch of object %s at byte %ld\n",
+				hex, prev_posn);
+		sprintf(range, "Range: bytes=%ld-", prev_posn);
+		range_header = curl_slist_append(range_header, range);
+		curl_easy_setopt(slot->curl,
+				 CURLOPT_HTTPHEADER, range_header);
+	}
+
+	/* Try to get the request started, abort the request on error */
+	request->state = RUN_FETCH_LOOSE;
+	if (!start_active_slot(slot)) {
+		fprintf(stderr, "Unable to start GET request\n");
+		remote->can_update_info_refs = 0;
+		release_request(request);
+	}
+}
+
+static void start_fetch_packed(struct transfer_request *request)
+{
+	char *url;
+	struct packed_git *target;
+	FILE *packfile;
+	char *filename;
+	long prev_posn = 0;
+	char range[RANGE_HEADER_SIZE];
+	struct curl_slist *range_header = NULL;
+
+	struct transfer_request *check_request = request_queue_head;
+	struct active_request_slot *slot;
+
+	target = find_sha1_pack(request->obj->sha1, remote->packs);
+	if (!target) {
+		fprintf(stderr, "Unable to fetch %s, will not be able to update server info refs\n", sha1_to_hex(request->obj->sha1));
+		remote->can_update_info_refs = 0;
+		release_request(request);
+		return;
+	}
+
+	fprintf(stderr,	"Fetching pack %s\n", sha1_to_hex(target->sha1));
+	fprintf(stderr, " which contains %s\n", sha1_to_hex(request->obj->sha1));
+
+	filename = sha1_pack_name(target->sha1);
+	snprintf(request->filename, sizeof(request->filename), "%s", filename);
+	snprintf(request->tmpfile, sizeof(request->tmpfile),
+		 "%s.temp", filename);
+
+	url = xmalloc(strlen(remote->url) + 64);
+	sprintf(url, "%sobjects/pack/pack-%s.pack",
+		remote->url, sha1_to_hex(target->sha1));
+
+	/* Make sure there isn't another open request for this pack */
+	while (check_request) {
+		if (check_request->state == RUN_FETCH_PACKED &&
+		    !strcmp(check_request->url, url)) {
+			free(url);
+			release_request(request);
+			return;
+		}
+		check_request = check_request->next;
+	}
+
+	packfile = fopen(request->tmpfile, "a");
+	if (!packfile) {
+		fprintf(stderr, "Unable to open local file %s for pack",
+			filename);
+		remote->can_update_info_refs = 0;
+		free(url);
+		return;
+	}
+
+	slot = get_active_slot();
+	slot->callback_func = process_response;
+	slot->callback_data = request;
+	request->slot = slot;
+	request->local_stream = packfile;
+	request->userData = target;
+
+	request->url = url;
+	curl_easy_setopt(slot->curl, CURLOPT_FILE, packfile);
+	curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite);
+	curl_easy_setopt(slot->curl, CURLOPT_URL, url);
+	curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, no_pragma_header);
+	slot->local = packfile;
+
+	/* If there is data present from a previous transfer attempt,
+	   resume where it left off */
+	prev_posn = ftell(packfile);
+	if (prev_posn>0) {
+		if (push_verbosely)
+			fprintf(stderr,
+				"Resuming fetch of pack %s at byte %ld\n",
+				sha1_to_hex(target->sha1), prev_posn);
+		sprintf(range, "Range: bytes=%ld-", prev_posn);
+		range_header = curl_slist_append(range_header, range);
+		curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, range_header);
+	}
+
+	/* Try to get the request started, abort the request on error */
+	request->state = RUN_FETCH_PACKED;
+	if (!start_active_slot(slot)) {
+		fprintf(stderr, "Unable to start GET request\n");
+		remote->can_update_info_refs = 0;
+		release_request(request);
+	}
+}
+
 static void start_mkcol(struct transfer_request *request)
 {
 	char *hex = sha1_to_hex(request->obj->sha1);
@@ -388,6 +652,10 @@ static void release_request(struct trans
 			entry->next = entry->next->next;
 	}
 
+	if (request->local_fileno != -1)
+		close(request->local_fileno);
+	if (request->local_stream)
+		fclose(request->local_stream);
 	if (request->url != NULL)
 		free(request->url);
 	free(request);
@@ -395,7 +663,11 @@ static void release_request(struct trans
 
 static void finish_request(struct transfer_request *request)
 {
-	request->curl_result =	request->slot->curl_result;
+	struct stat st;
+	struct packed_git *target;
+	struct packed_git **lst;
+
+	request->curl_result = request->slot->curl_result;
 	request->http_code = request->slot->http_code;
 	request->slot = NULL;
 
@@ -437,7 +709,6 @@ static void finish_request(struct transf
 		if (request->curl_result == CURLE_OK) {
 			fprintf(stderr, "    sent %s\n",
 				sha1_to_hex(request->obj->sha1));
-			request->state = COMPLETE;
 			request->obj->flags |= REMOTE;
 			release_request(request);
 		} else {
@@ -447,12 +718,73 @@ static void finish_request(struct transf
 			request->state = ABORTED;
 			aborted = 1;
 		}
+	} else if (request->state == RUN_FETCH_LOOSE) {
+		fchmod(request->local_fileno, 0444);
+		close(request->local_fileno); request->local_fileno = -1;
+
+		if (request->curl_result != CURLE_OK &&
+		    request->http_code != 416) {
+			if (stat(request->tmpfile, &st) == 0) {
+				if (st.st_size == 0)
+					unlink(request->tmpfile);
+			}
+		} else {
+			if (request->http_code == 416)
+				fprintf(stderr, "Warning: requested range invalid; we may already have all the data.\n");
+
+			inflateEnd(&request->stream);
+			SHA1_Final(request->real_sha1, &request->c);
+			if (request->zret != Z_STREAM_END) {
+				unlink(request->tmpfile);
+			} else if (memcmp(request->obj->sha1, request->real_sha1, 20)) {
+				unlink(request->tmpfile);
+			} else {
+				request->rename =
+					move_temp_to_file(
+						request->tmpfile,
+						request->filename);
+				if (request->rename == 0) {
+					request->obj->flags |= (LOCAL | REMOTE);
+				}
+			}
+		}
+
+		/* Try fetching packed if necessary */
+		if (request->obj->flags & LOCAL)
+			release_request(request);
+		else
+			start_fetch_packed(request);
+
+	} else if (request->state == RUN_FETCH_PACKED) {
+		if (request->curl_result != CURLE_OK) {
+			fprintf(stderr, "Unable to get pack file %s\n%s",
+				request->url, curl_errorstr);
+			remote->can_update_info_refs = 0;
+		} else {
+			fclose(request->local_stream);
+			request->local_stream = NULL;
+			if (!move_temp_to_file(request->tmpfile,
+					       request->filename)) {
+				target = (struct packed_git *)request->userData;
+				lst = &remote->packs;
+				while (*lst != target)
+					lst = &((*lst)->next);
+				*lst = (*lst)->next;
+
+				if (!verify_pack(target, 0))
+					install_packed_git(target);
+				else
+					remote->can_update_info_refs = 0;
+			}
+		}
+		release_request(request);
 	}
 }
 
 void fill_active_slots(void)
 {
 	struct transfer_request *request = request_queue_head;
+	struct transfer_request *next;
 	struct active_request_slot *slot = active_queue_head;
 	int num_transfers;
 
@@ -460,7 +792,10 @@ void fill_active_slots(void)
 		return;
 
 	while (active_requests < max_requests && request != NULL) {
-		if (pushing && request->state == NEED_PUSH) {
+		next = request->next;
+		if (request->state == NEED_FETCH) {
+			start_fetch_loose(request);
+		} else if (pushing && request->state == NEED_PUSH) {
 			if (remote_dir_exists[request->obj->sha1[0]] == 1) {
 				start_put(request);
 			} else {
@@ -468,7 +803,7 @@ void fill_active_slots(void)
 			}
 			curl_multi_perform(curlm, &num_transfers);
 		}
-		request = request->next;
+		request = next;
 	}
 
 	while (slot != NULL) {
@@ -482,7 +817,38 @@ void fill_active_slots(void)
 
 static void get_remote_object_list(unsigned char parent);
 
-static void add_request(struct object *obj, struct remote_lock *lock)
+static void add_fetch_request(struct object *obj)
+{
+	struct transfer_request *request;
+
+	check_locks();
+
+	/*
+	 * Don't fetch the object if it's known to exist locally
+	 * or is already in the request queue
+	 */
+	if (remote_dir_exists[obj->sha1[0]] == -1)
+		get_remote_object_list(obj->sha1[0]);
+	if (obj->flags & (LOCAL | FETCHING))
+		return;
+
+	obj->flags |= FETCHING;
+	request = xmalloc(sizeof(*request));
+	request->obj = obj;
+	request->url = NULL;
+	request->lock = NULL;
+	request->headers = NULL;
+	request->local_fileno = -1;
+	request->local_stream = NULL;
+	request->state = NEED_FETCH;
+	request->next = request_queue_head;
+	request_queue_head = request;
+
+	fill_active_slots();
+	step_active_slots();
+}
+
+static void add_send_request(struct object *obj, struct remote_lock *lock)
 {
 	struct transfer_request *request = request_queue_head;
 	struct packed_git *target;
@@ -510,6 +876,8 @@ static void add_request(struct object *o
 	request->url = NULL;
 	request->lock = lock;
 	request->headers = NULL;
+	request->local_fileno = -1;
+	request->local_stream = NULL;
 	request->state = NEED_PUSH;
 	request->next = request_queue_head;
 	request_queue_head = request;
@@ -1375,7 +1743,7 @@ static void get_delta(struct rev_info *r
 		p = process_tree(commit->tree, p, NULL, "");
 		commit->object.flags |= LOCAL;
 		if (!(commit->object.flags & UNINTERESTING))
-			add_request(&commit->object, lock);
+			add_send_request(&commit->object, lock);
 	}
 
 	for (pending = revs->pending_objects; pending; pending = pending->next) {
@@ -1402,7 +1770,7 @@ static void get_delta(struct rev_info *r
 
 	while (objects) {
 		if (!(objects->item->flags & UNINTERESTING))
-			add_request(objects->item, lock);
+			add_send_request(objects->item, lock);
 		objects = objects->next;
 	}
 }
@@ -1483,6 +1851,7 @@ static void one_remote_ref(char *refname
 {
 	struct ref *ref;
 	unsigned char remote_sha1[20];
+	struct object *obj;
 
 	if (fetch_ref(refname, remote_sha1) != 0) {
 		fprintf(stderr,
@@ -1491,6 +1860,19 @@ static void one_remote_ref(char *refname
 		return;
 	}
 
+	/*
+	 * Fetch a copy of the object if it doesn't exist locally - it
+	 * may be required for updating server info later.
+	 */
+	if (remote->can_update_info_refs && !has_sha1_file(remote_sha1)) {
+		obj = lookup_unknown_object(remote_sha1);
+		if (obj) {
+			fprintf(stderr,	"  fetch %s for %s\n",
+				sha1_to_hex(remote_sha1), refname);
+			add_fetch_request(obj);
+		}
+	}
+
 	int len = strlen(refname) + 1;
 	ref = xcalloc(1, sizeof(*ref) + len);
 	memcpy(ref->old_sha1, remote_sha1, 20);
@@ -1596,6 +1978,125 @@ static void mark_edges_uninteresting(str
 	}
 }
 
+static void add_remote_info_ref(struct remote_ls_ctx *ls)
+{
+	struct buffer *buf = (struct buffer *)ls->userData;
+	unsigned char remote_sha1[20];
+	struct object *o;
+	int len;
+	char *ref_info;
+
+	if (fetch_ref(ls->dentry_name, remote_sha1) != 0) {
+		fprintf(stderr,
+			"Unable to fetch ref %s from %s\n",
+			ls->dentry_name, remote->url);
+		aborted = 1;
+		return;
+	}
+
+	o = parse_object(remote_sha1);
+	if (!o) {
+		fprintf(stderr,
+			"Unable to parse object %s for remote ref %s\n",
+			sha1_to_hex(remote_sha1), ls->dentry_name);
+		aborted = 1;
+		return;
+	}
+
+	len = strlen(ls->dentry_name) + 42;
+	ref_info = xcalloc(len + 1, 1);
+	sprintf(ref_info, "%s	%s\n",
+		sha1_to_hex(remote_sha1), ls->dentry_name);
+	fwrite_buffer(ref_info, 1, len, buf);
+	free(ref_info);
+
+	if (o->type == tag_type) {
+		o = deref_tag(o, ls->dentry_name, 0);
+		if (o) {
+			len = strlen(ls->dentry_name) + 45;
+			ref_info = xcalloc(len + 1, 1);
+			sprintf(ref_info, "%s	%s^{}\n",
+				sha1_to_hex(o->sha1), ls->dentry_name);
+			fwrite_buffer(ref_info, 1, len, buf);
+			free(ref_info);
+		}
+	}
+}
+
+static void update_remote_info_refs(struct remote_lock *lock)
+{
+	struct buffer buffer;
+	struct active_request_slot *slot;
+	struct slot_results results;
+	char *if_header;
+	struct curl_slist *dav_headers = NULL;
+
+	buffer.buffer = xmalloc(4096);
+	memset(buffer.buffer, 0, 4096);
+	buffer.size = 4096;
+	buffer.posn = 0;
+	remote_ls("refs/", (PROCESS_FILES | RECURSIVE),
+		  add_remote_info_ref, &buffer);
+	if (!aborted) {
+		if_header = xmalloc(strlen(lock->token) + 25);
+		sprintf(if_header, "If: (<opaquelocktoken:%s>)", lock->token);
+		dav_headers = curl_slist_append(dav_headers, if_header);
+
+		slot = get_active_slot();
+		slot->results = &results;
+		curl_easy_setopt(slot->curl, CURLOPT_INFILE, &buffer);
+		curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, buffer.posn);
+		curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
+		curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
+		curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PUT);
+		curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
+		curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 1);
+		curl_easy_setopt(slot->curl, CURLOPT_PUT, 1);
+		curl_easy_setopt(slot->curl, CURLOPT_URL, lock->url);
+				
+		buffer.posn = 0;
+
+		if (start_active_slot(slot)) {
+			run_active_slot(slot);
+			if (results.curl_result != CURLE_OK) {
+				fprintf(stderr,
+					"PUT error: curl result=%d, HTTP code=%ld\n",
+					results.curl_result, results.http_code);
+			}
+		}
+		free(if_header);
+	}
+	free(buffer.buffer);
+}
+
+static int remote_exists(const char *path)
+{
+	char *url = xmalloc(strlen(remote->url) + strlen(path) + 1);
+	struct active_request_slot *slot;
+	struct slot_results results;
+
+	sprintf(url, "%s%s", remote->url, path);
+
+        slot = get_active_slot();
+	slot->results = &results;
+        curl_easy_setopt(slot->curl, CURLOPT_URL, url);
+        curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 1);
+
+        if (start_active_slot(slot)) {
+		run_active_slot(slot);
+		if (results.http_code == 404)
+			return 0;
+		else if (results.curl_result == CURLE_OK)
+			return 1;
+		else
+			fprintf(stderr, "HEAD HTTP error %ld\n", results.http_code);
+	} else {
+		fprintf(stderr, "Unable to start HEAD request\n");
+	}
+
+	return -1;
+}
+
 int main(int argc, char **argv)
 {
 	struct transfer_request *request;
@@ -1603,6 +2104,7 @@ int main(int argc, char **argv)
 	int nr_refspec = 0;
 	char **refspec = NULL;
 	struct remote_lock *ref_lock = NULL;
+	struct remote_lock *info_ref_lock = NULL;
 	struct rev_info revs;
 	int rc = 0;
 	int i;
@@ -1667,6 +2169,18 @@ int main(int argc, char **argv)
 		goto cleanup;
 	}
 
+	/* Check whether the remote has server info files */
+	remote->can_update_info_refs = 0;
+	remote->has_info_refs = remote_exists("info/refs");
+	remote->has_info_packs = remote_exists("objects/info/packs");
+	if (remote->has_info_refs) {
+		info_ref_lock = lock_remote("info/refs", LOCK_TIME);
+		if (info_ref_lock)
+			remote->can_update_info_refs = 1;
+	}
+	if (remote->has_info_packs)
+		fetch_indices();
+
 	/* Get a list of all local and remote heads to validate refspecs */
 	get_local_heads();
 	fprintf(stderr, "Fetching remote heads...\n");
@@ -1769,7 +2283,6 @@ int main(int argc, char **argv)
 		pushing = 0;
 		prepare_revision_walk(&revs);
 		mark_edges_uninteresting(revs.commits);
-		fetch_indices();
 		get_delta(&revs, ref_lock);
 		finish_all_active_slots();
 
@@ -1792,6 +2305,18 @@ int main(int argc, char **argv)
 		check_locks();
 	}
 
+	/* Update remote server info if appropriate */
+	if (remote->has_info_refs && new_refs) {
+		if (info_ref_lock && remote->can_update_info_refs) {
+			fprintf(stderr, "Updating remote server info\n");
+			update_remote_info_refs(info_ref_lock);
+		} else {
+			fprintf(stderr, "Unable to update server info\n");
+		}
+	}
+	if (info_ref_lock)
+		unlock_remote(info_ref_lock);
+
  cleanup:
 	free(remote);
 
-- 
1.2.4.g8e81-dirty

^ permalink raw reply related

* [PATCH 1/6] http-push: fix revision walk
From: Nick Hengeveld @ 2006-03-11  4:17 UTC (permalink / raw)
  To: git

The revision walk was not including tags because setup_revisions zeroes out
the revs flags.  Pass --objects so it picks up all the necessary bits.

---

 http-push.c |   13 +++++--------
 1 files changed, 5 insertions(+), 8 deletions(-)

4bff87736bfc51313e7e23ebd9b99bc476c00616
diff --git a/http-push.c b/http-push.c
index 226d719..4c1b0c3 100644
--- a/http-push.c
+++ b/http-push.c
@@ -1752,23 +1752,20 @@ int main(int argc, char **argv)
 		}
 
 		/* Set up revision info for this refspec */
-		const char *commit_argv[3];
-		int commit_argc = 2;
+		const char *commit_argv[4];
+		int commit_argc = 3;
 		char *new_sha1_hex = strdup(sha1_to_hex(ref->new_sha1));
 		char *old_sha1_hex = NULL;
-		commit_argv[1] = new_sha1_hex;
+		commit_argv[1] = "--objects";
+		commit_argv[2] = new_sha1_hex;
 		if (!push_all && !is_zero_sha1(ref->old_sha1)) {
 			old_sha1_hex = xmalloc(42);
 			sprintf(old_sha1_hex, "^%s",
 				sha1_to_hex(ref->old_sha1));
-			commit_argv[2] = old_sha1_hex;
+			commit_argv[3] = old_sha1_hex;
 			commit_argc++;
 		}
-		revs.commits = NULL;
 		setup_revisions(commit_argc, commit_argv, &revs, NULL);
-		revs.tag_objects = 1;
-		revs.tree_objects = 1;
-		revs.blob_objects = 1;
 		free(new_sha1_hex);
 		if (old_sha1_hex) {
 			free(old_sha1_hex);
-- 
1.2.4.g8e81-dirty

^ permalink raw reply related

* [PATCH 0/6] http-push updates
From: Nick Hengeveld @ 2006-03-11  4:17 UTC (permalink / raw)
  To: git

This series fixes a few http transport and http-push bugs, includes some
refactoring, and adds functionality to update remote server info/refs.

I'm considering future support for initializing a remote repo if the
remote url points to an empty directory and the --force arg is present.
Any thoughts?

I'm also planning to add support for using packs to send updates, and
for updating remote server objects/info/packs.  I'm not sure whether it
makes sense to always send packs or to only do so when enough objects
need to be pushed.

-- 
For a successful technology, reality must take precedence over public
relations, for nature cannot be fooled.

^ permalink raw reply

* [PATCH 2/6] HTTP slot reuse fixes
From: Nick Hengeveld @ 2006-03-11  4:18 UTC (permalink / raw)
  To: git

Incorporate into http-push a fix related to accessing slot results after
the slot was reused, and fix a case in run_active_slot where a
finished slot wasn't detected if the slot was reused.

---

 http-push.c |   56 +++++++++++++++++++++++++++++++++++++++-----------------
 http.c      |    8 +++++++-
 http.h      |    1 +
 3 files changed, 47 insertions(+), 18 deletions(-)

097851a0a1d713a9b69eb700b37809734af0c31e
diff --git a/http-push.c b/http-push.c
index 4c1b0c3..1b0b3a8 100644
--- a/http-push.c
+++ b/http-push.c
@@ -302,6 +302,7 @@ static void start_move(struct transfer_r
 static int refresh_lock(struct remote_lock *check_lock)
 {
 	struct active_request_slot *slot;
+	struct slot_results results;
 	char *if_header;
 	char timeout_header[25];
 	struct curl_slist *dav_headers = NULL;
@@ -329,6 +330,7 @@ static int refresh_lock(struct remote_lo
 		dav_headers = curl_slist_append(dav_headers, timeout_header);
 
 		slot = get_active_slot();
+		slot->results = &results;
 		curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
 		curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
 		curl_easy_setopt(slot->curl, CURLOPT_URL, lock->url);
@@ -337,8 +339,8 @@ static int refresh_lock(struct remote_lo
 
 		if (start_active_slot(slot)) {
 			run_active_slot(slot);
-			if (slot->curl_result != CURLE_OK) {
-				fprintf(stderr, "Got HTTP error %ld\n", slot->http_code);
+			if (results.curl_result != CURLE_OK) {
+				fprintf(stderr, "Got HTTP error %ld\n", results.http_code);
 				lock->active = 0;
 			} else {
 				lock->active = 1;
@@ -509,16 +511,18 @@ static int fetch_index(unsigned char *sh
 
 	FILE *indexfile;
 	struct active_request_slot *slot;
+	struct slot_results results;
 
 	/* Don't use the index if the pack isn't there */
 	url = xmalloc(strlen(remote->url) + 65);
 	sprintf(url, "%s/objects/pack/pack-%s.pack", remote->url, hex);
 	slot = get_active_slot();
+	slot->results = &results;
 	curl_easy_setopt(slot->curl, CURLOPT_URL, url);
 	curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 1);
 	if (start_active_slot(slot)) {
 		run_active_slot(slot);
-		if (slot->curl_result != CURLE_OK) {
+		if (results.curl_result != CURLE_OK) {
 			free(url);
 			return error("Unable to verify pack %s is available",
 				     hex);
@@ -543,6 +547,7 @@ static int fetch_index(unsigned char *sh
 			     filename);
 
 	slot = get_active_slot();
+	slot->results = &results;
 	curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0);
 	curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
 	curl_easy_setopt(slot->curl, CURLOPT_FILE, indexfile);
@@ -566,7 +571,7 @@ static int fetch_index(unsigned char *sh
 
 	if (start_active_slot(slot)) {
 		run_active_slot(slot);
-		if (slot->curl_result != CURLE_OK) {
+		if (results.curl_result != CURLE_OK) {
 			free(url);
 			fclose(indexfile);
 			return error("Unable to get pack index %s\n%s", url,
@@ -606,6 +611,7 @@ static int fetch_indices(void)
 	int i = 0;
 
 	struct active_request_slot *slot;
+	struct slot_results results;
 
 	data = xmalloc(4096);
 	memset(data, 0, 4096);
@@ -620,16 +626,17 @@ static int fetch_indices(void)
 	sprintf(url, "%s/objects/info/packs", remote->url);
 
 	slot = get_active_slot();
+	slot->results = &results;
 	curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);
 	curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
 	curl_easy_setopt(slot->curl, CURLOPT_URL, url);
 	curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL);
 	if (start_active_slot(slot)) {
 		run_active_slot(slot);
-		if (slot->curl_result != CURLE_OK) {
+		if (results.curl_result != CURLE_OK) {
 			free(buffer.buffer);
 			free(url);
-			if (slot->http_code == 404)
+			if (results.http_code == 404)
 				return 0;
 			else
 				return error("%s", curl_errorstr);
@@ -716,6 +723,7 @@ int fetch_ref(char *ref, unsigned char *
         struct buffer buffer;
 	char *base = remote->url;
 	struct active_request_slot *slot;
+	struct slot_results results;
         buffer.size = 41;
         buffer.posn = 0;
         buffer.buffer = hex;
@@ -723,13 +731,14 @@ int fetch_ref(char *ref, unsigned char *
         
 	url = quote_ref_url(base, ref);
 	slot = get_active_slot();
+	slot->results = &results;
 	curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);
 	curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
 	curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL);
 	curl_easy_setopt(slot->curl, CURLOPT_URL, url);
 	if (start_active_slot(slot)) {
 		run_active_slot(slot);
-		if (slot->curl_result != CURLE_OK)
+		if (results.curl_result != CURLE_OK)
 			return error("Couldn't get %s for %s\n%s",
 				     url, ref, curl_errorstr);
 	} else {
@@ -913,6 +922,7 @@ xml_cdata(void *userData, const XML_Char
 static struct remote_lock *lock_remote(char *path, long timeout)
 {
 	struct active_request_slot *slot;
+	struct slot_results results;
 	struct buffer out_buffer;
 	struct buffer in_buffer;
 	char *out_data;
@@ -946,14 +956,15 @@ static struct remote_lock *lock_remote(c
 	while (ep) {
 		*ep = 0;
 		slot = get_active_slot();
+		slot->results = &results;
 		curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
 		curl_easy_setopt(slot->curl, CURLOPT_URL, url);
 		curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_MKCOL);
 		curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
 		if (start_active_slot(slot)) {
 			run_active_slot(slot);
-			if (slot->curl_result != CURLE_OK &&
-			    slot->http_code != 405) {
+			if (results.curl_result != CURLE_OK &&
+			    results.http_code != 405) {
 				fprintf(stderr,
 					"Unable to create branch path %s\n",
 					url);
@@ -985,6 +996,7 @@ static struct remote_lock *lock_remote(c
 	dav_headers = curl_slist_append(dav_headers, "Content-Type: text/xml");
 
 	slot = get_active_slot();
+	slot->results = &results;
 	curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);
 	curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.size);
 	curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
@@ -1003,7 +1015,7 @@ static struct remote_lock *lock_remote(c
 
 	if (start_active_slot(slot)) {
 		run_active_slot(slot);
-		if (slot->curl_result == CURLE_OK) {
+		if (results.curl_result == CURLE_OK) {
 			ctx.name = xcalloc(10, 1);
 			ctx.len = 0;
 			ctx.cdata = NULL;
@@ -1053,6 +1065,7 @@ static struct remote_lock *lock_remote(c
 static int unlock_remote(struct remote_lock *lock)
 {
 	struct active_request_slot *slot;
+	struct slot_results results;
 	char *lock_token_header;
 	struct curl_slist *dav_headers = NULL;
 	int rc = 0;
@@ -1063,6 +1076,7 @@ static int unlock_remote(struct remote_l
 	dav_headers = curl_slist_append(dav_headers, lock_token_header);
 
 	slot = get_active_slot();
+	slot->results = &results;
 	curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
 	curl_easy_setopt(slot->curl, CURLOPT_URL, lock->url);
 	curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_UNLOCK);
@@ -1070,11 +1084,11 @@ static int unlock_remote(struct remote_l
 
 	if (start_active_slot(slot)) {
 		run_active_slot(slot);
-		if (slot->curl_result == CURLE_OK)
+		if (results.curl_result == CURLE_OK)
 			rc = 1;
 		else
 			fprintf(stderr, "Got HTTP error %ld\n",
-				slot->http_code);
+				results.http_code);
 	} else {
 		fprintf(stderr, "Unable to start request\n");
 	}
@@ -1091,6 +1105,7 @@ static void crawl_remote_refs(char *path
 {
 	char *url;
 	struct active_request_slot *slot;
+	struct slot_results results;
 	struct buffer in_buffer;
 	struct buffer out_buffer;
 	char *in_data;
@@ -1125,6 +1140,7 @@ static void crawl_remote_refs(char *path
 	dav_headers = curl_slist_append(dav_headers, "Content-Type: text/xml");
 
 	slot = get_active_slot();
+	slot->results = &results;
 	curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);
 	curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.size);
 	curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
@@ -1137,7 +1153,7 @@ static void crawl_remote_refs(char *path
 
 	if (start_active_slot(slot)) {
 		run_active_slot(slot);
-		if (slot->curl_result == CURLE_OK) {
+		if (results.curl_result == CURLE_OK) {
 			ctx.name = xcalloc(10, 1);
 			ctx.len = 0;
 			ctx.cdata = NULL;
@@ -1171,6 +1187,7 @@ static void get_remote_object_list(unsig
 {
 	char *url;
 	struct active_request_slot *slot;
+	struct slot_results results;
 	struct buffer in_buffer;
 	struct buffer out_buffer;
 	char *in_data;
@@ -1203,6 +1220,7 @@ static void get_remote_object_list(unsig
 	dav_headers = curl_slist_append(dav_headers, "Content-Type: text/xml");
 
 	slot = get_active_slot();
+	slot->results = &results;
 	curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);
 	curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.size);
 	curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
@@ -1215,7 +1233,7 @@ static void get_remote_object_list(unsig
 
 	if (start_active_slot(slot)) {
 		run_active_slot(slot);
-		if (slot->curl_result == CURLE_OK) {
+		if (results.curl_result == CURLE_OK) {
 			remote_dir_exists[parent] = 1;
 			ctx.name = xcalloc(10, 1);
 			ctx.len = 0;
@@ -1250,6 +1268,7 @@ static void get_remote_object_list(unsig
 static int locking_available(void)
 {
 	struct active_request_slot *slot;
+	struct slot_results results;
 	struct buffer in_buffer;
 	struct buffer out_buffer;
 	char *in_data;
@@ -1278,6 +1297,7 @@ static int locking_available(void)
 	dav_headers = curl_slist_append(dav_headers, "Content-Type: text/xml");
 	
 	slot = get_active_slot();
+	slot->results = &results;
 	curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);
 	curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.size);
 	curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
@@ -1290,7 +1310,7 @@ static int locking_available(void)
 
 	if (start_active_slot(slot)) {
 		run_active_slot(slot);
-		if (slot->curl_result == CURLE_OK) {
+		if (results.curl_result == CURLE_OK) {
 			ctx.name = xcalloc(10, 1);
 			ctx.len = 0;
 			ctx.cdata = NULL;
@@ -1416,6 +1436,7 @@ static void get_delta(struct rev_info *r
 static int update_remote(unsigned char *sha1, struct remote_lock *lock)
 {
 	struct active_request_slot *slot;
+	struct slot_results results;
 	char *out_data;
 	char *if_header;
 	struct buffer out_buffer;
@@ -1437,6 +1458,7 @@ static int update_remote(unsigned char *
 	out_buffer.buffer = out_data;
 
 	slot = get_active_slot();
+	slot->results = &results;
 	curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);
 	curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.size);
 	curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
@@ -1451,10 +1473,10 @@ static int update_remote(unsigned char *
 		run_active_slot(slot);
 		free(out_data);
 		free(if_header);
-		if (slot->curl_result != CURLE_OK) {
+		if (results.curl_result != CURLE_OK) {
 			fprintf(stderr,
 				"PUT error: curl result=%d, HTTP code=%ld\n",
-				slot->curl_result, slot->http_code);
+				results.curl_result, results.http_code);
 			/* We should attempt recovery? */
 			return 0;
 		}
diff --git a/http.c b/http.c
index 14a7669..9604e33 100644
--- a/http.c
+++ b/http.c
@@ -339,6 +339,7 @@ struct active_request_slot *get_active_s
 	slot->in_use = 1;
 	slot->local = NULL;
 	slot->results = NULL;
+	slot->finished = NULL;
 	slot->callback_data = NULL;
 	slot->callback_func = NULL;
 	curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, pragma_header);
@@ -389,8 +390,10 @@ void run_active_slot(struct active_reque
 	fd_set excfds;
 	int max_fd;
 	struct timeval select_timeout;
+	int finished = 0;
 
-	while (slot->in_use) {
+	slot->finished = &finished;
+	while (!finished) {
 		data_received = 0;
 		step_active_slots();
 
@@ -442,6 +445,9 @@ static void finish_active_slot(struct ac
 	closedown_active_slot(slot);
         curl_easy_getinfo(slot->curl, CURLINFO_HTTP_CODE, &slot->http_code);
 
+	if (slot->finished != NULL)
+		(*slot->finished) = 1;
+
 	/* Store slot results so they can be read after the slot is reused */
 	if (slot->results != NULL) {
 		slot->results->curl_result = slot->curl_result;
diff --git a/http.h b/http.h
index 36fa154..9ca16ac 100644
--- a/http.h
+++ b/http.h
@@ -35,6 +35,7 @@ struct active_request_slot
 	int in_use;
 	CURLcode curl_result;
 	long http_code;
+	int *finished;
 	struct slot_results *results;
 	void *callback_data;
 	void (*callback_func)(void *data);
-- 
1.2.4.g8e81-dirty

^ permalink raw reply related

* proxy documentation
From: Tony Luck @ 2006-03-11  0:49 UTC (permalink / raw)
  To: git

Example documentation for proxy settings in Documentation/git-repo-config.txt
shows:

[proxy]
                command="ssh" for "ssh://kernel.org/"

But the code in connect.c:git_proxy_command_options() looks
for "core.gitproxy" rather than "proxy.command".

I've only just started looking at the proxy support ... is it just the name
that is wrong in the documentation, or are there other issues here?

proxy.command sounds like a better name than core.gitproxy ... so
maybe the Docs are "right" and the code is "wrong"?

-Tony

^ permalink raw reply

* Re: git-rev-list bug?
From: Junio C Hamano @ 2006-03-10 22:42 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git, Catalin Marinas
In-Reply-To: <Pine.LNX.4.64.0603101030160.18022@g5.osdl.org>

Linus Torvalds <torvalds@osdl.org> writes:

> On Fri, 10 Mar 2006, Junio C Hamano wrote:
>> 
>> So we would need a combination of both, something like this?
>
> Looks good to me.
>
> As does the 'revs.prune_fn' abstraction by Fredrik Kuivinen, for that 
> matter. Ack to both.

Thanks.  I'm swamped by day-job today so will apply it sometime
tomorrow.

^ permalink raw reply

* annotate.perl triggers rpm bug
From: sean @ 2006-03-10 21:23 UTC (permalink / raw)
  To: Ryan Anderson; +Cc: git

Hi Ryan

Commit 87475f4 exposes a problem in the creation of rpms (at least
on Fedora boxes).   RPM automatically creates a dependency for any
perl "use" lines, and the above commit fools it into creating a false 
dependecy for the nonexistent perl package "revs" because of this
portion of the diff:

+       -S, --rev-file revs-file
+                       use revs from revs-file instead of calling git-rev-list
                        ^^ fools rpm

Obviously this creates a problem when someone goes to install the git-core
rpm.  Any chance we could get a small change to work around this bug in rpm?

Thanks,
Sean


diff --git a/git-annotate.perl b/git-annotate.perl
index feea0a2..6805b8b 100755
--- a/git-annotate.perl
+++ b/git-annotate.perl
@@ -20,7 +20,7 @@ sub usage() {
        -r, --rename
                        Follow renames (Defaults on).
        -S, --rev-file revs-file
-                       use revs from revs-file instead of calling git-rev-list
+                       uses revs from revs-file instead of calling git-rev-list
        -h, --help
                        This message.
 ';

^ permalink raw reply related

* [PATCH] Fix testsuite to account for removed dot
From: Pavel Roskin @ 2006-03-10 21:21 UTC (permalink / raw)
  To: git

Signed-off-by: Pavel Roskin <proski@gnu.org>
---

 t/t1200-tutorial.sh |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/t/t1200-tutorial.sh b/t/t1200-tutorial.sh
index c8a85f9..1002413 100755
--- a/t/t1200-tutorial.sh
+++ b/t/t1200-tutorial.sh
@@ -128,7 +128,7 @@ test_expect_success 'git show-branch' 'c
 git checkout mybranch
 
 cat > resolve.expect << EOF
-Updating from VARIABLE to VARIABLE.
+Updating from VARIABLE to VARIABLE
  example |    1 +
  hello   |    1 +
  2 files changed, 2 insertions(+), 0 deletions(-)

^ permalink raw reply related

* Re: [PATCH 1/3] cg-mv doesn't work with bash 3.1.7 due to excessive quotes
From: Pavel Roskin @ 2006-03-10 20:48 UTC (permalink / raw)
  To: Petr Baudis; +Cc: git
In-Reply-To: <1141395067.30343.14.camel@dv>

Hello, Petr!

On Fri, 2006-03-03 at 09:11 -0500, Pavel Roskin wrote:
> On Thu, 2006-03-02 at 21:27 -0800, Junio C Hamano wrote:
> > Pavel Roskin <proski@gnu.org> writes:
> > 
> > > -	ARGS2["${#ARGS2[@]}"]="$_git_relpath${arg%/}"
> > > +	ARGS2[${#ARGS2[@]}]="$_git_relpath${arg%/}"

Any issues with this patch?  FC5 is due in a week.  Expect and outcry
from the new bash 3.1.7 users if the fixed cogito is not available
shortly.

Bash is not as wrong as it may seem.  Left hand side in assignments is
already a special case in earlier versions of bash, just not in the
index:

bash 3.00.16 (FC4)
$ f"oo"=bar
bash: foo=bar: command not found
$ foo["0"]=bar
$

bash 3.1.7 (FC5)
$ f"oo"=bar
bash: foo=bar: command not found
$ foo["0"]=bar
bash: "0": syntax error: operand expected (error token is ""0"")
$

-- 
Regards,
Pavel Roskin

^ permalink raw reply

* Re: git-rev-list bug?
From: Linus Torvalds @ 2006-03-10 18:31 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Catalin Marinas
In-Reply-To: <7vslpqy4u7.fsf@assigned-by-dhcp.cox.net>



On Fri, 10 Mar 2006, Junio C Hamano wrote:
> 
> So we would need a combination of both, something like this?

Looks good to me.

As does the 'revs.prune_fn' abstraction by Fredrik Kuivinen, for that 
matter. Ack to both.

		Linus

^ permalink raw reply

* Re: bug?: stgit creates (unneccessary?) conflicts when pulling
From: Shawn Pearce @ 2006-03-10 16:23 UTC (permalink / raw)
  To: Catalin Marinas; +Cc: git
In-Reply-To: <b0943d9e0603091400o2cd0291h@mail.gmail.com>

Catalin Marinas <catalin.marinas@gmail.com> wrote:
> On 01/03/06, Shawn Pearce <spearce@spearce.org> wrote:
> > Speaking of making StGIT faster: earlier we were talking about how
> > git-diff|git-apply is faster than a 3 way git-read-tree on large
> > merges when there are many structural changes in the tree due to
> > the smaller number of process spawns required.
> >
> > You might want to take a look at pg--merge-all: This is sort of based
> > on git-merge-recursive, but I've gotten it down to just a handful
> > of process spawns, aside from the stupidity of git-checkout-index.
> 
> Trying to implement this, I've just noticed that git-read-tree has a
> --aggressive option which takes care of the file removals. Adding this
> option lowered the pushing time in StGIT from ~2 min to under 2
> seconds (merges between 2.6.14 and the latest kernel). There's
> probably no need to deal with file removals in pg--merge-all anymore.


Thanks for the heads up.  I'll have to add that in.  In case you
didn't notice the list traffic I have added a --stage=all switch to
git-checkout-index to grab into temporary files all unmerged stages.

I'm still working on integrating that into pg--merge-all but the
idea is to save on the fork/exec of git-unpack-file when I get into
the diff portion of the merge process.  At least on Cygwin (a place
where I'm really using pg) it will save time as the forks are so
expensive there.  Linux users may not see any improvement from it.

I also added --stdin to git-checkout-index but pg--merge-all is
still using xargs.  I just haven't had time to convert it over and
push it up to my public repo.  Hopefully I'll get both of those
done this weekend.

I've started to get busy with an Eclipse plugin for GIT so my work
with pg is likely going to slow down a little (besides its doing
most of what I need at this point).  But the next thing I was going
to try to add to GIT to boost pg's performance was to integrate
a diff library, so we aren't forking out a diff process for every
file we need to extract a diff for.

-- 
Shawn.

^ permalink raw reply

* [PATCH 4/4] Add quick reference
From: Jonas Fonseca @ 2006-03-10 14:48 UTC (permalink / raw)
  To: Petr Baudis; +Cc: git
In-Reply-To: <20060310144106.GA7920@diku.dk>

Signed-off-by: Jonas Fonseca <fonseca@diku.dk>

---

 If someone wants to have a look, I've put it here:
 http://www.diku.dk/hjemmesider/studerende/fonseca/cg-ref.pdf

 Documentation/Makefile             |    9 ++-
 Documentation/asciidoc.conf        |    4 +
 Documentation/make-cg-ref-asciidoc |   61 +++++++++++++++++++
 Documentation/quick-reference.txt  |  114 ++++++++++++++++++++++++++++++++++++
 4 files changed, 185 insertions(+), 3 deletions(-)

diff --git a/Documentation/Makefile b/Documentation/Makefile
index d316a14..439d20f 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -4,14 +4,14 @@ CG_SRC=$(filter-out $(CG_IGNORE), $(wild
 PACKAGE=cogito
 
 MAN1_TXT=$(patsubst ../cg%,cg%.1.txt,$(CG_SRC))
-MAN7_TXT=$(PACKAGE).7.txt
+MAN7_TXT=$(PACKAGE).7.txt cg-ref.7.txt
 
-DOC_HTML=$(patsubst %.txt,%.html,$(MAN1_TXT) $(MAN7_TXT)) introduction.html
+DOC_HTML=$(patsubst %.txt,%.html,$(MAN1_TXT) $(MAN7_TXT)) quick-reference.html introduction.html
 
 DOC_MAN1=$(patsubst %.txt,%,$(MAN1_TXT))
 DOC_MAN7=$(patsubst %.txt,%,$(MAN7_TXT))
 
-DOC_PDF=$(patsubst %.txt,%.pdf,$(MAN1_TXT) $(MAN7_TXT)) introduction.pdf
+DOC_PDF=$(patsubst %.txt,%.pdf,$(MAN1_TXT) $(MAN7_TXT)) quick-reference.pdf introduction.pdf
 
 prefix=$(HOME)
 bin=$(prefix)/bin
@@ -100,6 +100,9 @@ introduction.xml: ../README
 $(PACKAGE).7.txt : make-$(PACKAGE)-asciidoc
 	./make-$(PACKAGE)-asciidoc > $@
 
+cg-ref.7.txt : quick-reference.txt make-cg-ref-asciidoc
+	CGPACKAGE=$(PACKAGE) ./make-cg-ref-asciidoc $< > $@
+
 # It seems that cg%.txt won't match this so use an explicit rule
 cg.1.txt : ../cg make-cg-asciidoc
 	CGPACKAGE=$(PACKAGE) ./make-cg-asciidoc $< > $@
diff --git a/Documentation/asciidoc.conf b/Documentation/asciidoc.conf
index baefb2f..69f1646 100644
--- a/Documentation/asciidoc.conf
+++ b/Documentation/asciidoc.conf
@@ -19,3 +19,7 @@ ifdef::backend-xhtml11[]
 [gitlink-inlinemacro]
 <a href="{target}.html">{target}{0?({0})}</a>
 endif::backend-xhtml11[]
+
+[attributes]
+# Five non breaking spaces used for option indentation in the quick reference
+cg-refopt=&#160;&#160;&#160;&#160;&#160;
diff --git a/Documentation/make-cg-ref-asciidoc b/Documentation/make-cg-ref-asciidoc
new file mode 100755
index 0000000..7fd60ca
--- /dev/null
+++ b/Documentation/make-cg-ref-asciidoc
@@ -0,0 +1,61 @@
+#!/usr/bin/env bash
+#
+# Generate asciidoc manpage markup from Cogito quick reference file.
+# Copyright (c) Jonas Fonseca, 2006
+#
+# Takes the path to the reference file. Prints the manpage to stdout.
+
+PACKAGE=${CGPACKAGE:-cogito}
+
+ref=$1
+
+cat <<__END__
+cg-ref(7)
+=========
+
+NAME
+----
+cg-ref - Cogito quick reference
+
+SYNOPSIS
+--------
+A list of frequently used commands grouped with related commands.
+
+DESCRIPTION
+-----------
+
+__END__
+
+sed '0,/^$/d' < "$ref" | \
+sed '/^`/d' | \
+sed 's/--/../g' | \
+sed '/frame="none"/,1d' | \
+sed 's/\\$//' | \
+while read line; do
+	if echo "$line" | grep -q '^.*:$'; then
+		echo "$line"
+		echo "$line" | sed "s/[^~]/~/g"
+		echo
+		echo "[verse]"
+	else
+		entry=$(echo "$line" | sed "s/^\([^	]*\)	/\1/")
+		space=$(echo "$entry" | sed "s/[^*']//g" | sed "s/[*']/ /g")
+
+		echo "$line" | sed "s/^\([^	]*\)	/\1$space	/"
+	fi
+done | \
+sed 's/.*cg-refopt} \(-[^	]*\)/    \1        /' | \
+sed "s/[*]\([^*]*\)[*]/\1/g" | \
+sed "s/[']\([^']*\)[']/\1/g"
+
+cat << __END__
+
+COPYRIGHT
+---------
+Copyright (C) Jonas Fonseca, 2006.
+
+SEE ALSO
+--------
+gitlink:cg-ref[7] is part of gitlink:${PACKAGE}[7],
+a toolkit for managing gitlink:git[7] trees.
+__END__
diff --git a/Documentation/quick-reference.txt b/Documentation/quick-reference.txt
new file mode 100644
index 0000000..11c0a13
--- /dev/null
+++ b/Documentation/quick-reference.txt
@@ -0,0 +1,114 @@
+Cogito Quick Reference
+======================
+
+[frame="none"]
+`-------------------------------`---------------------------------------------
+Getting help:
+------------------------------------------------------------------------------
+*cg help* 'command'		Show help for a command
+*cg* 'command' -h		Show usage summary for a command
+------------------------------------------------------------------------------
+
+[frame="none"]
+`-------------------------------`---------------------------------------------
+Repository creation:
+------------------------------------------------------------------------------
+*cg init*			Create a repository in the current directory
+*cg clone* 'url'		Clone a remote repository
+------------------------------------------------------------------------------
+
+[frame="none"]
+`-------------------------------`---------------------------------------------
+File operations:
+------------------------------------------------------------------------------
+*cg add* 'file'			Add file to the working tree
+*cg add* -r 'directory'		Recursively add files in directory
+*cg rm* 'file'			Remove file or directory from the working tree
+*cg rm* -r 'directory'		Recursively remove files in directory
+{cg-refopt} -f			Delete file from disk
+*cg mv* 'file' 'dest'		Move file or directory to new location
+{cg-refopt} -f			Overwrite existing destination files
+*cg restore* 'file'		Restore file
+{cg-refopt} -r 'rev'		Bring back file from revision (and add it)
+{cg-refopt} -f			Overwrite uncommitted changes
+------------------------------------------------------------------------------
+
+[frame="none"]
+`-------------------------------`---------------------------------------------
+Examining History:
+------------------------------------------------------------------------------
+*cg log* '[file]'		View commit log
+{cg-refopt} -r 'rev'		Limit to revision range
+{cg-refopt} -f			List affected files
+{cg-refopt} -s			Summarize commits to one line
+*cg diff* '[file]'		Show diff of changes
+{cg-refopt} -r 'rev'		Diff revision instead of working tree
+{cg-refopt} -p			Diff against parent
+{cg-refopt} -s			Show diff stat
+------------------------------------------------------------------------------
+
+[frame="none"]
+`-------------------------------`---------------------------------------------
+Working tree:
+------------------------------------------------------------------------------
+*cg status* '[file]'		Show branches and status of the working tree
+*cg commit*			Commit the working tree
+{cg-refopt} -m 'message'	Append message to commit log
+*cg admin-uncommit*		Undo commit
+*cg reset*			Reset the working treeUndo commit
+*cg seek* 'rev'			Temporarily switch the working tree
+*cg clean*			Remove file not under revision control
+------------------------------------------------------------------------------
+
+[frame="none"]
+`-------------------------------`---------------------------------------------
+Remote branches:
+------------------------------------------------------------------------------
+*cg branch-ls*			List remote branches
+*cg branch-add* 'branch' 'url'	Add remote branch
+*cg branch-chg* 'branch' 'url'	Change URL of existing branch
+*cg fetch* 'branch'		Fetch changes from a remote branch
+*cg update* 'branch'		Fetch and merge changes from a remote branch
+*cg push* 'branch'		Push changes to a remote branch
+------------------------------------------------------------------------------
+
+[frame="none"]
+`-------------------------------`---------------------------------------------
+Local branches:
+------------------------------------------------------------------------------
+*cg merge* 'branch'		Merge changes from branch
+*cg switch* 'branch'		Switch the working tree to branch
+{cg-refopt} -r 'rev'		Create branch from revision
+{cg-refopt} -f			Overwrite existing branch
+------------------------------------------------------------------------------
+
+[frame="none"]
+`-------------------------------`---------------------------------------------
+Exporting and importing:
+------------------------------------------------------------------------------
+*cg patch*			Apply patch
+*cg mkpatch*			Format a patch with log message and diffstat
+{cg-refopt} -r 'rev'		Limit to revision range
+*cg export* 'directory'		Export "snapshot" to directory
+{cg-refopt} -r 'rev'			
+------------------------------------------------------------------------------
+
+[frame="none"]
+`-------------------------------`---------------------------------------------
+Tags:
+------------------------------------------------------------------------------
+*cg tag* 'name' 'rev'		Create tag for a given revision
+{cg-refopt} -s			Sign tag with your private key using GPG
+*cg tag-ls*			Show name and revision for all tags
+------------------------------------------------------------------------------
+
+`-------------------------------`---------------------------------------------
+File status flags:
+------------------------------------------------------------------------------
+?				file is unknown
+A				file has been added.
+D				file has been deleted.
+!				file is not in working tree
+M				file has been touched or modified
+m				file has been touched or modified (during merge)
+------------------------------------------------------------------------------

-- 
Jonas Fonseca

^ permalink raw reply related

* [PATCH 3/4] Generate PDF documents using docbook2pdf
From: Jonas Fonseca @ 2006-03-10 14:44 UTC (permalink / raw)
  To: Petr Baudis; +Cc: git
In-Reply-To: <20060310144106.GA7920@diku.dk>

Unfortunately xmlto cannot be used for this,

Signed-off-by: Jonas Fonseca <fonseca@diku.dk>

---

 Documentation/Makefile |   14 ++++++++++++--
 1 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/Documentation/Makefile b/Documentation/Makefile
index 00e9276..d316a14 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -11,6 +11,8 @@ DOC_HTML=$(patsubst %.txt,%.html,$(MAN1_
 DOC_MAN1=$(patsubst %.txt,%,$(MAN1_TXT))
 DOC_MAN7=$(patsubst %.txt,%,$(MAN7_TXT))
 
+DOC_PDF=$(patsubst %.txt,%.pdf,$(MAN1_TXT) $(MAN7_TXT)) introduction.pdf
+
 prefix=$(HOME)
 bin=$(prefix)/bin
 mandir=$(prefix)/man
@@ -35,15 +37,17 @@ all: html man txt
 
 html: $(DOC_HTML)
 
-
 man: man1 man7
 man1: $(DOC_MAN1)
 man7: $(DOC_MAN7)
 
+pdf: $(DOC_PDF)
+
 txt: txt1 txt7
 txt1: $(MAN1_TXT)
 txt7: $(MAN7_TXT)
 
+
 install: man txt
 	$(INSTALL) -m755 -d $(DESTDIR)/$(txtdir)
 	$(INSTALL) $(MAN1_TXT) $(MAN7_TXT) $(DESTDIR)/$(txtdir)
@@ -56,13 +60,16 @@ install-html: html
 	$(INSTALL) $(DOC_HTML) $(DESTDIR)/$(htmldir)
 
 clean:
-	rm -f *.xml *.html *.1 *.7 cg*.[17].txt $(PACKAGE).7.txt
+	rm -f *.xml *.html *.pdf *.1 *.7 cg*.[17].txt $(PACKAGE).7.txt
 
 .PRECIOUS: cg%.txt
 
 introduction.html: ../README
 	asciidoc -b xhtml11 -d article -f asciidoc.conf -o $@ $<
 
+introduction.xml: ../README
+	asciidoc -b docbook -d article -f asciidoc.conf -o $@ $<
+
 %.1.html : %.1.txt
 	asciidoc -b xhtml11 -d manpage -f asciidoc.conf $<
 
@@ -87,6 +94,9 @@ introduction.html: ../README
 %.7 : %.7.xml
 	xmlto man $<
 
+%.pdf : %.xml
+	docbook2pdf $<
+
 $(PACKAGE).7.txt : make-$(PACKAGE)-asciidoc
 	./make-$(PACKAGE)-asciidoc > $@
 
-- 
Jonas Fonseca

^ permalink raw reply related

* [PATCH 2/4] Encode the manpage section in the file name
From: Jonas Fonseca @ 2006-03-10 14:43 UTC (permalink / raw)
  To: Petr Baudis; +Cc: git
In-Reply-To: <20060310144106.GA7920@diku.dk>

This makes it easier to handle other document types.

Signed-off-by: Jonas Fonseca <fonseca@diku.dk>

---

 Documentation/Makefile |   39 +++++++++++++++++++++++++++------------
 1 files changed, 27 insertions(+), 12 deletions(-)

diff --git a/Documentation/Makefile b/Documentation/Makefile
index 661c259..00e9276 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -3,13 +3,13 @@ CG_SRC=$(filter-out $(CG_IGNORE), $(wild
 
 PACKAGE=cogito
 
-MAN1_TXT=$(patsubst ../cg%,cg%.txt,$(CG_SRC))
-MAN7_TXT=$(PACKAGE).txt
+MAN1_TXT=$(patsubst ../cg%,cg%.1.txt,$(CG_SRC))
+MAN7_TXT=$(PACKAGE).7.txt
 
 DOC_HTML=$(patsubst %.txt,%.html,$(MAN1_TXT) $(MAN7_TXT)) introduction.html
 
-DOC_MAN1=$(patsubst %.txt,%.1,$(MAN1_TXT))
-DOC_MAN7=$(patsubst %.txt,%.7,$(MAN7_TXT))
+DOC_MAN1=$(patsubst %.txt,%,$(MAN1_TXT))
+DOC_MAN7=$(patsubst %.txt,%,$(MAN7_TXT))
 
 prefix=$(HOME)
 bin=$(prefix)/bin
@@ -56,28 +56,43 @@ install-html: html
 	$(INSTALL) $(DOC_HTML) $(DESTDIR)/$(htmldir)
 
 clean:
-	rm -f *.xml *.html *.1 *.7 cg*.txt $(PACKAGE).txt
+	rm -f *.xml *.html *.1 *.7 cg*.[17].txt $(PACKAGE).7.txt
 
 .PRECIOUS: cg%.txt
 
 introduction.html: ../README
 	asciidoc -b xhtml11 -d article -f asciidoc.conf -o $@ $<
 
-%.html : %.txt
+%.1.html : %.1.txt
 	asciidoc -b xhtml11 -d manpage -f asciidoc.conf $<
 
-%.1 %.7 : %.xml
-	xmlto man $<
+%.7.html : %.7.txt
+	asciidoc -b xhtml11 -d manpage -f asciidoc.conf $<
 
-%.xml : %.txt
+%.html : %.txt
+	asciidoc -b xhtml11 -d article -f asciidoc.conf -o $@ $<
+
+%.1.xml : %.1.txt
 	asciidoc -b docbook -d manpage -f asciidoc.conf $<
 
-$(PACKAGE).txt : make-$(PACKAGE)-asciidoc
+%.7.xml : %.7.txt
+	asciidoc -b docbook -d manpage -f asciidoc.conf $<
+
+%.xml : %.txt
+	asciidoc -b docbook -d article -f asciidoc.conf $<
+
+%.1 : %.1.xml
+	xmlto man $<
+
+%.7 : %.7.xml
+	xmlto man $<
+
+$(PACKAGE).7.txt : make-$(PACKAGE)-asciidoc
 	./make-$(PACKAGE)-asciidoc > $@
 
 # It seems that cg%.txt won't match this so use an explicit rule
-cg.txt : ../cg make-cg-asciidoc
+cg.1.txt : ../cg make-cg-asciidoc
 	CGPACKAGE=$(PACKAGE) ./make-cg-asciidoc $< > $@
 
-cg-%.txt : ../cg-% make-cg-asciidoc
+cg-%.1.txt : ../cg-% make-cg-asciidoc
 	CGPACKAGE=$(PACKAGE) ./make-cg-asciidoc $< > $@

-- 
Jonas Fonseca

^ permalink raw reply related

* [PATCH 1/4] Simplify wildcards for match files to be ignored
From: Jonas Fonseca @ 2006-03-10 14:43 UTC (permalink / raw)
  To: Petr Baudis; +Cc: git
In-Reply-To: <20060310144106.GA7920@diku.dk>

Signed-off-by: Jonas Fonseca <fonseca@diku.dk>

---

 Documentation/Makefile |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/Documentation/Makefile b/Documentation/Makefile
index 3aad2fb..661c259 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -1,4 +1,4 @@
-CG_IGNORE=$(wildcard ../cg-X* ../cg-*.orig ../cg-*.rej ../cg-*.in)
+CG_IGNORE=$(wildcard ../cg-X* ../cg-*.*)
 CG_SRC=$(filter-out $(CG_IGNORE), $(wildcard ../cg*))
 
 PACKAGE=cogito

-- 
Jonas Fonseca

^ permalink raw reply related

* Cogito: Cleanup documentation building and add quick reference
From: Jonas Fonseca @ 2006-03-10 14:41 UTC (permalink / raw)
  To: Petr Baudis; +Cc: git

Hi,

Here are a few patches that makes it possible to build documentation as
PDF using docbook2pdf (chosen because xmlto doesn't seem to be able to
generate PDFs).

All the patches leads up to adding a quick reference with often used
Cogito commands and associated option. It is inspired by svn-ref and the
goal is to have the PDF version under two pages long. The grouping of
commands could need some more comments.

The quick reference can be translated into HTML, PDF and cg-ref(7)
manpage. The last one is achieved by stripping much of the markup from
the 'default' version since manpages cannot have table layout. Note the
HTML and PDF versions are generated as quick-reference.{html,pdf}. We
might want to generate cg-ref.{html,pdf} instead.

-- 
Jonas Fonseca

^ permalink raw reply

* [PATCH] fetch,parse-remote,fmt-merge-msg: refs/remotes/* support
From: Eric Wong @ 2006-03-10 12:19 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7vzmjz5y6o.fsf@assigned-by-dhcp.cox.net>

Note: This replaces the previous patch to fetch and parse-remote.

We can now easily fetch and merge things from heads in the
refs/remotes/ hierarchy in remote repositories.

The refs/remotes/ hierarchy is likely to become the standard for
tracking foreign SCMs, as well as the location of Pull: targets
for non-master heads of newly cloned repositories.

Signed-off-by: Eric Wong <normalperson@yhbt.net>

---

 git-fetch.sh           |    8 +++++++-
 git-fmt-merge-msg.perl |    8 ++++++++
 git-parse-remote.sh    |    8 ++++----
 3 files changed, 19 insertions(+), 5 deletions(-)

6697c83da96b26739c3fe33c8526da6124cea909
diff --git a/git-fetch.sh b/git-fetch.sh
index 0346d4a..11e9a9d 100755
--- a/git-fetch.sh
+++ b/git-fetch.sh
@@ -94,6 +94,9 @@ append_fetch_head () {
     # remote-nick is the URL given on the command line (or a shorthand)
     # remote-name is the $GIT_DIR relative refs/ path we computed
     # for this refspec.
+
+    # the $note_ variable will be fed to git-fmt-merge-msg for further
+    # processing.
     case "$remote_name_" in
     HEAD)
 	note_= ;;
@@ -103,6 +106,9 @@ append_fetch_head () {
     refs/tags/*)
 	note_="$(expr "$remote_name_" : 'refs/tags/\(.*\)')"
 	note_="tag '$note_' of " ;;
+    refs/remotes/*)
+	note_="$(expr "$remote_name_" : 'refs/\(remotes/.*\)')"
+	note_="remote branch '$note_' of " ;;
     *)
 	note_="$remote_name of " ;;
     esac
@@ -150,7 +156,7 @@ fast_forward_local () {
 	git-update-ref "$1" "$2" 
 	;;
 
-    refs/heads/*)
+    refs/heads/* | refs/remotes/*)
 	# $1 is the ref being updated.
 	# $2 is the new value for the ref.
 	local=$(git-rev-parse --verify "$1^0" 2>/dev/null)
diff --git a/git-fmt-merge-msg.perl b/git-fmt-merge-msg.perl
index afe80e6..5986e54 100755
--- a/git-fmt-merge-msg.perl
+++ b/git-fmt-merge-msg.perl
@@ -75,6 +75,7 @@ while (<>) {
 		$src{$src} = {
 			BRANCH => [],
 			TAG => [],
+			R_BRANCH => [],
 			GENERIC => [],
 			# &1 == has HEAD.
 			# &2 == has others.
@@ -91,6 +92,11 @@ while (<>) {
 		push @{$src{$src}{TAG}}, $1;
 		$src{$src}{HEAD_STATUS} |= 2;
 	}
+	elsif (/^remote branch (.*)$/) {
+		$origin = $1;
+		push @{$src{$src}{R_BRANCH}}, $1;
+		$src{$src}{HEAD_STATUS} |= 2;
+	}
 	elsif (/^HEAD$/) {
 		$origin = $src;
 		$src{$src}{HEAD_STATUS} |= 1;
@@ -123,6 +129,8 @@ for my $src (@src) {
 	}
 	push @this, andjoin("branch ", "branches ",
 			   $src{$src}{BRANCH});
+	push @this, andjoin("remote branch ", "remote branches ",
+			   $src{$src}{R_BRANCH});
 	push @this, andjoin("tag ", "tags ",
 			   $src{$src}{TAG});
 	push @this, andjoin("commit ", "commits ",
diff --git a/git-parse-remote.sh b/git-parse-remote.sh
index 5f158c6..63f2281 100755
--- a/git-parse-remote.sh
+++ b/git-parse-remote.sh
@@ -86,14 +86,14 @@ canon_refs_list_for_fetch () {
 		local=$(expr "$ref" : '[^:]*:\(.*\)')
 		case "$remote" in
 		'') remote=HEAD ;;
-		refs/heads/* | refs/tags/*) ;;
-		heads/* | tags/* ) remote="refs/$remote" ;;
+		refs/heads/* | refs/tags/* | refs/remotes/*) ;;
+		heads/* | tags/* | remotes/* ) remote="refs/$remote" ;;
 		*) remote="refs/heads/$remote" ;;
 		esac
 		case "$local" in
 		'') local= ;;
-		refs/heads/* | refs/tags/*) ;;
-		heads/* | tags/* ) local="refs/$local" ;;
+		refs/heads/* | refs/tags/* | refs/remotes/*) ;;
+		heads/* | tags/* | remotes/* ) local="refs/$local" ;;
 		*) local="refs/heads/$local" ;;
 		esac
 
-- 
1.2.4.gbe2d

^ permalink raw reply related

* Re: What's in git.git
From: Martin Langhoff @ 2006-03-10 11:59 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Fredrik Kuivinen, Junio C Hamano, git
In-Reply-To: <Pine.LNX.4.63.0603101215100.25810@wbgn013.biozentrum.uni-wuerzburg.de>

On 3/11/06, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:
> The history is linearized, and the commits are ordered accordingly, then
> to be passed to git-annotate/-blame.

Exactly.

If a process has already done the costly git-rev-list for other
purposes (say, grab logentries of the relevant commits), and wants to
also run annotate/blame, it should be able to reuse it cheaply, by
passing -S filename. Possibly an IDE (or gitk/qgit) would want to do
this.

Now, what I use it for in git-cvsserver is to "flatten" merges. CVS
clients don't really understand that we know about parallel history,
so every time we have a merge the view that the CVS client gets is of
a "merge commit" with a merge summary. And I sweep the merged commits
under the carpet.

(there's some arbitrary nondeterministic magic in how I pick what side
to track and what side to merge. let's not think about that too much.
but I just want git-blame to see a somewhat simplified git-rev-list).

does that help?

cheers,


m

^ permalink raw reply

* Re: What's in git.git
From: Johannes Schindelin @ 2006-03-10 11:17 UTC (permalink / raw)
  To: Fredrik Kuivinen; +Cc: Martin Langhoff, Junio C Hamano, git
In-Reply-To: <20060310104443.GA4491@c165.ib.student.liu.se>

Hi,

On Fri, 10 Mar 2006, Fredrik Kuivinen wrote:

> On Mon, Mar 06, 2006 at 10:05:41PM +1300, Martin Langhoff wrote:
> > On 3/6/06, Junio C Hamano <junkio@cox.net> wrote:
> > > - The deathmatch between annotate/blame (Ryan Anderson, Fredrik
> > >   Kuivinen, me cheerleading)
> > 
> > Add fuel to the fire  ;-) Can git-blame take cached git-rev-list
> > output like annotate does with -S?
> > 
> 
> Currently it cannot do that. How is that option used?

The history is linearized, and the commits are ordered accordingly, then 
to be passed to git-annotate/-blame.

> If you want to make annotate/blame faster for certain files you might as 
> well cache the output of annotate/blame instead of the git-rev-list 
> output, no?
> 
> What am I missing?

Two things:

- the history is growing, and
- it would be inefficient/error-prone to save the annotates for files 

Hth,
Dscho
  

^ permalink raw reply

* Re: bug?: stgit creates (unneccessary?) conflicts when pulling
From: Catalin Marinas @ 2006-03-10 11:13 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Shawn Pearce
In-Reply-To: <7vslpr2ojz.fsf@assigned-by-dhcp.cox.net>

On 09/03/06, Junio C Hamano <junkio@cox.net> wrote:
> "Catalin Marinas" <catalin.marinas@gmail.com> writes:
>
> > Trying to implement this, I've just noticed that git-read-tree has a
> > --aggressive option which takes care of the file removals. Adding this
> > option lowered the pushing time in StGIT from ~2 min to under 2
> > seconds (merges between 2.6.14 and the latest kernel). There's
> > probably no need to deal with file removals in pg--merge-all anymore.
>
> Yup, it was originally done to improve the performance of
> resolve merge strategy, but I am glad somebody else has found
> use for it.

Actually, I asked for it about 6 months ago:

http://marc.theaimsgroup.com/?l=git&m=112677889118711&w=2

and I got the reply from you :-):

http://marc.theaimsgroup.com/?l=git&m=112690084826630&w=2

Anyway, it's good we have it, it saved me some time with implementing
Shawn's merging algorithm.

--
Catalin

^ permalink raw reply

* Re: git-rev-list bug?
From: Catalin Marinas @ 2006-03-10 11:01 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Linus Torvalds, git
In-Reply-To: <7vslpqy4u7.fsf@assigned-by-dhcp.cox.net>

Junio C Hamano <junkio@cox.net> wrote:
> Junio C Hamano <junkio@cox.net> writes:
>
>> It however has a side effect -- uninteresting commits were never
>> parsed here, but now they get parsed.  I am not sure if there
>> are correctness implications...
>
> Actually there is.  If a merge with an uninteresting side branch
> was the only thing that brought changes to paths we are
> interested in, we do not want TREE_SAME logic to remove other
> parents (i.e. the branches we are interested in) from the merge
> commit.  
>
> So we would need a combination of both, something like this?

I can confirm that it "stg patches" works fine with this patch for
git-rev-list.

Thanks.

-- 
Catalin

^ permalink raw reply

* Re: What's in git.git
From: Fredrik Kuivinen @ 2006-03-10 10:44 UTC (permalink / raw)
  To: Martin Langhoff; +Cc: Junio C Hamano, git
In-Reply-To: <46a038f90603060105m29595745ke64d4a623506c0b0@mail.gmail.com>

On Mon, Mar 06, 2006 at 10:05:41PM +1300, Martin Langhoff wrote:
> On 3/6/06, Junio C Hamano <junkio@cox.net> wrote:
> > - The deathmatch between annotate/blame (Ryan Anderson, Fredrik
> >   Kuivinen, me cheerleading)
> 
> Add fuel to the fire  ;-) Can git-blame take cached git-rev-list
> output like annotate does with -S?
> 

Currently it cannot do that. How is that option used? If you want to
make annotate/blame faster for certain files you might as well cache
the output of annotate/blame instead of the git-rev-list output, no?

What am I missing?

- Fredrik

^ permalink raw reply

* Re: git-rev-list bug?
From: Junio C Hamano @ 2006-03-10 10:25 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git, Catalin Marinas
In-Reply-To: <7v4q26zklx.fsf@assigned-by-dhcp.cox.net>

Junio C Hamano <junkio@cox.net> writes:

> It however has a side effect -- uninteresting commits were never
> parsed here, but now they get parsed.  I am not sure if there
> are correctness implications...

Actually there is.  If a merge with an uninteresting side branch
was the only thing that brought changes to paths we are
interested in, we do not want TREE_SAME logic to remove other
parents (i.e. the branches we are interested in) from the merge
commit.  

So we would need a combination of both, something like this?

---
diff --git a/revision.c b/revision.c
index 713f27e..c8d93ff 100644
--- a/revision.c
+++ b/revision.c
@@ -282,6 +282,7 @@ static int same_tree_as_empty(struct tre
 static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
 {
 	struct commit_list **pp, *parent;
+	int tree_changed = 0;
 
 	if (!commit->tree)
 		return;
@@ -296,14 +297,19 @@ static void try_to_simplify_commit(struc
 	while ((parent = *pp) != NULL) {
 		struct commit *p = parent->item;
 
-		if (p->object.flags & UNINTERESTING) {
-			pp = &parent->next;
-			continue;
-		}
-
 		parse_commit(p);
 		switch (compare_tree(p->tree, commit->tree)) {
 		case TREE_SAME:
+			if (p->object.flags & UNINTERESTING) {
+				/* Even if a merge with an uninteresting
+				 * side branch brought the entire change
+				 * we are interested in, we do not want
+				 * to lose the other branches of this
+				 * merge, so we just keep going.
+				 */
+				pp = &parent->next;
+				continue;
+			}
 			parent->next = NULL;
 			commit->parents = parent;
 			return;
@@ -315,12 +321,14 @@ static void try_to_simplify_commit(struc
 			}
 		/* fallthrough */
 		case TREE_DIFFERENT:
+			tree_changed = 1;
 			pp = &parent->next;
 			continue;
 		}
 		die("bad tree compare for commit %s", sha1_to_hex(commit->object.sha1));
 	}
-	commit->object.flags |= TREECHANGE;
+	if (tree_changed)
+		commit->object.flags |= TREECHANGE;
 }
 
 static void add_parents_to_list(struct rev_info *revs, struct commit *commit, struct commit_list **list)

^ permalink raw reply related

* Re: git-rev-list bug?
From: Junio C Hamano @ 2006-03-10  9:59 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git, Catalin Marinas
In-Reply-To: <7virqmzlhb.fsf@assigned-by-dhcp.cox.net>

Junio C Hamano <junkio@cox.net> writes:

> I am wondering why try_to_simplify_commit() skips parents marked
> with UNINTERESTING.  I think this is causing a problem Catalin
> found with rev-list.
> ...
> The attached patch seems to fix it (without losing the logic to
> omit tree comparison with UNINTERESTING parent, which I do not
> quite understand).

Actually the previous patch is not right either.  If I ask "what
changes path B between commit#1..commit#4", it would still omit
commit#2.

It should not matter if the parent is uninteresting while
checking if a commit touches the specified path.  The attached
patch which replaces the previous botched one does exactly that.

It however has a side effect -- uninteresting commits were never
parsed here, but now they get parsed.  I am not sure if there
are correctness implications...

---
diff --git a/revision.c b/revision.c
index 713f27e..9d0934a 100644
--- a/revision.c
+++ b/revision.c
@@ -296,11 +296,6 @@ static void try_to_simplify_commit(struc
 	while ((parent = *pp) != NULL) {
 		struct commit *p = parent->item;
 
-		if (p->object.flags & UNINTERESTING) {
-			pp = &parent->next;
-			continue;
-		}
-
 		parse_commit(p);
 		switch (compare_tree(p->tree, commit->tree)) {
 		case TREE_SAME:

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox