{"thread":{"id":"2846","subject":"How to clone-pack the HEAD?","startedAt":"2005-12-15T00:44:40Z","lastAt":"2005-12-18T00:53:06Z","messageCount":10,"participants":["Petr Baudis","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"13655","messageId":"20051215004440.GM22159@pasky.or.cz","threadId":"2846","inReplyTo":null,"subject":"How to clone-pack the HEAD?","fromName":"Petr Baudis","fromEmail":"pasky@ucw.cz","sentAt":"2005-12-15T00:44:40Z","receivedAt":"2005-12-15T00:44:40Z","isPatch":false,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"  Hello,\n\n  I'd like to make cg-clone use git-clone-pack instead of git-fetch-pack\nso that it gets actually usable on large repositories, but I'm hitting\nproblems:\n\n  (i) git-clone-pack url HEAD doesn't work\n\n\tIf .git/HEAD already exists, it will panick because of the\n\twrite_one_ref()'s O_CREAT|O_EXCL. If .git/HEAD doesn't exist,\n\tgit-clone-pack refuses to do anything since it doesn't run\n\twith valid GIT repository.\n\n  (ii) git-clone-pack has hardcoded assumptions about refs/heads/master\n\n\tThe problem is, git-clone-pack doesn't seem to care about what\n\tref does HEAD point to at the remote side, it just starts to\n\tpanic and do weird things if it isn't master, which seems\n\t\"really really wrong\". Also, because git-clone-pack ... HEAD\n\tdoesn't work, I think I have no way to clone the actual HEAD\n\tref of the remote repository.\n\n  Overally, I think what I really need is git-fetch-pack (with it\noutputting the ref info which I can write on my own, DTRT'ing from\nthe Cogito POV), just with the option not to unpack the pack.\n\n  I'd be very happy if fixing this would be possible before 1.0 so that\nI can fix Cogito's fetching over git and ssh ASAP - git-clone-pack's\narchitecture seems to be way too much hardcoded to carry over head names\nto the cloned repository (which is fine for the GIT porcelainish, but\nnot for Cogito philosophy).\n\n  PS: Sorry if this mail is a bit incoherent - I'm already falling\nasleep over the keyboard, but I don't want to see GIT 1.0 fly by during\nthe night. ;-) BTW, Junio, do you have any timeline (more precise than\n\"in the coming week(s)\") for the release, or are you just waiting for\n\"n days without big problem\" or something like that?\n\n  Thanks,\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nStuff: http://pasky.or.cz/\nVI has two modes: the one in which it beeps and the one in which\nit doesn't.\n"},{"id":"13657","messageId":"7vfyovtaub.fsf@assigned-by-dhcp.cox.net","threadId":"2846","inReplyTo":"20051215004440.GM22159@pasky.or.cz","subject":"Re: How to clone-pack the HEAD?","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-12-15T01:20:28Z","receivedAt":"2005-12-15T01:20:28Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Petr Baudis <pasky@ucw.cz> writes:\n\n>   (i) git-clone-pack url HEAD doesn't work\n\n\"clone-pack url branchname\" might work, but the thing is, nobody\nuses clone-pack with explicit heads arguments so if HEAD does\nnot work I am not surprised at all.\n\n>   (ii) git-clone-pack has hardcoded assumptions about refs/heads/master\n\nI've read that part of the code twice in the past, but my\nrecollection is it tries hard to \"guess\" where HEAD points at\n(because the remote side does not tell us, other than which\ncommit object HEAD points at).  When more than two branch heads\npoint at the same commit as HEAD records, it gives preference to\n\"master\" branch while guessing, but otherwise there is nothing\nspecial about the \"master\" branch.\n\nThe problem is, clone-pack is about cloning and not fetching.  I\nam not claiming it is the right design decision --- after all,\nit was the oldest of the git native protocol driver suite ---\nbut just stating where it stands with all the history behind its\n(and git-fetch-pack's) evolution.\n\nI think extending git-fetch-pack to optionally keep things\npacked would be somewhat painful but the right approach.  Less\npainful and readily doable would be to run clone-pack as is, and\nreorganize the result of \"copy of the remote\" yourself.  That\nwould be a straightforward thing to do if you are using it for\nthe initial cloning.\n"},{"id":"13659","messageId":"20051215013201.GD10680@pasky.or.cz","threadId":"2846","inReplyTo":"7vfyovtaub.fsf@assigned-by-dhcp.cox.net","subject":"Re: How to clone-pack the HEAD?","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2005-12-15T01:32:01Z","receivedAt":"2005-12-15T01:32:01Z","isPatch":false,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"Dear diary, on Thu, Dec 15, 2005 at 02:20:28AM CET, I got a letter\nwhere Junio C Hamano <junkio@cox.net> said that...\n> Petr Baudis <pasky@ucw.cz> writes:\n> \n> >   (i) git-clone-pack url HEAD doesn't work\n> \n> \"clone-pack url branchname\" might work, but the thing is, nobody\n> uses clone-pack with explicit heads arguments so if HEAD does\n> not work I am not surprised at all.\n..snip..\n> I think extending git-fetch-pack to optionally keep things\n> packed would be somewhat painful but the right approach.  Less\n> painful and readily doable would be to run clone-pack as is, and\n> reorganize the result of \"copy of the remote\" yourself.  That\n> would be a straightforward thing to do if you are using it for\n> the initial cloning.\n\nExcept that I cannot do the guessing git-clone-pack does (without\nfetching all the branches) - so I guess I'll make a patch tomorrow which\nfixes git-clone-pack ... HEAD (probably by checking in write_one_ref()\nwhether it is looking at a symlink and following it first if that's the\ncase) and then in Cogito do\n\n\tgit-symbolic-ref HEAD refs/heads/origin\n\nbefore git-clone-pack (and repoint HEAD back after it's over). That\nshould do exactly what I need it to, I think.\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nStuff: http://pasky.or.cz/\nVI has two modes: the one in which it beeps and the one in which\nit doesn't.\n"},{"id":"13661","messageId":"7vpsnzrv43.fsf@assigned-by-dhcp.cox.net","threadId":"2846","inReplyTo":"20051215013201.GD10680@pasky.or.cz","subject":"Re: How to clone-pack the HEAD?","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-12-15T01:45:32Z","receivedAt":"2005-12-15T01:45:32Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Petr Baudis <pasky@suse.cz> writes:\n\n> Except that I cannot do the guessing git-clone-pack does (without\n> fetching all the branches)\n\nExactly my point.  If you are not getting all the branches, you\nare not cloning but doing something else.\n\nExtending git-fetch-pack would be the right approach if that is\nwhat you are trying to do.\n"},{"id":"13662","messageId":"7vlkynrurh.fsf@assigned-by-dhcp.cox.net","threadId":"2846","inReplyTo":"7vpsnzrv43.fsf@assigned-by-dhcp.cox.net","subject":"Re: How to clone-pack the HEAD?","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-12-15T01:53:06Z","receivedAt":"2005-12-15T01:53:06Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <junkio@cox.net> writes:\n\n> Petr Baudis <pasky@suse.cz> writes:\n>\n>> Except that I cannot do the guessing git-clone-pack does (without\n>> fetching all the branches)\n>\n> Exactly my point.  If you are not getting all the branches, you\n> are not cloning but doing something else.\n\nNot really.  I take this back.  What you want to do I did not\nunderstand well enough.\n\nHEAD is kinda special.  A hack I can think of is to do ls-remote\nfirst and do the guess clone-pack does for full clone case, and\nthen give a specific branch name to clone.  That might work.\n"},{"id":"13663","messageId":"20051215015944.GE10680@pasky.or.cz","threadId":"2846","inReplyTo":"7vpsnzrv43.fsf@assigned-by-dhcp.cox.net","subject":"Re: How to clone-pack the HEAD?","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2005-12-15T01:59:44Z","receivedAt":"2005-12-15T01:59:44Z","isPatch":false,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"Dear diary, on Thu, Dec 15, 2005 at 02:45:32AM CET, I got a letter\nwhere Junio C Hamano <junkio@cox.net> said that...\n> Petr Baudis <pasky@suse.cz> writes:\n> \n> > Except that I cannot do the guessing git-clone-pack does (without\n> > fetching all the branches)\n> \n> Exactly my point.  If you are not getting all the branches, you\n> are not cloning but doing something else.\n\nAh, play with the words. Sure I'm cloning - however I'm not cloning\na repository but a branch. In Cogito world, that's the only thing that\nmakes sense to clone, in GIT world it's more complicated (you don't\nalways clone the whole repository there either, since git-clone-pack\nlets you narrow down the refs).\n\n> Extending git-fetch-pack would be the right approach if that is\n> what you are trying to do.\n\nI'll then try to extend git-fetch-pack instead. I'll send some fix for\ngit-clone-pack anyway, though. ;-)\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nStuff: http://pasky.or.cz/\nVI has two modes: the one in which it beeps and the one in which\nit doesn't.\n"},{"id":"13666","messageId":"7vpsnzq66x.fsf@assigned-by-dhcp.cox.net","threadId":"2846","inReplyTo":"7vlkynrurh.fsf@assigned-by-dhcp.cox.net","subject":"Re: How to clone-pack the HEAD?","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-12-15T05:29:10Z","receivedAt":"2005-12-15T05:29:10Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <junkio@cox.net> writes:\n\n> Not really.  I take this back.  What you want to do I did not\n> understand well enough.\n>\n> HEAD is kinda special.  A hack I can think of is to do ls-remote\n> first and do the guess clone-pack does for full clone case, and\n> then give a specific branch name to clone.  That might work.\n\n... and another way would be to do this; I'll put this (with\nfixes if there is some needed) in \"master\" tonight.\n\nAlso I might want to give --keep option to fetch-pack as well;\nclone-pack has some static functions that we can extract out to\na common file to link to both.\n\n-- >8 --\nSubject: [PATCH] clone-pack: make it usable for partial branch cloning.\n\nclone-pack had some logic to accept subset of remote refs from\nthe command line and clone from there.  However, it was never\nused in practice and its problems were not found out so far.\n\nThis commit changes the command to output the object names of\nrefs to the standard output instead of making a clone of the\nremote repository when explicit <head> parameters are given; the\noutput format is the same as fetch-pack.\n\nThe traditional behaviour of cloning the whole repository by\ngiving no explicit <head> parameters stays the same.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n\n---\n\n Documentation/git-clone-pack.txt |    6 +++++-\n clone-pack.c                     |   13 +++++++++++--\n 2 files changed, 16 insertions(+), 3 deletions(-)\n\n31ec6abf887ec95642cbe82fe61076e975494ab0\ndiff --git a/Documentation/git-clone-pack.txt b/Documentation/git-clone-pack.txt\nindex cfc7b62..39906fc 100644\n--- a/Documentation/git-clone-pack.txt\n+++ b/Documentation/git-clone-pack.txt\n@@ -43,7 +43,11 @@ OPTIONS\n \tThe heads to update.  This is relative to $GIT_DIR\n \t(e.g. \"HEAD\", \"refs/heads/master\").  When unspecified,\n \tall heads are updated to match the remote repository.\n-\n++\n+Usually all the refs from existing repository are stored\n+under the same name in the new repository.  Giving explicit\n+<head> arguments instead writes the object names and refs to\n+the standard output, just like get-fetch-pack does.\n \n Author\n ------\ndiff --git a/clone-pack.c b/clone-pack.c\nindex a99a95c..b5ce5d3 100644\n--- a/clone-pack.c\n+++ b/clone-pack.c\n@@ -259,8 +259,17 @@ static int clone_pack(int fd[2], int nr_\n \n \tstatus = clone_without_unpack(fd);\n \n-\tif (!status)\n-\t\twrite_refs(refs);\n+\tif (!status) {\n+\t\tif (nr_match == 0)\n+\t\t\twrite_refs(refs);\n+\t\telse\n+\t\t\twhile (refs) {\n+\t\t\t\tprintf(\"%s %s\\n\",\n+\t\t\t\t       sha1_to_hex(refs->old_sha1),\n+\t\t\t\t       refs->name);\n+\t\t\t\trefs = refs->next;\n+\t\t\t}\n+\t}\n \treturn status;\n }\n \n-- \n0.99.9n\n"},{"id":"13672","messageId":"7vfyouricc.fsf@assigned-by-dhcp.cox.net","threadId":"2846","inReplyTo":"7vpsnzq66x.fsf@assigned-by-dhcp.cox.net","subject":"Re: How to clone-pack the HEAD?","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-12-15T06:21:23Z","receivedAt":"2005-12-15T06:21:23Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <junkio@cox.net> writes:\n\n> Also I might want to give --keep option to fetch-pack as well;\n> clone-pack has some static functions that we can extract out to\n> a common file to link to both.\n\nAnd this is the second installment, on top of the previous one.\nI am a bit reluctant about this one only because of its size,\nbut I suspect it may be much easier to use for your purpose.\n\nI'll keep this in the proposed updates branch for now (the other\none goes to master tonight), so if you like this one, please\nholler, test out and ack.\n\n-- >8 --\nSubject: [PATCH] fetch-pack: -k option to keep downloaded pack.\n\nSplit out the functions that deal with the socketpair after\nfinishing git protocol handshake to receive the packed data into\na separate file, and use it in fetch-pack to keep/explode the\nreceived pack data.  We earlier had something like that on\nclone-pack side once, but the list discussion resulted in the\ndecision that it makes sense to always keep the pack for\nclone-pack, so unpacking option is not enabled on the clone-pack\nside, but we later still could do so easily if we wanted to with\nthis change.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n\n---\n\n Documentation/git-fetch-pack.txt |    7 +-\n Makefile                         |    1 \n cache.h                          |    5 +\n clone-pack.c                     |  136 ------------------------------\n fetch-clone.c                    |  172 ++++++++++++++++++++++++++++++++++++++\n fetch-pack.c                     |   58 +++++--------\n 6 files changed, 206 insertions(+), 173 deletions(-)\n create mode 100644 fetch-clone.c\n\n32cf3b780b1cf77cf2fa7042d31dfe969ad0b9b9\ndiff --git a/Documentation/git-fetch-pack.txt b/Documentation/git-fetch-pack.txt\nindex ea6faab..b507e9b 100644\n--- a/Documentation/git-fetch-pack.txt\n+++ b/Documentation/git-fetch-pack.txt\n@@ -8,7 +8,7 @@ git-fetch-pack - Receive missing objects\n \n SYNOPSIS\n --------\n-git-fetch-pack [-q] [--exec=<git-upload-pack>] [<host>:]<directory> [<refs>...]\n+git-fetch-pack [-q] [-k] [--exec=<git-upload-pack>] [<host>:]<directory> [<refs>...]\n \n DESCRIPTION\n -----------\n@@ -29,6 +29,11 @@ OPTIONS\n \tPass '-q' flag to 'git-unpack-objects'; this makes the\n \tcloning process less verbose.\n \n+-k::\n+\tDo not invoke 'git-unpack-objects' on received data, but\n+\tcreate a single packfile out of it instead, and store it\n+\tin the object database.\n+\n --exec=<git-upload-pack>::\n \tUse this to specify the path to 'git-upload-pack' on the\n \tremote side, if is not found on your $PATH.\ndiff --git a/Makefile b/Makefile\nindex d494ad4..9fd2ed3 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -175,6 +175,7 @@ LIB_OBJS = \\\n \tquote.o read-cache.o refs.o run-command.o \\\n \tserver-info.o setup.o sha1_file.o sha1_name.o strbuf.o \\\n \ttag.o tree.o usage.o config.o environment.o ctype.o copy.o \\\n+\tfetch-clone.o \\\n \t$(DIFF_OBJS)\n \n LIBS = $(LIB_FILE)\ndiff --git a/cache.h b/cache.h\nindex c78d8ae..cb87bec 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -338,4 +338,9 @@ extern char git_default_name[MAX_GITNAME\n extern char git_commit_encoding[MAX_ENCODING_LENGTH];\n \n extern int copy_fd(int ifd, int ofd);\n+\n+/* Finish off pack transfer receiving end */\n+extern int receive_unpack_pack(int fd[2], const char *me, int quiet);\n+extern int receive_keep_pack(int fd[2], const char *me);\n+\n #endif /* CACHE_H */\ndiff --git a/clone-pack.c b/clone-pack.c\nindex b5ce5d3..03dbc2e 100644\n--- a/clone-pack.c\n+++ b/clone-pack.c\n@@ -1,7 +1,6 @@\n #include \"cache.h\"\n #include \"refs.h\"\n #include \"pkt-line.h\"\n-#include <sys/wait.h>\n \n static const char clone_pack_usage[] =\n \"git-clone-pack [--exec=<git-upload-pack>] [<host>:]<directory> [<heads>]*\";\n@@ -112,139 +111,6 @@ static void write_refs(struct ref *ref)\n \tfree(head_path);\n }\n \n-static int finish_pack(const char *pack_tmp_name)\n-{\n-\tint pipe_fd[2];\n-\tpid_t pid;\n-\tchar idx[PATH_MAX];\n-\tchar final[PATH_MAX];\n-\tchar hash[41];\n-\tunsigned char sha1[20];\n-\tchar *cp;\n-\tint err = 0;\n-\n-\tif (pipe(pipe_fd) < 0)\n-\t\tdie(\"git-clone-pack: unable to set up pipe\");\n-\n-\tstrcpy(idx, pack_tmp_name); /* \".git/objects/pack-XXXXXX\" */\n-\tcp = strrchr(idx, '/');\n-\tmemcpy(cp, \"/pidx\", 5);\n-\n-\tpid = fork();\n-\tif (pid < 0)\n-\t\tdie(\"git-clone-pack: unable to fork off git-index-pack\");\n-\tif (!pid) {\n-\t\tclose(0);\n-\t\tdup2(pipe_fd[1], 1);\n-\t\tclose(pipe_fd[0]);\n-\t\tclose(pipe_fd[1]);\n-\t\texeclp(\"git-index-pack\",\"git-index-pack\",\n-\t\t       \"-o\", idx, pack_tmp_name, NULL);\n-\t\terror(\"cannot exec git-index-pack <%s> <%s>\",\n-\t\t      idx, pack_tmp_name);\n-\t\texit(1);\n-\t}\n-\tclose(pipe_fd[1]);\n-\tif (read(pipe_fd[0], hash, 40) != 40) {\n-\t\terror(\"git-clone-pack: unable to read from git-index-pack\");\n-\t\terr = 1;\n-\t}\n-\tclose(pipe_fd[0]);\n-\n-\tfor (;;) {\n-\t\tint status, code;\n-\t\tint retval = waitpid(pid, &status, 0);\n-\n-\t\tif (retval < 0) {\n-\t\t\tif (errno == EINTR)\n-\t\t\t\tcontinue;\n-\t\t\terror(\"waitpid failed (%s)\", strerror(retval));\n-\t\t\tgoto error_die;\n-\t\t}\n-\t\tif (WIFSIGNALED(status)) {\n-\t\t\tint sig = WTERMSIG(status);\n-\t\t\terror(\"git-index-pack died of signal %d\", sig);\n-\t\t\tgoto error_die;\n-\t\t}\n-\t\tif (!WIFEXITED(status)) {\n-\t\t\terror(\"git-index-pack died of unnatural causes %d\",\n-\t\t\t      status);\n-\t\t\tgoto error_die;\n-\t\t}\n-\t\tcode = WEXITSTATUS(status);\n-\t\tif (code) {\n-\t\t\terror(\"git-index-pack died with error code %d\", code);\n-\t\t\tgoto error_die;\n-\t\t}\n-\t\tif (err)\n-\t\t\tgoto error_die;\n-\t\tbreak;\n-\t}\n-\thash[40] = 0;\n-\tif (get_sha1_hex(hash, sha1)) {\n-\t\terror(\"git-index-pack reported nonsense '%s'\", hash);\n-\t\tgoto error_die;\n-\t}\n-\t/* Now we have pack in pack_tmp_name[], and\n-\t * idx in idx[]; rename them to their final names.\n-\t */\n-\tsnprintf(final, sizeof(final),\n-\t\t \"%s/pack/pack-%s.pack\", get_object_directory(), hash);\n-\tmove_temp_to_file(pack_tmp_name, final);\n-\tchmod(final, 0444);\n-\tsnprintf(final, sizeof(final),\n-\t\t \"%s/pack/pack-%s.idx\", get_object_directory(), hash);\n-\tmove_temp_to_file(idx, final);\n-\tchmod(final, 0444);\n-\treturn 0;\n-\n- error_die:\n-\tunlink(idx);\n-\tunlink(pack_tmp_name);\n-\texit(1);\n-}\n-\n-static int clone_without_unpack(int fd[2])\n-{\n-\tchar tmpfile[PATH_MAX];\n-\tint ofd, ifd;\n-\n-\tifd = fd[0];\n-\tsnprintf(tmpfile, sizeof(tmpfile),\n-\t\t \"%s/pack/tmp-XXXXXX\", get_object_directory());\n-\tofd = mkstemp(tmpfile);\n-\tif (ofd < 0)\n-\t\treturn error(\"unable to create temporary file %s\", tmpfile);\n-\n-\twhile (1) {\n-\t\tchar buf[8192];\n-\t\tssize_t sz, wsz, pos;\n-\t\tsz = read(ifd, buf, sizeof(buf));\n-\t\tif (sz == 0)\n-\t\t\tbreak;\n-\t\tif (sz < 0) {\n-\t\t\terror(\"error reading pack (%s)\", strerror(errno));\n-\t\t\tclose(ofd);\n-\t\t\tunlink(tmpfile);\n-\t\t\treturn -1;\n-\t\t}\n-\t\tpos = 0;\n-\t\twhile (pos < sz) {\n-\t\t\twsz = write(ofd, buf + pos, sz - pos);\n-\t\t\tif (wsz < 0) {\n-\t\t\t\terror(\"error writing pack (%s)\",\n-\t\t\t\t      strerror(errno));\n-\t\t\t\tclose(ofd);\n-\t\t\t\tunlink(tmpfile);\n-\t\t\t\treturn -1;\n-\t\t\t}\n-\t\t\tpos += wsz;\n-\t\t}\n-\t}\n-\tclose(ofd);\n-\treturn finish_pack(tmpfile);\n-}\n-\n static int clone_pack(int fd[2], int nr_match, char **match)\n {\n \tstruct ref *refs;\n@@ -257,7 +123,7 @@ static int clone_pack(int fd[2], int nr_\n \t}\n \tclone_handshake(fd, refs);\n \n-\tstatus = clone_without_unpack(fd);\n+\tstatus = receive_keep_pack(fd, \"git-clone-pack\");\n \n \tif (!status) {\n \t\tif (nr_match == 0)\ndiff --git a/fetch-clone.c b/fetch-clone.c\nnew file mode 100644\nindex 0000000..2b2aa15\n--- /dev/null\n+++ b/fetch-clone.c\n@@ -0,0 +1,172 @@\n+#include \"cache.h\"\n+#include <sys/wait.h>\n+\n+static int finish_pack(const char *pack_tmp_name, const char *me)\n+{\n+\tint pipe_fd[2];\n+\tpid_t pid;\n+\tchar idx[PATH_MAX];\n+\tchar final[PATH_MAX];\n+\tchar hash[41];\n+\tunsigned char sha1[20];\n+\tchar *cp;\n+\tint err = 0;\n+\n+\tif (pipe(pipe_fd) < 0)\n+\t\tdie(\"%s: unable to set up pipe\", me);\n+\n+\tstrcpy(idx, pack_tmp_name); /* \".git/objects/pack-XXXXXX\" */\n+\tcp = strrchr(idx, '/');\n+\tmemcpy(cp, \"/pidx\", 5);\n+\n+\tpid = fork();\n+\tif (pid < 0)\n+\t\tdie(\"git-clone-pack: unable to fork off git-index-pack\");\n+\tif (!pid) {\n+\t\tclose(0);\n+\t\tdup2(pipe_fd[1], 1);\n+\t\tclose(pipe_fd[0]);\n+\t\tclose(pipe_fd[1]);\n+\t\texeclp(\"git-index-pack\",\"git-index-pack\",\n+\t\t       \"-o\", idx, pack_tmp_name, NULL);\n+\t\terror(\"cannot exec git-index-pack <%s> <%s>\",\n+\t\t      idx, pack_tmp_name);\n+\t\texit(1);\n+\t}\n+\tclose(pipe_fd[1]);\n+\tif (read(pipe_fd[0], hash, 40) != 40) {\n+\t\terror(\"%s: unable to read from git-index-pack\", me);\n+\t\terr = 1;\n+\t}\n+\tclose(pipe_fd[0]);\n+\n+\tfor (;;) {\n+\t\tint status, code;\n+\t\tint retval = waitpid(pid, &status, 0);\n+\n+\t\tif (retval < 0) {\n+\t\t\tif (errno == EINTR)\n+\t\t\t\tcontinue;\n+\t\t\terror(\"waitpid failed (%s)\", strerror(retval));\n+\t\t\tgoto error_die;\n+\t\t}\n+\t\tif (WIFSIGNALED(status)) {\n+\t\t\tint sig = WTERMSIG(status);\n+\t\t\terror(\"git-index-pack died of signal %d\", sig);\n+\t\t\tgoto error_die;\n+\t\t}\n+\t\tif (!WIFEXITED(status)) {\n+\t\t\terror(\"git-index-pack died of unnatural causes %d\",\n+\t\t\t      status);\n+\t\t\tgoto error_die;\n+\t\t}\n+\t\tcode = WEXITSTATUS(status);\n+\t\tif (code) {\n+\t\t\terror(\"git-index-pack died with error code %d\", code);\n+\t\t\tgoto error_die;\n+\t\t}\n+\t\tif (err)\n+\t\t\tgoto error_die;\n+\t\tbreak;\n+\t}\n+\thash[40] = 0;\n+\tif (get_sha1_hex(hash, sha1)) {\n+\t\terror(\"git-index-pack reported nonsense '%s'\", hash);\n+\t\tgoto error_die;\n+\t}\n+\t/* Now we have pack in pack_tmp_name[], and\n+\t * idx in idx[]; rename them to their final names.\n+\t */\n+\tsnprintf(final, sizeof(final),\n+\t\t \"%s/pack/pack-%s.pack\", get_object_directory(), hash);\n+\tmove_temp_to_file(pack_tmp_name, final);\n+\tchmod(final, 0444);\n+\tsnprintf(final, sizeof(final),\n+\t\t \"%s/pack/pack-%s.idx\", get_object_directory(), hash);\n+\tmove_temp_to_file(idx, final);\n+\tchmod(final, 0444);\n+\treturn 0;\n+\n+ error_die:\n+\tunlink(idx);\n+\tunlink(pack_tmp_name);\n+\texit(1);\n+}\n+\n+int receive_unpack_pack(int fd[2], const char *me, int quiet)\n+{\n+\tint status;\n+\tpid_t pid;\n+\n+\tpid = fork();\n+\tif (pid < 0)\n+\t\tdie(\"%s: unable to fork off git-unpack-objects\", me);\n+\tif (!pid) {\n+\t\tdup2(fd[0], 0);\n+\t\tclose(fd[0]);\n+\t\tclose(fd[1]);\n+\t\texeclp(\"git-unpack-objects\", \"git-unpack-objects\",\n+\t\t       quiet ? \"-q\" : NULL, NULL);\n+\t\tdie(\"git-unpack-objects exec failed\");\n+\t}\n+\tclose(fd[0]);\n+\tclose(fd[1]);\n+\twhile (waitpid(pid, &status, 0) < 0) {\n+\t\tif (errno != EINTR)\n+\t\t\tdie(\"waiting for git-unpack-objects: %s\",\n+\t\t\t    strerror(errno));\n+\t}\n+\tif (WIFEXITED(status)) {\n+\t\tint code = WEXITSTATUS(status);\n+\t\tif (code)\n+\t\t\tdie(\"git-unpack-objects died with error code %d\",\n+\t\t\t    code);\n+\t\treturn 0;\n+\t}\n+\tif (WIFSIGNALED(status)) {\n+\t\tint sig = WTERMSIG(status);\n+\t\tdie(\"git-unpack-objects died of signal %d\", sig);\n+\t}\n+\tdie(\"git-unpack-objects died of unnatural causes %d\", status);\n+}\n+\n+int receive_keep_pack(int fd[2], const char *me)\n+{\n+\tchar tmpfile[PATH_MAX];\n+\tint ofd, ifd;\n+\n+\tifd = fd[0];\n+\tsnprintf(tmpfile, sizeof(tmpfile),\n+\t\t \"%s/pack/tmp-XXXXXX\", get_object_directory());\n+\tofd = mkstemp(tmpfile);\n+\tif (ofd < 0)\n+\t\treturn error(\"unable to create temporary file %s\", tmpfile);\n+\n+\twhile (1) {\n+\t\tchar buf[8192];\n+\t\tssize_t sz, wsz, pos;\n+\t\tsz = read(ifd, buf, sizeof(buf));\n+\t\tif (sz == 0)\n+\t\t\tbreak;\n+\t\tif (sz < 0) {\n+\t\t\terror(\"error reading pack (%s)\", strerror(errno));\n+\t\t\tclose(ofd);\n+\t\t\tunlink(tmpfile);\n+\t\t\treturn -1;\n+\t\t}\n+\t\tpos = 0;\n+\t\twhile (pos < sz) {\n+\t\t\twsz = write(ofd, buf + pos, sz - pos);\n+\t\t\tif (wsz < 0) {\n+\t\t\t\terror(\"error writing pack (%s)\",\n+\t\t\t\t      strerror(errno));\n+\t\t\t\tclose(ofd);\n+\t\t\t\tunlink(tmpfile);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t\tpos += wsz;\n+\t\t}\n+\t}\n+\tclose(ofd);\n+\treturn finish_pack(tmpfile, me);\n+}\ndiff --git a/fetch-pack.c b/fetch-pack.c\nindex 58ba209..2528053 100644\n--- a/fetch-pack.c\n+++ b/fetch-pack.c\n@@ -3,13 +3,12 @@\n #include \"pkt-line.h\"\n #include \"commit.h\"\n #include \"tag.h\"\n-#include <time.h>\n-#include <sys/wait.h>\n \n+static int keep_pack;\n static int quiet;\n static int verbose;\n static const char fetch_pack_usage[] =\n-\"git-fetch-pack [-q] [-v] [--exec=upload-pack] [host:]directory <refs>...\";\n+\"git-fetch-pack [-q] [-v] [-k] [--exec=upload-pack] [host:]directory <refs>...\";\n static const char *exec = \"git-upload-pack\";\n \n #define COMPLETE\t(1U << 0)\n@@ -363,7 +362,6 @@ static int fetch_pack(int fd[2], int nr_\n \tstruct ref *ref;\n \tunsigned char sha1[20];\n \tint status;\n-\tpid_t pid;\n \n \tget_remote_heads(fd[0], &ref, 0, NULL, 0);\n \tif (server_supports(\"multi_ack\")) {\n@@ -381,40 +379,22 @@ static int fetch_pack(int fd[2], int nr_\n \t}\n \tif (find_common(fd, sha1, ref) < 0)\n \t\tfprintf(stderr, \"warning: no common commits\\n\");\n-\tpid = fork();\n-\tif (pid < 0)\n-\t\tdie(\"git-fetch-pack: unable to fork off git-unpack-objects\");\n-\tif (!pid) {\n-\t\tdup2(fd[0], 0);\n-\t\tclose(fd[0]);\n-\t\tclose(fd[1]);\n-\t\texeclp(\"git-unpack-objects\", \"git-unpack-objects\",\n-\t\t       quiet ? \"-q\" : NULL, NULL);\n-\t\tdie(\"git-unpack-objects exec failed\");\n-\t}\n-\tclose(fd[0]);\n-\tclose(fd[1]);\n-\twhile (waitpid(pid, &status, 0) < 0) {\n-\t\tif (errno != EINTR)\n-\t\t\tdie(\"waiting for git-unpack-objects: %s\", strerror(errno));\n-\t}\n-\tif (WIFEXITED(status)) {\n-\t\tint code = WEXITSTATUS(status);\n-\t\tif (code)\n-\t\t\tdie(\"git-unpack-objects died with error code %d\", code);\n-all_done:\n-\t\twhile (ref) {\n-\t\t\tprintf(\"%s %s\\n\",\n-\t\t\t       sha1_to_hex(ref->old_sha1), ref->name);\n-\t\t\tref = ref->next;\n-\t\t}\n-\t\treturn 0;\n-\t}\n-\tif (WIFSIGNALED(status)) {\n-\t\tint sig = WTERMSIG(status);\n-\t\tdie(\"git-unpack-objects died of signal %d\", sig);\n+\n+\tif (keep_pack)\n+\t\tstatus = receive_keep_pack(fd, \"git-fetch-pack\");\n+\telse\n+\t\tstatus = receive_unpack_pack(fd, \"git-fetch-pack\", quiet);\n+\n+\tif (status)\n+\t\tdie(\"git-fetch-pack: fetch failed.\");\n+\n+ all_done:\n+\twhile (ref) {\n+\t\tprintf(\"%s %s\\n\",\n+\t\t       sha1_to_hex(ref->old_sha1), ref->name);\n+\t\tref = ref->next;\n \t}\n-\tdie(\"Sherlock Holmes! git-unpack-objects died of unnatural causes %d!\", status);\n+\treturn 0;\n }\n \n int main(int argc, char **argv)\n@@ -440,6 +420,10 @@ int main(int argc, char **argv)\n \t\t\t\tquiet = 1;\n \t\t\t\tcontinue;\n \t\t\t}\n+\t\t\tif (!strcmp(\"-k\", arg)) {\n+\t\t\t\tkeep_pack = 1;\n+\t\t\t\tcontinue;\n+\t\t\t}\n \t\t\tif (!strcmp(\"-v\", arg)) {\n \t\t\t\tverbose = 1;\n \t\t\t\tcontinue;\n-- \n0.99.9n\n"},{"id":"13771","messageId":"20051218003803.GT22159@pasky.or.cz","threadId":"2846","inReplyTo":"7vpsnzq66x.fsf@assigned-by-dhcp.cox.net","subject":"Re: How to clone-pack the HEAD?","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2005-12-18T00:38:03Z","receivedAt":"2005-12-18T00:38:03Z","isPatch":false,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"Dear diary, on Thu, Dec 15, 2005 at 06:29:10AM CET, I got a letter\nwhere Junio C Hamano <junkio@cox.net> said that...\n> Junio C Hamano <junkio@cox.net> writes:\n> \n> > Not really.  I take this back.  What you want to do I did not\n> > understand well enough.\n> >\n> > HEAD is kinda special.  A hack I can think of is to do ls-remote\n> > first and do the guess clone-pack does for full clone case, and\n> > then give a specific branch name to clone.  That might work.\n> \n> ... and another way would be to do this; I'll put this (with\n> fixes if there is some needed) in \"master\" tonight.\n\nThanks! This makes it work very nicely and exactly the way I want, even\ngiving git-fetch-pack-compatible output so I can seamlessly switch\nbetween the two commands. Very nice!\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nStuff: http://pasky.or.cz/\nVI has two modes: the one in which it beeps and the one in which\nit doesn't.\n"},{"id":"13773","messageId":"20051218005306.GU22159@pasky.or.cz","threadId":"2846","inReplyTo":"7vfyouricc.fsf@assigned-by-dhcp.cox.net","subject":"Re: How to clone-pack the HEAD?","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2005-12-18T00:53:06Z","receivedAt":"2005-12-18T00:53:06Z","isPatch":false,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"Dear diary, on Thu, Dec 15, 2005 at 07:21:23AM CET, I got a letter\nwhere Junio C Hamano <junkio@cox.net> said that...\n> Junio C Hamano <junkio@cox.net> writes:\n> \n> > Also I might want to give --keep option to fetch-pack as well;\n> > clone-pack has some static functions that we can extract out to\n> > a common file to link to both.\n> \n> And this is the second installment, on top of the previous one.\n> I am a bit reluctant about this one only because of its size,\n> but I suspect it may be much easier to use for your purpose.\n> \n> I'll keep this in the proposed updates branch for now (the other\n> one goes to master tonight), so if you like this one, please\n> holler, test out and ack.\n\nWell, I like this one, but you don't need to put this to master just for\nme, I'm perfectly fine with the git-clone-pack fix - both commands are\nnow equally simple for me to use in Cogito. (And both seem to work fine\nafter some basic testing.)\n\nBut you are right that git-clone-pack is basically made obsolete by this\npatch, and I tend to like that fact - that's why I have slight\npreference to this patch anyway, despite its size (and it's mostly\ncommon code being moved around anyway). It's probably too late to remove\ngit-clone-pack altogether, but you might at least deprecate it and print\na warning when it's being ran (or at least please print a warning when\nit's being ran in a repository which is already populated, which is very\nlikely a driver error, and I've actually made it just a minute ago ;).\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nStuff: http://pasky.or.cz/\nVI has two modes: the one in which it beeps and the one in which\nit doesn't.\n"}]}