{"thread":{"id":"10730","subject":"git push mirror mode","startedAt":"2007-11-08T12:11:36Z","lastAt":"2007-11-12T15:25:41Z","messageCount":23,"participants":["Andy Whitcroft","Johannes Schindelin","Andreas Ericsson","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"58864","messageId":"20071108121136.GG9736@shadowen.org","threadId":"10730","inReplyTo":null,"subject":"git push mirror mode","fromName":"Andy Whitcroft","fromEmail":"apw@shadowen.org","sentAt":"2007-11-08T12:11:36Z","receivedAt":"2007-11-08T12:11:36Z","isPatch":false,"sender":{"key":"apw@shadowen.org","avatar":"https://gravatar.com/avatar/d3088262854661a913ef35cc40fedcc270142d4461791142bc1ea0b2a4e2e147?d=mp&s=160"},"body":"Ok, sometime back Junio sent out a proof-of-concept change to\nsend-pack allowing a mirror mode.  That patch seemed to interact\nbadly dropping refs in the .git directorty and I did not have time\nto fix it up.\n\nI've just rebased it to the latest next, and updated my follow up patch\nto make this available as 'git push --mirror <remote>'.  I have only\ntested this lightly.\n\n-apw\n"},{"id":"58866","messageId":"1f94d22f57fd8168c5b5ff555888abdd@pinky","threadId":"10730","inReplyTo":"20071108121136.GG9736@shadowen.org","subject":"[PATCH 1/2] mirror pushing","fromName":"Andy Whitcroft","fromEmail":"apw@shadowen.org","sentAt":null,"receivedAt":"2007-11-08T12:11:57Z","isPatch":true,"sender":{"key":"apw@shadowen.org","avatar":"https://gravatar.com/avatar/d3088262854661a913ef35cc40fedcc270142d4461791142bc1ea0b2a4e2e147?d=mp&s=160"},"body":"\nExisting \"git push --all\" is almost perfect for backing up to\nanother repository, except that \"--all\" only means \"all\nbranches\" in modern git, and it does not delete old branches and\ntags that exist at the back-up repository that you have removed\nfrom your local repository.\n\nThis teaches \"git-send-pack\" a new \"--mirror\" option.  The\ndifference from the \"--all\" option are that (1) it sends all\nrefs, not just branches, and (2) it deletes old refs you no\nlonger have on the local side from the remote side.\n\n[apw@shadowen.org: rebase to next post arguments update]\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Andy Whitcroft <apw@shadowen.org>\n---\n builtin-send-pack.c |   40 ++++++++++++++++++++++++++++------------\n remote.c            |   15 ++++++++++-----\n send-pack.h         |    1 +\n 3 files changed, 39 insertions(+), 17 deletions(-)\ndiff --git a/builtin-send-pack.c b/builtin-send-pack.c\nindex 5a0f5c6..d5ead97 100644\n--- a/builtin-send-pack.c\n+++ b/builtin-send-pack.c\n@@ -8,7 +8,7 @@\n #include \"send-pack.h\"\n \n static const char send_pack_usage[] =\n-\"git-send-pack [--all] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\\n\"\n+\"git-send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\\n\"\n \"  --all and explicit <ref> specification are mutually exclusive.\";\n \n static struct send_pack_args args = {\n@@ -242,7 +242,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest\n \tif (!remote_tail)\n \t\tremote_tail = &remote_refs;\n \tif (match_refs(local_refs, remote_refs, &remote_tail,\n-\t\t       nr_refspec, refspec, args.send_all))\n+\t\t       nr_refspec, refspec, args.send_all | (args.send_mirror << 1)))\n \t\treturn -1;\n \n \tif (!remote_refs) {\n@@ -259,20 +259,28 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest\n \t\tchar old_hex[60], *new_hex;\n \t\tint will_delete_ref;\n \t\tconst char *pretty_ref;\n-\t\tconst char *pretty_peer;\n+\t\tconst char *pretty_peer = NULL; /* only used when not deleting */\n+\t\tconst unsigned char *new_sha1;\n \n-\t\tif (!ref->peer_ref)\n-\t\t\tcontinue;\n+\t\tif (!ref->peer_ref) {\n+\t\t\tif (!args.send_mirror)\n+\t\t\t\tcontinue;\n+\t\t\tnew_sha1 = null_sha1;\n+\t\t}\n+\t\telse\n+\t\t\tnew_sha1 = ref->peer_ref->new_sha1;\n \n \t\tif (!shown_dest) {\n \t\t\tfprintf(stderr, \"To %s\\n\", dest);\n \t\t\tshown_dest = 1;\n \t\t}\n \n+\t\twill_delete_ref = is_null_sha1(new_sha1);\n+\n \t\tpretty_ref = prettify_ref(ref->name);\n-\t\tpretty_peer = prettify_ref(ref->peer_ref->name);\n+\t\tif (!will_delete_ref)\n+\t\t\tpretty_peer = prettify_ref(ref->peer_ref->name);\n \n-\t\twill_delete_ref = is_null_sha1(ref->peer_ref->new_sha1);\n \t\tif (will_delete_ref && !allow_deleting_refs) {\n \t\t\tfprintf(stderr, \" ! %-*s %s (remote does not support deleting refs)\\n\",\n \t\t\t\t\tSUMMARY_WIDTH, \"[rejected]\", pretty_ref);\n@@ -280,7 +288,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest\n \t\t\tcontinue;\n \t\t}\n \t\tif (!will_delete_ref &&\n-\t\t    !hashcmp(ref->old_sha1, ref->peer_ref->new_sha1)) {\n+\t\t    !hashcmp(ref->old_sha1, new_sha1)) {\n \t\t\tif (args.verbose)\n \t\t\t\tfprintf(stderr, \" = %-*s %s -> %s\\n\",\n \t\t\t\t\tSUMMARY_WIDTH, \"[up to date]\",\n@@ -312,8 +320,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest\n \t\t    !is_null_sha1(ref->old_sha1) &&\n \t\t    !ref->force) {\n \t\t\tif (!has_sha1_file(ref->old_sha1) ||\n-\t\t\t    !ref_newer(ref->peer_ref->new_sha1,\n-\t\t\t\t       ref->old_sha1)) {\n+\t\t\t    !ref_newer(new_sha1, ref->old_sha1)) {\n \t\t\t\t/* We do not have the remote ref, or\n \t\t\t\t * we know that the remote ref is not\n \t\t\t\t * an ancestor of what we are trying to\n@@ -328,7 +335,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t}\n-\t\thashcpy(ref->new_sha1, ref->peer_ref->new_sha1);\n+\t\thashcpy(ref->new_sha1, new_sha1);\n \t\tif (!will_delete_ref)\n \t\t\tnew_refs++;\n \t\tstrcpy(old_hex, sha1_to_hex(ref->old_sha1));\n@@ -459,6 +466,10 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)\n \t\t\t\targs.dry_run = 1;\n \t\t\t\tcontinue;\n \t\t\t}\n+\t\t\tif (!strcmp(arg, \"--mirror\")) {\n+\t\t\t\targs.send_mirror = 1;\n+\t\t\t\tcontinue;\n+\t\t\t}\n \t\t\tif (!strcmp(arg, \"--force\")) {\n \t\t\t\targs.force_update = 1;\n \t\t\t\tcontinue;\n@@ -483,7 +494,12 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)\n \t}\n \tif (!dest)\n \t\tusage(send_pack_usage);\n-\tif (heads && args.send_all)\n+\t/*\n+\t * --all and --mirror are incompatible; neither makes sense\n+\t * with any refspecs.\n+\t */\n+\tif ((heads && (args.send_all || args.send_mirror)) ||\n+\t\t\t\t\t(args.send_all && args.send_mirror))\n \t\tusage(send_pack_usage);\n \n \tif (remote_name) {\ndiff --git a/remote.c b/remote.c\nindex 59defdb..45dd59b 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -722,10 +722,12 @@ static const struct refspec *check_pattern_match(const struct refspec *rs,\n  * without thinking.\n  */\n int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,\n-\t       int nr_refspec, const char **refspec, int all)\n+\t       int nr_refspec, const char **refspec, int flags)\n {\n \tstruct refspec *rs =\n \t\tparse_ref_spec(nr_refspec, (const char **) refspec);\n+\tint send_all = flags & 01;\n+\tint send_mirror = flags & 02;\n \n \tif (match_explicit_refs(src, dst, dst_tail, rs, nr_refspec))\n \t\treturn -1;\n@@ -742,7 +744,7 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,\n \t\t\tif (!pat)\n \t\t\t\tcontinue;\n \t\t}\n-\t\telse if (prefixcmp(src->name, \"refs/heads/\"))\n+\t\telse if (!send_mirror && prefixcmp(src->name, \"refs/heads/\"))\n \t\t\t/*\n \t\t\t * \"matching refs\"; traditionally we pushed everything\n \t\t\t * including refs outside refs/heads/ hierarchy, but\n@@ -763,10 +765,13 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,\n \t\tif (dst_peer && dst_peer->peer_ref)\n \t\t\t/* We're already sending something to this ref. */\n \t\t\tgoto free_name;\n-\t\tif (!dst_peer && !nr_refspec && !all)\n-\t\t\t/* Remote doesn't have it, and we have no\n+\n+\t\tif (!dst_peer && !nr_refspec && !(send_all || send_mirror))\n+\t\t\t/*\n+\t\t\t * Remote doesn't have it, and we have no\n \t\t\t * explicit pattern, and we don't have\n-\t\t\t * --all. */\n+\t\t\t * --all nor --mirror.\n+\t\t\t */\n \t\t\tgoto free_name;\n \t\tif (!dst_peer) {\n \t\t\t/* Create a new one and link it */\ndiff --git a/send-pack.h b/send-pack.h\nindex 7a24f71..8ff1dc3 100644\n--- a/send-pack.h\n+++ b/send-pack.h\n@@ -5,6 +5,7 @@ struct send_pack_args {\n \tconst char *receivepack;\n \tunsigned verbose:1,\n \t\tsend_all:1,\n+\t\tsend_mirror:1,\n \t\tforce_update:1,\n \t\tuse_thin_pack:1,\n \t\tdry_run:1;\n"},{"id":"58867","messageId":"8d394f51c869abc6c910dd0ffc94b4ab@pinky","threadId":"10730","inReplyTo":"20071108121136.GG9736@shadowen.org","subject":"[PATCH 2/2] git-push: plumb in --mirror mode","fromName":"Andy Whitcroft","fromEmail":"apw@shadowen.org","sentAt":null,"receivedAt":"2007-11-08T12:11:57Z","isPatch":true,"sender":{"key":"apw@shadowen.org","avatar":"https://gravatar.com/avatar/d3088262854661a913ef35cc40fedcc270142d4461791142bc1ea0b2a4e2e147?d=mp&s=160"},"body":"\nPlumb in the --mirror mode for git-push.\n\nSigned-off-by: Andy Whitcroft <apw@shadowen.org>\n---\n builtin-push.c |   14 ++++++++++++--\n transport.c    |    7 +++++++\n transport.h    |    1 +\n 3 files changed, 20 insertions(+), 2 deletions(-)\ndiff --git a/builtin-push.c b/builtin-push.c\nindex 2c56195..d49157c 100644\n--- a/builtin-push.c\n+++ b/builtin-push.c\n@@ -10,7 +10,7 @@\n #include \"parse-options.h\"\n \n static const char * const push_usage[] = {\n-\t\"git-push [--all] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]\",\n+\t\"git-push [--all | --mirror] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]\",\n \tNULL,\n };\n \n@@ -91,6 +91,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n {\n \tint flags = 0;\n \tint all = 0;\n+\tint mirror = 0;\n \tint dry_run = 0;\n \tint force = 0;\n \tint tags = 0;\n@@ -100,6 +101,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n \t\tOPT__VERBOSE(&verbose),\n \t\tOPT_STRING( 0 , \"repo\", &repo, \"repository\", \"repository\"),\n \t\tOPT_BOOLEAN( 0 , \"all\", &all, \"push all refs\"),\n+\t\tOPT_BOOLEAN( 0 , \"mirror\", &mirror, \"mirror all refs\"),\n \t\tOPT_BOOLEAN( 0 , \"tags\", &tags, \"push tags\"),\n \t\tOPT_BOOLEAN( 0 , \"dry-run\", &dry_run, \"dry run\"),\n \t\tOPT_BOOLEAN('f', \"force\", &force, \"force updates\"),\n@@ -119,13 +121,21 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n \t\tadd_refspec(\"refs/tags/*\");\n \tif (all)\n \t\tflags |= TRANSPORT_PUSH_ALL;\n+\tif (mirror)\n+\t\tflags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE);\n \n \tif (argc > 0) {\n \t\trepo = argv[0];\n \t\tset_refspecs(argv + 1, argc - 1);\n \t}\n-\tif ((flags & TRANSPORT_PUSH_ALL) && refspec)\n+\tif ((flags & (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) && refspec)\n \t\tusage_with_options(push_usage, options);\n \n+\tif ((flags & (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) ==\n+\t\t\t\t(TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) {\n+\t\terror(\"--all and --mirror are incompatible\");\n+\t\tusage_with_options(push_usage, options);\n+\t}\n+\n \treturn do_push(repo, flags);\n }\ndiff --git a/transport.c b/transport.c\nindex f4577b7..08e62b1 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -284,6 +284,9 @@ static int rsync_transport_push(struct transport *transport,\n \tstruct child_process rsync;\n \tconst char *args[10];\n \n+\tif (flags & TRANSPORT_PUSH_MIRROR)\n+\t\treturn error(\"rsync transport does not support mirror mode\");\n+\n \t/* first push the objects */\n \n \tstrbuf_addstr(&buf, transport->url);\n@@ -386,6 +389,9 @@ static int curl_transport_push(struct transport *transport, int refspec_nr, cons\n \tint argc;\n \tint err;\n \n+\tif (flags & TRANSPORT_PUSH_MIRROR)\n+\t\treturn error(\"http transport does not support mirror mode\");\n+\n \targv = xmalloc((refspec_nr + 11) * sizeof(char *));\n \targv[0] = \"http-push\";\n \targc = 1;\n@@ -653,6 +659,7 @@ static int git_transport_push(struct transport *transport, int refspec_nr, const\n \n \targs.receivepack = data->receivepack;\n \targs.send_all = !!(flags & TRANSPORT_PUSH_ALL);\n+\targs.send_mirror = !!(flags & TRANSPORT_PUSH_MIRROR);\n \targs.force_update = !!(flags & TRANSPORT_PUSH_FORCE);\n \targs.use_thin_pack = data->thin;\n \targs.verbose = transport->verbose;\ndiff --git a/transport.h b/transport.h\nindex d27f562..7f337d2 100644\n--- a/transport.h\n+++ b/transport.h\n@@ -30,6 +30,7 @@ struct transport {\n #define TRANSPORT_PUSH_ALL 1\n #define TRANSPORT_PUSH_FORCE 2\n #define TRANSPORT_PUSH_DRY_RUN 4\n+#define TRANSPORT_PUSH_MIRROR 8\n \n /* Returns a transport suitable for the url */\n struct transport *transport_get(struct remote *, const char *);\n"},{"id":"58872","messageId":"Pine.LNX.4.64.0711081218090.4362@racer.site","threadId":"10730","inReplyTo":"20071108121136.GG9736@shadowen.org","subject":"Re: git push mirror mode","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-11-08T12:19:18Z","receivedAt":"2007-11-08T12:19:18Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Thu, 8 Nov 2007, Andy Whitcroft wrote:\n\n> Ok, sometime back Junio sent out a proof-of-concept change to\n> send-pack allowing a mirror mode.\n\nYou added/left his sign-off, but did not attribute the patches to him.  \nWhy?\n\nCiao,\nDscho\n\nP.S.: Without tests I am opposed to inclusion.  This _definitely_ needs \nsome tests.\n"},{"id":"58874","messageId":"20071108124435.GH9736@shadowen.org","threadId":"10730","inReplyTo":"Pine.LNX.4.64.0711081218090.4362@racer.site","subject":"Re: git push mirror mode","fromName":"Andy Whitcroft","fromEmail":"apw@shadowen.org","sentAt":"2007-11-08T12:44:35Z","receivedAt":"2007-11-08T12:44:35Z","isPatch":false,"sender":{"key":"apw@shadowen.org","avatar":"https://gravatar.com/avatar/d3088262854661a913ef35cc40fedcc270142d4461791142bc1ea0b2a4e2e147?d=mp&s=160"},"body":"On Thu, Nov 08, 2007 at 12:19:18PM +0000, Johannes Schindelin wrote:\n> Hi,\n> \n> On Thu, 8 Nov 2007, Andy Whitcroft wrote:\n> \n> > Ok, sometime back Junio sent out a proof-of-concept change to\n> > send-pack allowing a mirror mode.\n> \n> You added/left his sign-off, but did not attribute the patches to him.  \n> Why?\n\nI believe I left his signed off by from the original (first) patch, and\nadded mine to indicate that what I had modified was also unecombered.\nThe second patch is only signed off by me as I am the author.  In my\nworld (admittedly a kernel hacker) the first Signed-off-by: indicates the\nprimary authorship of that patch and the [apw@...] part tries to clarify\nthe changes I made therein.\n\nNo intentional stripping of credit was intended, and I believe that the\nattribution as written states Junio is the originator of this patch.\nHowever that is the way I would read the meanings of these lines, if git\nhas different rules or you think there is a clearer way of stating this\nI am happy to change it, and resend it so attributed.\n\n-apw\n"},{"id":"58875","messageId":"20071108124916.GI9736@shadowen.org","threadId":"10730","inReplyTo":"Pine.LNX.4.64.0711081218090.4362@racer.site","subject":"Re: git push mirror mode","fromName":"Andy Whitcroft","fromEmail":"apw@shadowen.org","sentAt":"2007-11-08T12:49:16Z","receivedAt":"2007-11-08T12:49:16Z","isPatch":false,"sender":{"key":"apw@shadowen.org","avatar":"https://gravatar.com/avatar/d3088262854661a913ef35cc40fedcc270142d4461791142bc1ea0b2a4e2e147?d=mp&s=160"},"body":"On Thu, Nov 08, 2007 at 12:19:18PM +0000, Johannes Schindelin wrote:\n\n> P.S.: Without tests I am opposed to inclusion.  This _definitely_ needs \n> some tests.\n\nThis is very much 'pu' material right now.  I've used it for a day\nkeeping some kernel repos in sync on a couple of test boxes.  Hardly\nextensive testing.\n\nYes some tests would be advisable.  However I am no expert in the git\ntest system, so I am not going to be able to do that in short order.\nWhat little time I had to work on this this morning was wasted by some\nSarBox madness here (but that is another story).  In the spirit of\nmaking progress on what is a useful feature I pulled Junio's original\nchange forward, fixed up my patch to expose it the the user and gave it\nsome testing.\n\nWhats there does seem to work and has a prima-facie use case.  Hopefully\nsomeone can provide the nessary tests before I can.\n\n-apw\n"},{"id":"58880","messageId":"47330BA4.6030101@op5.se","threadId":"10730","inReplyTo":"20071108124435.GH9736@shadowen.org","subject":"Re: git push mirror mode","fromName":"Andreas Ericsson","fromEmail":"ae@op5.se","sentAt":"2007-11-08T13:14:12Z","receivedAt":"2007-11-08T13:14:12Z","isPatch":false,"sender":{"key":"ae@op5.se","avatar":"https://gravatar.com/avatar/426e89595c75a8f5252dd0c989e5fabe5bcac616e68557427ad9aef6b0ca342a?d=mp&s=160"},"body":"Andy Whitcroft wrote:\n> On Thu, Nov 08, 2007 at 12:19:18PM +0000, Johannes Schindelin wrote:\n>> Hi,\n>>\n>> On Thu, 8 Nov 2007, Andy Whitcroft wrote:\n>>\n>>> Ok, sometime back Junio sent out a proof-of-concept change to\n>>> send-pack allowing a mirror mode.\n>> You added/left his sign-off, but did not attribute the patches to him.  \n>> Why?\n> \n> I believe I left his signed off by from the original (first) patch, and\n> added mine to indicate that what I had modified was also unecombered.\n> The second patch is only signed off by me as I am the author.  In my\n> world (admittedly a kernel hacker) the first Signed-off-by: indicates the\n> primary authorship of that patch and the [apw@...] part tries to clarify\n> the changes I made therein.\n> \n> No intentional stripping of credit was intended, and I believe that the\n> attribution as written states Junio is the originator of this patch.\n> However that is the way I would read the meanings of these lines, if git\n> has different rules or you think there is a clearer way of stating this\n> I am happy to change it, and resend it so attributed.\n> \n\nBarring any errors in my understanding of the matter, here's how it\nworks for git.\n\ngit separates author from committer, so code attribution is done with\nauthor, and \"I verified this is sane\" is done by committer. Those two\nusually only ever differ when the user tells git commit that the author\nwas someone else than him/her self, or when rewriting history with git\nrebase or similar. git am also maintains authorship (using the From:\nline in emails), but sets $committer to the person running it, so when\nyou apply patches sent by email from someone else you get the code\nattribution right by default.\n\nThe Signed-off-by line is, in git, used as \"I touched the code here and\nagree that it may be included in the mothership repo and all future\nreleases\" (the spirit of that sentence is also in\nDocumentation/SubmittingPatches).\n\nWe also have Acked-by (as does the kernel, no? I think we inherited it\nfrom there) to mean something along the lines of \"I vote we include this\",\nbut not always based on technical merit (ie, patches can have many acks\nwithout having ever been tested).\n\nSuggested-by, Tested-by and Reported-by are used less often, not always\nwritten in dash-form, but hopefully always self-explanatory ;-)\n\n-- \nAndreas Ericsson                   andreas.ericsson@op5.se\nOP5 AB                             www.op5.se\nTel: +46 8-230225                  Fax: +46 8-230231\n"},{"id":"58885","messageId":"20071108134432.GK9736@shadowen.org","threadId":"10730","inReplyTo":"47330BA4.6030101@op5.se","subject":"Re: git push mirror mode","fromName":"Andy Whitcroft","fromEmail":"apw@shadowen.org","sentAt":"2007-11-08T13:44:32Z","receivedAt":"2007-11-08T13:44:32Z","isPatch":false,"sender":{"key":"apw@shadowen.org","avatar":"https://gravatar.com/avatar/d3088262854661a913ef35cc40fedcc270142d4461791142bc1ea0b2a4e2e147?d=mp&s=160"},"body":"On Thu, Nov 08, 2007 at 02:14:12PM +0100, Andreas Ericsson wrote:\n\n> Barring any errors in my understanding of the matter, here's how it\n> works for git.\n> \n> git separates author from committer, so code attribution is done with\n> author, and \"I verified this is sane\" is done by committer. Those two\n> usually only ever differ when the user tells git commit that the author\n> was someone else than him/her self, or when rewriting history with git\n> rebase or similar. git am also maintains authorship (using the From:\n> line in emails), but sets $committer to the person running it, so when\n> you apply patches sent by email from someone else you get the code\n> attribution right by default.\n> \n> The Signed-off-by line is, in git, used as \"I touched the code here and\n> agree that it may be included in the mothership repo and all future\n> releases\" (the spirit of that sentence is also in\n> Documentation/SubmittingPatches).\n> \n> We also have Acked-by (as does the kernel, no? I think we inherited it\n> from there) to mean something along the lines of \"I vote we include this\",\n> but not always based on technical merit (ie, patches can have many acks\n> without having ever been tested).\n> \n> Suggested-by, Tested-by and Reported-by are used less often, not always\n> written in dash-form, but hopefully always self-explanatory ;-)\n\nWhat that doesn't tell me is how when sending an email carrying a patch\none ensures the attribution is correct when loaded into git.\n\nHaving messed about with it a bit it does seem that if one wants git to\nattribute the patch to junio I have to add a From: line to the top of\nthe email payload.\n\nI'll resend so attributed.\n\n-apw\n"},{"id":"58886","messageId":"473313A6.40401@op5.se","threadId":"10730","inReplyTo":"20071108134432.GK9736@shadowen.org","subject":"Re: git push mirror mode","fromName":"Andreas Ericsson","fromEmail":"ae@op5.se","sentAt":"2007-11-08T13:48:22Z","receivedAt":"2007-11-08T13:48:22Z","isPatch":false,"sender":{"key":"ae@op5.se","avatar":"https://gravatar.com/avatar/426e89595c75a8f5252dd0c989e5fabe5bcac616e68557427ad9aef6b0ca342a?d=mp&s=160"},"body":"Andy Whitcroft wrote:\n> On Thu, Nov 08, 2007 at 02:14:12PM +0100, Andreas Ericsson wrote:\n> \n>> Barring any errors in my understanding of the matter, here's how it\n>> works for git.\n>>\n>> git separates author from committer, so code attribution is done with\n>> author, and \"I verified this is sane\" is done by committer. Those two\n>> usually only ever differ when the user tells git commit that the author\n>> was someone else than him/her self, or when rewriting history with git\n>> rebase or similar. git am also maintains authorship (using the From:\n>> line in emails), but sets $committer to the person running it, so when\n>> you apply patches sent by email from someone else you get the code\n>> attribution right by default.\n>>\n>> The Signed-off-by line is, in git, used as \"I touched the code here and\n>> agree that it may be included in the mothership repo and all future\n>> releases\" (the spirit of that sentence is also in\n>> Documentation/SubmittingPatches).\n>>\n>> We also have Acked-by (as does the kernel, no? I think we inherited it\n>> from there) to mean something along the lines of \"I vote we include this\",\n>> but not always based on technical merit (ie, patches can have many acks\n>> without having ever been tested).\n>>\n>> Suggested-by, Tested-by and Reported-by are used less often, not always\n>> written in dash-form, but hopefully always self-explanatory ;-)\n> \n> What that doesn't tell me is how when sending an email carrying a patch\n> one ensures the attribution is correct when loaded into git.\n> \n\nAch damn. I had a sentence there reading \"From: can also be specified in\nthe email body to attribute code to someone else than the sender.\" It's\nin my clipboard, but I forgot to paste it :-/\n\n\n> Having messed about with it a bit it does seem that if one wants git to\n> attribute the patch to junio I have to add a From: line to the top of\n> the email payload.\n> \n> I'll resend so attributed.\n> \n\nThanks.\n\n-- \nAndreas Ericsson                   andreas.ericsson@op5.se\nOP5 AB                             www.op5.se\nTel: +46 8-230225                  Fax: +46 8-230231\n"},{"id":"58890","messageId":"1194531890.0@pinky","threadId":"10730","inReplyTo":"20071108121136.GG9736@shadowen.org","subject":"[PATCH 1/2] mirror pushing","fromName":"Andy Whitcroft","fromEmail":"apw@shadowen.org","sentAt":null,"receivedAt":"2007-11-08T14:14:37Z","isPatch":true,"sender":{"key":"apw@shadowen.org","avatar":"https://gravatar.com/avatar/d3088262854661a913ef35cc40fedcc270142d4461791142bc1ea0b2a4e2e147?d=mp&s=160"},"body":"\nFrom: Junio C Hamano <gitster@pobox.com>\n\nExisting \"git push --all\" is almost perfect for backing up to\nanother repository, except that \"--all\" only means \"all\nbranches\" in modern git, and it does not delete old branches and\ntags that exist at the back-up repository that you have removed\nfrom your local repository.\n\nThis teaches \"git-send-pack\" a new \"--mirror\" option.  The\ndifference from the \"--all\" option are that (1) it sends all\nrefs, not just branches, and (2) it deletes old refs you no\nlonger have on the local side from the remote side.\n\n[apw@shadowen.org: rebase to next post arguments update]\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Andy Whitcroft <apw@shadowen.org>\n---\n builtin-send-pack.c |   40 ++++++++++++++++++++++++++++------------\n remote.c            |   15 ++++++++++-----\n send-pack.h         |    1 +\n 3 files changed, 39 insertions(+), 17 deletions(-)\ndiff --git a/builtin-send-pack.c b/builtin-send-pack.c\nindex 5a0f5c6..d5ead97 100644\n--- a/builtin-send-pack.c\n+++ b/builtin-send-pack.c\n@@ -8,7 +8,7 @@\n #include \"send-pack.h\"\n \n static const char send_pack_usage[] =\n-\"git-send-pack [--all] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\\n\"\n+\"git-send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\\n\"\n \"  --all and explicit <ref> specification are mutually exclusive.\";\n \n static struct send_pack_args args = {\n@@ -242,7 +242,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest\n \tif (!remote_tail)\n \t\tremote_tail = &remote_refs;\n \tif (match_refs(local_refs, remote_refs, &remote_tail,\n-\t\t       nr_refspec, refspec, args.send_all))\n+\t\t       nr_refspec, refspec, args.send_all | (args.send_mirror << 1)))\n \t\treturn -1;\n \n \tif (!remote_refs) {\n@@ -259,20 +259,28 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest\n \t\tchar old_hex[60], *new_hex;\n \t\tint will_delete_ref;\n \t\tconst char *pretty_ref;\n-\t\tconst char *pretty_peer;\n+\t\tconst char *pretty_peer = NULL; /* only used when not deleting */\n+\t\tconst unsigned char *new_sha1;\n \n-\t\tif (!ref->peer_ref)\n-\t\t\tcontinue;\n+\t\tif (!ref->peer_ref) {\n+\t\t\tif (!args.send_mirror)\n+\t\t\t\tcontinue;\n+\t\t\tnew_sha1 = null_sha1;\n+\t\t}\n+\t\telse\n+\t\t\tnew_sha1 = ref->peer_ref->new_sha1;\n \n \t\tif (!shown_dest) {\n \t\t\tfprintf(stderr, \"To %s\\n\", dest);\n \t\t\tshown_dest = 1;\n \t\t}\n \n+\t\twill_delete_ref = is_null_sha1(new_sha1);\n+\n \t\tpretty_ref = prettify_ref(ref->name);\n-\t\tpretty_peer = prettify_ref(ref->peer_ref->name);\n+\t\tif (!will_delete_ref)\n+\t\t\tpretty_peer = prettify_ref(ref->peer_ref->name);\n \n-\t\twill_delete_ref = is_null_sha1(ref->peer_ref->new_sha1);\n \t\tif (will_delete_ref && !allow_deleting_refs) {\n \t\t\tfprintf(stderr, \" ! %-*s %s (remote does not support deleting refs)\\n\",\n \t\t\t\t\tSUMMARY_WIDTH, \"[rejected]\", pretty_ref);\n@@ -280,7 +288,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest\n \t\t\tcontinue;\n \t\t}\n \t\tif (!will_delete_ref &&\n-\t\t    !hashcmp(ref->old_sha1, ref->peer_ref->new_sha1)) {\n+\t\t    !hashcmp(ref->old_sha1, new_sha1)) {\n \t\t\tif (args.verbose)\n \t\t\t\tfprintf(stderr, \" = %-*s %s -> %s\\n\",\n \t\t\t\t\tSUMMARY_WIDTH, \"[up to date]\",\n@@ -312,8 +320,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest\n \t\t    !is_null_sha1(ref->old_sha1) &&\n \t\t    !ref->force) {\n \t\t\tif (!has_sha1_file(ref->old_sha1) ||\n-\t\t\t    !ref_newer(ref->peer_ref->new_sha1,\n-\t\t\t\t       ref->old_sha1)) {\n+\t\t\t    !ref_newer(new_sha1, ref->old_sha1)) {\n \t\t\t\t/* We do not have the remote ref, or\n \t\t\t\t * we know that the remote ref is not\n \t\t\t\t * an ancestor of what we are trying to\n@@ -328,7 +335,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t}\n-\t\thashcpy(ref->new_sha1, ref->peer_ref->new_sha1);\n+\t\thashcpy(ref->new_sha1, new_sha1);\n \t\tif (!will_delete_ref)\n \t\t\tnew_refs++;\n \t\tstrcpy(old_hex, sha1_to_hex(ref->old_sha1));\n@@ -459,6 +466,10 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)\n \t\t\t\targs.dry_run = 1;\n \t\t\t\tcontinue;\n \t\t\t}\n+\t\t\tif (!strcmp(arg, \"--mirror\")) {\n+\t\t\t\targs.send_mirror = 1;\n+\t\t\t\tcontinue;\n+\t\t\t}\n \t\t\tif (!strcmp(arg, \"--force\")) {\n \t\t\t\targs.force_update = 1;\n \t\t\t\tcontinue;\n@@ -483,7 +494,12 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)\n \t}\n \tif (!dest)\n \t\tusage(send_pack_usage);\n-\tif (heads && args.send_all)\n+\t/*\n+\t * --all and --mirror are incompatible; neither makes sense\n+\t * with any refspecs.\n+\t */\n+\tif ((heads && (args.send_all || args.send_mirror)) ||\n+\t\t\t\t\t(args.send_all && args.send_mirror))\n \t\tusage(send_pack_usage);\n \n \tif (remote_name) {\ndiff --git a/remote.c b/remote.c\nindex 59defdb..45dd59b 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -722,10 +722,12 @@ static const struct refspec *check_pattern_match(const struct refspec *rs,\n  * without thinking.\n  */\n int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,\n-\t       int nr_refspec, const char **refspec, int all)\n+\t       int nr_refspec, const char **refspec, int flags)\n {\n \tstruct refspec *rs =\n \t\tparse_ref_spec(nr_refspec, (const char **) refspec);\n+\tint send_all = flags & 01;\n+\tint send_mirror = flags & 02;\n \n \tif (match_explicit_refs(src, dst, dst_tail, rs, nr_refspec))\n \t\treturn -1;\n@@ -742,7 +744,7 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,\n \t\t\tif (!pat)\n \t\t\t\tcontinue;\n \t\t}\n-\t\telse if (prefixcmp(src->name, \"refs/heads/\"))\n+\t\telse if (!send_mirror && prefixcmp(src->name, \"refs/heads/\"))\n \t\t\t/*\n \t\t\t * \"matching refs\"; traditionally we pushed everything\n \t\t\t * including refs outside refs/heads/ hierarchy, but\n@@ -763,10 +765,13 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,\n \t\tif (dst_peer && dst_peer->peer_ref)\n \t\t\t/* We're already sending something to this ref. */\n \t\t\tgoto free_name;\n-\t\tif (!dst_peer && !nr_refspec && !all)\n-\t\t\t/* Remote doesn't have it, and we have no\n+\n+\t\tif (!dst_peer && !nr_refspec && !(send_all || send_mirror))\n+\t\t\t/*\n+\t\t\t * Remote doesn't have it, and we have no\n \t\t\t * explicit pattern, and we don't have\n-\t\t\t * --all. */\n+\t\t\t * --all nor --mirror.\n+\t\t\t */\n \t\t\tgoto free_name;\n \t\tif (!dst_peer) {\n \t\t\t/* Create a new one and link it */\ndiff --git a/send-pack.h b/send-pack.h\nindex 7a24f71..8ff1dc3 100644\n--- a/send-pack.h\n+++ b/send-pack.h\n@@ -5,6 +5,7 @@ struct send_pack_args {\n \tconst char *receivepack;\n \tunsigned verbose:1,\n \t\tsend_all:1,\n+\t\tsend_mirror:1,\n \t\tforce_update:1,\n \t\tuse_thin_pack:1,\n \t\tdry_run:1;\n"},{"id":"58891","messageId":"1194531906.0@pinky","threadId":"10730","inReplyTo":"20071108121136.GG9736@shadowen.org","subject":"[PATCH 2/2] git-push: plumb in --mirror mode","fromName":"Andy Whitcroft","fromEmail":"apw@shadowen.org","sentAt":null,"receivedAt":"2007-11-08T14:14:37Z","isPatch":true,"sender":{"key":"apw@shadowen.org","avatar":"https://gravatar.com/avatar/d3088262854661a913ef35cc40fedcc270142d4461791142bc1ea0b2a4e2e147?d=mp&s=160"},"body":"\nPlumb in the --mirror mode for git-push.\n\nSigned-off-by: Andy Whitcroft <apw@shadowen.org>\n---\n builtin-push.c |   14 ++++++++++++--\n transport.c    |    7 +++++++\n transport.h    |    1 +\n 3 files changed, 20 insertions(+), 2 deletions(-)\ndiff --git a/builtin-push.c b/builtin-push.c\nindex 2c56195..d49157c 100644\n--- a/builtin-push.c\n+++ b/builtin-push.c\n@@ -10,7 +10,7 @@\n #include \"parse-options.h\"\n \n static const char * const push_usage[] = {\n-\t\"git-push [--all] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]\",\n+\t\"git-push [--all | --mirror] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]\",\n \tNULL,\n };\n \n@@ -91,6 +91,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n {\n \tint flags = 0;\n \tint all = 0;\n+\tint mirror = 0;\n \tint dry_run = 0;\n \tint force = 0;\n \tint tags = 0;\n@@ -100,6 +101,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n \t\tOPT__VERBOSE(&verbose),\n \t\tOPT_STRING( 0 , \"repo\", &repo, \"repository\", \"repository\"),\n \t\tOPT_BOOLEAN( 0 , \"all\", &all, \"push all refs\"),\n+\t\tOPT_BOOLEAN( 0 , \"mirror\", &mirror, \"mirror all refs\"),\n \t\tOPT_BOOLEAN( 0 , \"tags\", &tags, \"push tags\"),\n \t\tOPT_BOOLEAN( 0 , \"dry-run\", &dry_run, \"dry run\"),\n \t\tOPT_BOOLEAN('f', \"force\", &force, \"force updates\"),\n@@ -119,13 +121,21 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n \t\tadd_refspec(\"refs/tags/*\");\n \tif (all)\n \t\tflags |= TRANSPORT_PUSH_ALL;\n+\tif (mirror)\n+\t\tflags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE);\n \n \tif (argc > 0) {\n \t\trepo = argv[0];\n \t\tset_refspecs(argv + 1, argc - 1);\n \t}\n-\tif ((flags & TRANSPORT_PUSH_ALL) && refspec)\n+\tif ((flags & (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) && refspec)\n \t\tusage_with_options(push_usage, options);\n \n+\tif ((flags & (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) ==\n+\t\t\t\t(TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) {\n+\t\terror(\"--all and --mirror are incompatible\");\n+\t\tusage_with_options(push_usage, options);\n+\t}\n+\n \treturn do_push(repo, flags);\n }\ndiff --git a/transport.c b/transport.c\nindex f4577b7..08e62b1 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -284,6 +284,9 @@ static int rsync_transport_push(struct transport *transport,\n \tstruct child_process rsync;\n \tconst char *args[10];\n \n+\tif (flags & TRANSPORT_PUSH_MIRROR)\n+\t\treturn error(\"rsync transport does not support mirror mode\");\n+\n \t/* first push the objects */\n \n \tstrbuf_addstr(&buf, transport->url);\n@@ -386,6 +389,9 @@ static int curl_transport_push(struct transport *transport, int refspec_nr, cons\n \tint argc;\n \tint err;\n \n+\tif (flags & TRANSPORT_PUSH_MIRROR)\n+\t\treturn error(\"http transport does not support mirror mode\");\n+\n \targv = xmalloc((refspec_nr + 11) * sizeof(char *));\n \targv[0] = \"http-push\";\n \targc = 1;\n@@ -653,6 +659,7 @@ static int git_transport_push(struct transport *transport, int refspec_nr, const\n \n \targs.receivepack = data->receivepack;\n \targs.send_all = !!(flags & TRANSPORT_PUSH_ALL);\n+\targs.send_mirror = !!(flags & TRANSPORT_PUSH_MIRROR);\n \targs.force_update = !!(flags & TRANSPORT_PUSH_FORCE);\n \targs.use_thin_pack = data->thin;\n \targs.verbose = transport->verbose;\ndiff --git a/transport.h b/transport.h\nindex d27f562..7f337d2 100644\n--- a/transport.h\n+++ b/transport.h\n@@ -30,6 +30,7 @@ struct transport {\n #define TRANSPORT_PUSH_ALL 1\n #define TRANSPORT_PUSH_FORCE 2\n #define TRANSPORT_PUSH_DRY_RUN 4\n+#define TRANSPORT_PUSH_MIRROR 8\n \n /* Returns a transport suitable for the url */\n struct transport *transport_get(struct remote *, const char *);\n"},{"id":"58899","messageId":"Pine.LNX.4.64.0711081441260.4362@racer.site","threadId":"10730","inReplyTo":"1194531890.0@pinky","subject":"Re: [PATCH 1/2] mirror pushing","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-11-08T15:03:31Z","receivedAt":"2007-11-08T15:03:31Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Thu, 8 Nov 2007, Andy Whitcroft wrote:\n\n> -\t\t       nr_refspec, refspec, args.send_all))\n> +\t\t       nr_refspec, refspec, args.send_all | (args.send_mirror << 1)))\n\nThis line is too long.  But it needsmore love: it's all too magic to have \na 1 for send_all, and a 2 for mirror.  Please introduce an enum for that \nin remote.h, and use those constants, so that this hunk and the following \none cannot get out of sync that easily.\n\n> +++ b/remote.c\n> @@ -722,10 +722,12 @@ static const struct refspec *check_pattern_match(const struct refspec *rs,\n>   * without thinking.\n>   */\n>  int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,\n> -\t       int nr_refspec, const char **refspec, int all)\n> +\t       int nr_refspec, const char **refspec, int flags)\n>  {\n>  \tstruct refspec *rs =\n>  \t\tparse_ref_spec(nr_refspec, (const char **) refspec);\n> +\tint send_all = flags & 01;\n> +\tint send_mirror = flags & 02;\n>  \n>  \tif (match_explicit_refs(src, dst, dst_tail, rs, nr_refspec))\n>  \t\treturn -1;\n\n\nThanks,\nDscho\n"},{"id":"58917","messageId":"20071108165801.GM9736@shadowen.org","threadId":"10730","inReplyTo":"20071108121136.GG9736@shadowen.org","subject":"git push mirror mode V3","fromName":"Andy Whitcroft","fromEmail":"apw@shadowen.org","sentAt":"2007-11-08T16:58:01Z","receivedAt":"2007-11-08T16:58:01Z","isPatch":false,"sender":{"key":"apw@shadowen.org","avatar":"https://gravatar.com/avatar/d3088262854661a913ef35cc40fedcc270142d4461791142bc1ea0b2a4e2e147?d=mp&s=160"},"body":"Ok, here is an update based on feedback from the list.  I bit the bullet\nand added some basic tests.  The stack passes the test suite.  Hopefully\nthe attribution is ok on the first patch now.  I have kept my\nmodifications to it a separate patch for the time being to keep\nattribution simple.\n\n-apw\n"},{"id":"58918","messageId":"1194541305.0@pinky","threadId":"10730","inReplyTo":"20071108165801.GM9736@shadowen.org","subject":"[PATCH 4/4] tests: git push mirror mode tests","fromName":"Andy Whitcroft","fromEmail":"apw@shadowen.org","sentAt":null,"receivedAt":"2007-11-08T16:58:01Z","isPatch":true,"sender":{"key":"apw@shadowen.org","avatar":"https://gravatar.com/avatar/d3088262854661a913ef35cc40fedcc270142d4461791142bc1ea0b2a4e2e147?d=mp&s=160"},"body":"\nAdd some basic tests for git push --mirror mode.\n\nSigned-off-by: Andy Whitcroft <apw@shadowen.org>\n---\n t/t5517-push-mirror.sh |  101 ++++++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 101 insertions(+), 0 deletions(-)\ndiff --git a/t/t5517-push-mirror.sh b/t/t5517-push-mirror.sh\nnew file mode 100755\nindex 0000000..1a285d4\n--- /dev/null\n+++ b/t/t5517-push-mirror.sh\n@@ -0,0 +1,101 @@\n+#!/bin/sh\n+\n+test_description='pushing to a mirror repository'\n+\n+. ./test-lib.sh\n+\n+D=`pwd`\n+\n+mk_repo_pair () {\n+\trm -rf master mirror &&\n+\tmkdir mirror && cd mirror &&\n+\t\tgit init &&\n+\tcd .. &&\n+\tmkdir master && cd master &&\n+\t\tgit init &&\n+\t\tgit config remote.up.url ../mirror &&\n+\tcd ..\n+}\n+\n+test_expect_success 'push mirror does not create new branches' '\n+\n+\tmk_repo_pair &&\n+\tcd master &&\n+\t\techo one >foo && git add foo && git commit -m one &&\n+\t\tmaster_master=$(git show-ref -s --verify refs/heads/master) &&\n+\t\tgit push --mirror up &&\n+\tcd ../mirror &&\n+\t\tmirror_master=$(git show-ref -s --verify refs/heads/master) &&\n+\ttest \"$master_master\" = \"$mirror_master\"\n+\n+'\n+\n+test_expect_success 'push mirror does not update existing branches' '\n+\n+\tmk_repo_pair &&\n+\tcd master &&\n+\t\techo one >foo && git add foo && git commit -m one &&\n+\t\tgit push --mirror up &&\n+\t\techo two >foo && git add foo && git commit -m two &&\n+\t\tmaster_master=$(git show-ref -s --verify refs/heads/master) &&\n+\t\tgit push --mirror up &&\n+\tcd ../mirror &&\n+\t\tmirror_master=$(git show-ref -s --verify refs/heads/master) &&\n+\ttest \"$master_master\" = \"$mirror_master\"\n+\n+'\n+\n+test_expect_success 'push mirror does not force update existing branches' '\n+\n+\tmk_repo_pair &&\n+\tcd master &&\n+\t\techo one >foo && git add foo && git commit -m one &&\n+\t\tgit push --mirror up &&\n+\t\techo two >foo && git add foo && git commit -m two &&\n+\t\tgit push --mirror up &&\n+\t\tgit reset --hard HEAD^\n+\t\tmaster_master=$(git show-ref -s --verify refs/heads/master) &&\n+\t\tgit push --mirror up &&\n+\tcd ../mirror &&\n+\t\tmirror_master=$(git show-ref -s --verify refs/heads/master) &&\n+\ttest \"$master_master\" = \"$mirror_master\"\n+\n+'\n+\n+test_expect_failure 'push mirror does not remove branches' '\n+\n+\tmk_repo_pair &&\n+\tcd master &&\n+\t\techo one >foo && git add foo && git commit -m one &&\n+\t\tgit branch remove master &&\n+\t\tgit push --mirror up &&\n+\t\tgit branch -D remove\n+\t\tgit push --mirror up &&\n+\tcd ../mirror &&\n+\t\tgit show-ref -s --verify refs/heads/remove\n+\n+'\n+\n+test_expect_success 'push mirror does not add, update and remove together' '\n+\n+\tmk_repo_pair &&\n+\tcd master &&\n+\t\techo one >foo && git add foo && git commit -m one &&\n+\t\tgit branch remove master &&\n+\t\tgit push --mirror up &&\n+\t\tgit branch -D remove &&\n+\t\tgit branch add master &&\n+\t\techo two >foo && git add foo && git commit -m two &&\n+\t\tmaster_master=$(git show-ref -s --verify refs/heads/master) &&\n+\t\tmaster_add=$(git show-ref -s --verify refs/heads/add) &&\n+\t\tgit push --mirror up &&\n+\tcd ../mirror &&\n+\t\tmirror_master=$(git show-ref -s --verify refs/heads/master) &&\n+\t\tmirror_add=$(git show-ref -s --verify refs/heads/add) &&\n+\t\ttest \"$master_master\" = \"$mirror_master\" &&\n+\t\ttest \"$master_add\" = \"$mirror_add\" &&\n+\t\t! git show-ref -s --verify refs/heads/remove\n+\n+'\n+\n+test_done\n"},{"id":"58919","messageId":"1194541273.0@pinky","threadId":"10730","inReplyTo":"20071108165801.GM9736@shadowen.org","subject":"[PATCH 2/4] mirror pushing -- clean up match_refs flags","fromName":"Andy Whitcroft","fromEmail":"apw@shadowen.org","sentAt":null,"receivedAt":"2007-11-08T16:58:01Z","isPatch":true,"sender":{"key":"apw@shadowen.org","avatar":"https://gravatar.com/avatar/d3088262854661a913ef35cc40fedcc270142d4461791142bc1ea0b2a4e2e147?d=mp&s=160"},"body":"\nAdd a new enum to define the match_refs flags field and switch\nall callers to it.\n\nSigned-off-by: Andy Whitcroft <apw@shadowen.org>\n---\n builtin-send-pack.c |    8 +++++++-\n http-push.c         |    4 ++--\n remote.c            |    4 ++--\n remote.h            |    7 +++++++\n 4 files changed, 18 insertions(+), 5 deletions(-)\ndiff --git a/builtin-send-pack.c b/builtin-send-pack.c\nindex d5ead97..d42164e 100644\n--- a/builtin-send-pack.c\n+++ b/builtin-send-pack.c\n@@ -227,6 +227,12 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest\n \tint allow_deleting_refs = 0;\n \tint expect_status_report = 0;\n \tint shown_dest = 0;\n+\tint flags = MATCH_REFS_NONE;\n+\n+\tif (args.send_all)\n+\t\tflags |= MATCH_REFS_ALL;\n+\tif (args.send_mirror)\n+\t\tflags |= MATCH_REFS_MIRROR;\n \n \t/* No funny business with the matcher */\n \tremote_tail = get_remote_heads(in, &remote_refs, 0, NULL, REF_NORMAL);\n@@ -242,7 +248,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest\n \tif (!remote_tail)\n \t\tremote_tail = &remote_refs;\n \tif (match_refs(local_refs, remote_refs, &remote_tail,\n-\t\t       nr_refspec, refspec, args.send_all | (args.send_mirror << 1)))\n+\t\t\t\t\t       nr_refspec, refspec, flags))\n \t\treturn -1;\n \n \tif (!remote_refs) {\ndiff --git a/http-push.c b/http-push.c\nindex 99328f5..66b81f1 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -78,7 +78,7 @@ static struct curl_slist *no_pragma_header;\n static struct curl_slist *default_headers;\n \n static int push_verbosely;\n-static int push_all;\n+static int push_all = MATCH_REFS_NONE;\n static int force_all;\n static int dry_run;\n \n@@ -2300,7 +2300,7 @@ int main(int argc, char **argv)\n \n \t\tif (*arg == '-') {\n \t\t\tif (!strcmp(arg, \"--all\")) {\n-\t\t\t\tpush_all = 1;\n+\t\t\t\tpush_all = MATCH_REFS_ALL;\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (!strcmp(arg, \"--force\")) {\ndiff --git a/remote.c b/remote.c\nindex 45dd59b..09b7aad 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -726,8 +726,8 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,\n {\n \tstruct refspec *rs =\n \t\tparse_ref_spec(nr_refspec, (const char **) refspec);\n-\tint send_all = flags & 01;\n-\tint send_mirror = flags & 02;\n+\tint send_all = flags & MATCH_REFS_ALL;\n+\tint send_mirror = flags & MATCH_REFS_MIRROR;\n \n \tif (match_explicit_refs(src, dst, dst_tail, rs, nr_refspec))\n \t\treturn -1;\ndiff --git a/remote.h b/remote.h\nindex 6a4c7a0..b10036c 100644\n--- a/remote.h\n+++ b/remote.h\n@@ -102,4 +102,11 @@ struct branch *branch_get(const char *name);\n int branch_has_merge_config(struct branch *branch);\n int branch_merge_matches(struct branch *, int n, const char *);\n \n+/* Flags to match_refs. */\n+enum match_refs_flags {\n+\tMATCH_REFS_NONE\t\t= 0,\n+\tMATCH_REFS_ALL \t\t= (1 << 0),\n+\tMATCH_REFS_MIRROR\t= (1 << 1),\n+};\n+\n #endif\n"},{"id":"58920","messageId":"1194541289.0@pinky","threadId":"10730","inReplyTo":"20071108165801.GM9736@shadowen.org","subject":"[PATCH 3/4] git-push: plumb in --mirror mode","fromName":"Andy Whitcroft","fromEmail":"apw@shadowen.org","sentAt":null,"receivedAt":"2007-11-08T16:58:01Z","isPatch":true,"sender":{"key":"apw@shadowen.org","avatar":"https://gravatar.com/avatar/d3088262854661a913ef35cc40fedcc270142d4461791142bc1ea0b2a4e2e147?d=mp&s=160"},"body":"\nPlumb in the --mirror mode for git-push.\n\nSigned-off-by: Andy Whitcroft <apw@shadowen.org>\n---\n builtin-push.c |   14 ++++++++++++--\n transport.c    |    7 +++++++\n transport.h    |    1 +\n 3 files changed, 20 insertions(+), 2 deletions(-)\ndiff --git a/builtin-push.c b/builtin-push.c\nindex 2c56195..d49157c 100644\n--- a/builtin-push.c\n+++ b/builtin-push.c\n@@ -10,7 +10,7 @@\n #include \"parse-options.h\"\n \n static const char * const push_usage[] = {\n-\t\"git-push [--all] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]\",\n+\t\"git-push [--all | --mirror] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]\",\n \tNULL,\n };\n \n@@ -91,6 +91,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n {\n \tint flags = 0;\n \tint all = 0;\n+\tint mirror = 0;\n \tint dry_run = 0;\n \tint force = 0;\n \tint tags = 0;\n@@ -100,6 +101,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n \t\tOPT__VERBOSE(&verbose),\n \t\tOPT_STRING( 0 , \"repo\", &repo, \"repository\", \"repository\"),\n \t\tOPT_BOOLEAN( 0 , \"all\", &all, \"push all refs\"),\n+\t\tOPT_BOOLEAN( 0 , \"mirror\", &mirror, \"mirror all refs\"),\n \t\tOPT_BOOLEAN( 0 , \"tags\", &tags, \"push tags\"),\n \t\tOPT_BOOLEAN( 0 , \"dry-run\", &dry_run, \"dry run\"),\n \t\tOPT_BOOLEAN('f', \"force\", &force, \"force updates\"),\n@@ -119,13 +121,21 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n \t\tadd_refspec(\"refs/tags/*\");\n \tif (all)\n \t\tflags |= TRANSPORT_PUSH_ALL;\n+\tif (mirror)\n+\t\tflags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE);\n \n \tif (argc > 0) {\n \t\trepo = argv[0];\n \t\tset_refspecs(argv + 1, argc - 1);\n \t}\n-\tif ((flags & TRANSPORT_PUSH_ALL) && refspec)\n+\tif ((flags & (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) && refspec)\n \t\tusage_with_options(push_usage, options);\n \n+\tif ((flags & (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) ==\n+\t\t\t\t(TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) {\n+\t\terror(\"--all and --mirror are incompatible\");\n+\t\tusage_with_options(push_usage, options);\n+\t}\n+\n \treturn do_push(repo, flags);\n }\ndiff --git a/transport.c b/transport.c\nindex f4577b7..08e62b1 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -284,6 +284,9 @@ static int rsync_transport_push(struct transport *transport,\n \tstruct child_process rsync;\n \tconst char *args[10];\n \n+\tif (flags & TRANSPORT_PUSH_MIRROR)\n+\t\treturn error(\"rsync transport does not support mirror mode\");\n+\n \t/* first push the objects */\n \n \tstrbuf_addstr(&buf, transport->url);\n@@ -386,6 +389,9 @@ static int curl_transport_push(struct transport *transport, int refspec_nr, cons\n \tint argc;\n \tint err;\n \n+\tif (flags & TRANSPORT_PUSH_MIRROR)\n+\t\treturn error(\"http transport does not support mirror mode\");\n+\n \targv = xmalloc((refspec_nr + 11) * sizeof(char *));\n \targv[0] = \"http-push\";\n \targc = 1;\n@@ -653,6 +659,7 @@ static int git_transport_push(struct transport *transport, int refspec_nr, const\n \n \targs.receivepack = data->receivepack;\n \targs.send_all = !!(flags & TRANSPORT_PUSH_ALL);\n+\targs.send_mirror = !!(flags & TRANSPORT_PUSH_MIRROR);\n \targs.force_update = !!(flags & TRANSPORT_PUSH_FORCE);\n \targs.use_thin_pack = data->thin;\n \targs.verbose = transport->verbose;\ndiff --git a/transport.h b/transport.h\nindex d27f562..7f337d2 100644\n--- a/transport.h\n+++ b/transport.h\n@@ -30,6 +30,7 @@ struct transport {\n #define TRANSPORT_PUSH_ALL 1\n #define TRANSPORT_PUSH_FORCE 2\n #define TRANSPORT_PUSH_DRY_RUN 4\n+#define TRANSPORT_PUSH_MIRROR 8\n \n /* Returns a transport suitable for the url */\n struct transport *transport_get(struct remote *, const char *);\n"},{"id":"58921","messageId":"1194541257.0@pinky","threadId":"10730","inReplyTo":"20071108165801.GM9736@shadowen.org","subject":"[PATCH 1/4] mirror pushing","fromName":"Andy Whitcroft","fromEmail":"apw@shadowen.org","sentAt":null,"receivedAt":"2007-11-08T16:58:01Z","isPatch":true,"sender":{"key":"apw@shadowen.org","avatar":"https://gravatar.com/avatar/d3088262854661a913ef35cc40fedcc270142d4461791142bc1ea0b2a4e2e147?d=mp&s=160"},"body":"\nFrom: Junio C Hamano <gitster@pobox.com>\n\nExisting \"git push --all\" is almost perfect for backing up to\nanother repository, except that \"--all\" only means \"all\nbranches\" in modern git, and it does not delete old branches and\ntags that exist at the back-up repository that you have removed\nfrom your local repository.\n\nThis teaches \"git-send-pack\" a new \"--mirror\" option.  The\ndifference from the \"--all\" option are that (1) it sends all\nrefs, not just branches, and (2) it deletes old refs you no\nlonger have on the local side from the remote side.\n\n[apw@shadowen.org: rebase to next post arguments update]\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Andy Whitcroft <apw@shadowen.org>\n---\n builtin-send-pack.c |   40 ++++++++++++++++++++++++++++------------\n remote.c            |   15 ++++++++++-----\n send-pack.h         |    1 +\n 3 files changed, 39 insertions(+), 17 deletions(-)\ndiff --git a/builtin-send-pack.c b/builtin-send-pack.c\nindex 5a0f5c6..d5ead97 100644\n--- a/builtin-send-pack.c\n+++ b/builtin-send-pack.c\n@@ -8,7 +8,7 @@\n #include \"send-pack.h\"\n \n static const char send_pack_usage[] =\n-\"git-send-pack [--all] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\\n\"\n+\"git-send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\\n\"\n \"  --all and explicit <ref> specification are mutually exclusive.\";\n \n static struct send_pack_args args = {\n@@ -242,7 +242,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest\n \tif (!remote_tail)\n \t\tremote_tail = &remote_refs;\n \tif (match_refs(local_refs, remote_refs, &remote_tail,\n-\t\t       nr_refspec, refspec, args.send_all))\n+\t\t       nr_refspec, refspec, args.send_all | (args.send_mirror << 1)))\n \t\treturn -1;\n \n \tif (!remote_refs) {\n@@ -259,20 +259,28 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest\n \t\tchar old_hex[60], *new_hex;\n \t\tint will_delete_ref;\n \t\tconst char *pretty_ref;\n-\t\tconst char *pretty_peer;\n+\t\tconst char *pretty_peer = NULL; /* only used when not deleting */\n+\t\tconst unsigned char *new_sha1;\n \n-\t\tif (!ref->peer_ref)\n-\t\t\tcontinue;\n+\t\tif (!ref->peer_ref) {\n+\t\t\tif (!args.send_mirror)\n+\t\t\t\tcontinue;\n+\t\t\tnew_sha1 = null_sha1;\n+\t\t}\n+\t\telse\n+\t\t\tnew_sha1 = ref->peer_ref->new_sha1;\n \n \t\tif (!shown_dest) {\n \t\t\tfprintf(stderr, \"To %s\\n\", dest);\n \t\t\tshown_dest = 1;\n \t\t}\n \n+\t\twill_delete_ref = is_null_sha1(new_sha1);\n+\n \t\tpretty_ref = prettify_ref(ref->name);\n-\t\tpretty_peer = prettify_ref(ref->peer_ref->name);\n+\t\tif (!will_delete_ref)\n+\t\t\tpretty_peer = prettify_ref(ref->peer_ref->name);\n \n-\t\twill_delete_ref = is_null_sha1(ref->peer_ref->new_sha1);\n \t\tif (will_delete_ref && !allow_deleting_refs) {\n \t\t\tfprintf(stderr, \" ! %-*s %s (remote does not support deleting refs)\\n\",\n \t\t\t\t\tSUMMARY_WIDTH, \"[rejected]\", pretty_ref);\n@@ -280,7 +288,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest\n \t\t\tcontinue;\n \t\t}\n \t\tif (!will_delete_ref &&\n-\t\t    !hashcmp(ref->old_sha1, ref->peer_ref->new_sha1)) {\n+\t\t    !hashcmp(ref->old_sha1, new_sha1)) {\n \t\t\tif (args.verbose)\n \t\t\t\tfprintf(stderr, \" = %-*s %s -> %s\\n\",\n \t\t\t\t\tSUMMARY_WIDTH, \"[up to date]\",\n@@ -312,8 +320,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest\n \t\t    !is_null_sha1(ref->old_sha1) &&\n \t\t    !ref->force) {\n \t\t\tif (!has_sha1_file(ref->old_sha1) ||\n-\t\t\t    !ref_newer(ref->peer_ref->new_sha1,\n-\t\t\t\t       ref->old_sha1)) {\n+\t\t\t    !ref_newer(new_sha1, ref->old_sha1)) {\n \t\t\t\t/* We do not have the remote ref, or\n \t\t\t\t * we know that the remote ref is not\n \t\t\t\t * an ancestor of what we are trying to\n@@ -328,7 +335,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t}\n-\t\thashcpy(ref->new_sha1, ref->peer_ref->new_sha1);\n+\t\thashcpy(ref->new_sha1, new_sha1);\n \t\tif (!will_delete_ref)\n \t\t\tnew_refs++;\n \t\tstrcpy(old_hex, sha1_to_hex(ref->old_sha1));\n@@ -459,6 +466,10 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)\n \t\t\t\targs.dry_run = 1;\n \t\t\t\tcontinue;\n \t\t\t}\n+\t\t\tif (!strcmp(arg, \"--mirror\")) {\n+\t\t\t\targs.send_mirror = 1;\n+\t\t\t\tcontinue;\n+\t\t\t}\n \t\t\tif (!strcmp(arg, \"--force\")) {\n \t\t\t\targs.force_update = 1;\n \t\t\t\tcontinue;\n@@ -483,7 +494,12 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)\n \t}\n \tif (!dest)\n \t\tusage(send_pack_usage);\n-\tif (heads && args.send_all)\n+\t/*\n+\t * --all and --mirror are incompatible; neither makes sense\n+\t * with any refspecs.\n+\t */\n+\tif ((heads && (args.send_all || args.send_mirror)) ||\n+\t\t\t\t\t(args.send_all && args.send_mirror))\n \t\tusage(send_pack_usage);\n \n \tif (remote_name) {\ndiff --git a/remote.c b/remote.c\nindex 59defdb..45dd59b 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -722,10 +722,12 @@ static const struct refspec *check_pattern_match(const struct refspec *rs,\n  * without thinking.\n  */\n int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,\n-\t       int nr_refspec, const char **refspec, int all)\n+\t       int nr_refspec, const char **refspec, int flags)\n {\n \tstruct refspec *rs =\n \t\tparse_ref_spec(nr_refspec, (const char **) refspec);\n+\tint send_all = flags & 01;\n+\tint send_mirror = flags & 02;\n \n \tif (match_explicit_refs(src, dst, dst_tail, rs, nr_refspec))\n \t\treturn -1;\n@@ -742,7 +744,7 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,\n \t\t\tif (!pat)\n \t\t\t\tcontinue;\n \t\t}\n-\t\telse if (prefixcmp(src->name, \"refs/heads/\"))\n+\t\telse if (!send_mirror && prefixcmp(src->name, \"refs/heads/\"))\n \t\t\t/*\n \t\t\t * \"matching refs\"; traditionally we pushed everything\n \t\t\t * including refs outside refs/heads/ hierarchy, but\n@@ -763,10 +765,13 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,\n \t\tif (dst_peer && dst_peer->peer_ref)\n \t\t\t/* We're already sending something to this ref. */\n \t\t\tgoto free_name;\n-\t\tif (!dst_peer && !nr_refspec && !all)\n-\t\t\t/* Remote doesn't have it, and we have no\n+\n+\t\tif (!dst_peer && !nr_refspec && !(send_all || send_mirror))\n+\t\t\t/*\n+\t\t\t * Remote doesn't have it, and we have no\n \t\t\t * explicit pattern, and we don't have\n-\t\t\t * --all. */\n+\t\t\t * --all nor --mirror.\n+\t\t\t */\n \t\t\tgoto free_name;\n \t\tif (!dst_peer) {\n \t\t\t/* Create a new one and link it */\ndiff --git a/send-pack.h b/send-pack.h\nindex 7a24f71..8ff1dc3 100644\n--- a/send-pack.h\n+++ b/send-pack.h\n@@ -5,6 +5,7 @@ struct send_pack_args {\n \tconst char *receivepack;\n \tunsigned verbose:1,\n \t\tsend_all:1,\n+\t\tsend_mirror:1,\n \t\tforce_update:1,\n \t\tuse_thin_pack:1,\n \t\tdry_run:1;\n"},{"id":"58943","messageId":"7vk5os1k0y.fsf@gitster.siamese.dyndns.org","threadId":"10730","inReplyTo":"Pine.LNX.4.64.0711081218090.4362@racer.site","subject":"Re: git push mirror mode","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-11-08T21:53:33Z","receivedAt":"2007-11-08T21:53:33Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> On Thu, 8 Nov 2007, Andy Whitcroft wrote:\n>\n>> Ok, sometime back Junio sent out a proof-of-concept change to\n>> send-pack allowing a mirror mode.\n>\n> You added/left his sign-off, but did not attribute the patches to him.  \n\nNo big deal; I do not think much of my changes remain in the\nresult.  Mentioning \"inspired by\" would be nice as courtesy, but\nI think this is mostly Andy's work.\n\nAs I haven't seen _his_ part of the change before he posted this\nupdated patch, copying my S-o-b line wasn't necessary either.\n"},{"id":"59014","messageId":"1194603673.0@pinky","threadId":"10730","inReplyTo":"1194541305.0@pinky","subject":"[PATCH] tests: git push mirror mode tests V2","fromName":"Andy Whitcroft","fromEmail":"apw@shadowen.org","sentAt":null,"receivedAt":"2007-11-09T09:12:28Z","isPatch":true,"sender":{"key":"apw@shadowen.org","avatar":"https://gravatar.com/avatar/d3088262854661a913ef35cc40fedcc270142d4461791142bc1ea0b2a4e2e147?d=mp&s=160"},"body":"\nAdd some basic tests for git push --mirror mode.\n\nSigned-off-by: Andy Whitcroft <apw@shadowen.org>\n---\n\tFollowing the discussion on how tests which change directory\n\tshould use subshells to prevent loss of CWD and of how\n\t! is not something we can rely on, here is an updates to\n\tthe tests.\n---\n t/t5517-push-mirror.sh |  125 ++++++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 125 insertions(+), 0 deletions(-)\ndiff --git a/t/t5517-push-mirror.sh b/t/t5517-push-mirror.sh\nnew file mode 100755\nindex 0000000..a65d2f5\n--- /dev/null\n+++ b/t/t5517-push-mirror.sh\n@@ -0,0 +1,125 @@\n+#!/bin/sh\n+\n+test_description='pushing to a mirror repository'\n+\n+. ./test-lib.sh\n+\n+D=`pwd`\n+\n+invert () {\n+\tif \"$@\"; then\n+\t\treturn 1\n+\telse\n+\t\treturn 0\n+\tfi\n+}\n+\n+mk_repo_pair () {\n+\trm -rf master mirror &&\n+\tmkdir mirror &&\n+\t(\n+\t\tcd mirror &&\n+\t\tgit init\n+\t) &&\n+\tmkdir master &&\n+\t(\n+\t\tcd master &&\n+\t\tgit init &&\n+\t\tgit config remote.up.url ../mirror\n+\t)\n+}\n+\n+\n+test_expect_success 'push mirror does not create new branches' '\n+\n+\tmk_repo_pair &&\n+\t(\n+\t\tcd master &&\n+\t\techo one >foo && git add foo && git commit -m one &&\n+\t\tgit push --mirror up\n+\t) &&\n+\tmaster_master=$(cd master && git show-ref -s --verify refs/heads/master) &&\n+\tmirror_master=$(cd mirror && git show-ref -s --verify refs/heads/master) &&\n+\ttest \"$master_master\" = \"$mirror_master\"\n+\n+'\n+\n+test_expect_success 'push mirror does not update existing branches' '\n+\n+\tmk_repo_pair &&\n+\t(\n+\t\tcd master &&\n+\t\techo one >foo && git add foo && git commit -m one &&\n+\t\tgit push --mirror up &&\n+\t\techo two >foo && git add foo && git commit -m two &&\n+\t\tgit push --mirror up\n+\t) &&\n+\tmaster_master=$(cd master && git show-ref -s --verify refs/heads/master) &&\n+\tmirror_master=$(cd mirror && git show-ref -s --verify refs/heads/master) &&\n+\ttest \"$master_master\" = \"$mirror_master\"\n+\n+'\n+\n+test_expect_success 'push mirror does not force update existing branches' '\n+\n+\tmk_repo_pair &&\n+\t(\n+\t\tcd master &&\n+\t\techo one >foo && git add foo && git commit -m one &&\n+\t\tgit push --mirror up &&\n+\t\techo two >foo && git add foo && git commit -m two &&\n+\t\tgit push --mirror up &&\n+\t\tgit reset --hard HEAD^\n+\t\tgit push --mirror up\n+\t) &&\n+\tmaster_master=$(cd master && git show-ref -s --verify refs/heads/master) &&\n+\tmirror_master=$(cd mirror && git show-ref -s --verify refs/heads/master) &&\n+\ttest \"$master_master\" = \"$mirror_master\"\n+\n+'\n+\n+test_expect_success 'push mirror does not remove branches' '\n+\n+\tmk_repo_pair &&\n+\t(\n+\t\tcd master &&\n+\t\techo one >foo && git add foo && git commit -m one &&\n+\t\tgit branch remove master &&\n+\t\tgit push --mirror up &&\n+\t\tgit branch -D remove\n+\t\tgit push --mirror up \n+\t) &&\n+\t(\n+\t\tcd mirror &&\n+\t\tinvert git show-ref -s --verify refs/heads/remove\n+\t)\n+\n+'\n+\n+test_expect_success 'push mirror does not add, update and remove together' '\n+\n+\tmk_repo_pair &&\n+\t(\n+\t\tcd master &&\n+\t\techo one >foo && git add foo && git commit -m one &&\n+\t\tgit branch remove master &&\n+\t\tgit push --mirror up &&\n+\t\tgit branch -D remove &&\n+\t\tgit branch add master &&\n+\t\techo two >foo && git add foo && git commit -m two &&\n+\t\tgit push --mirror up\n+\t) &&\n+\tmaster_master=$(cd master && git show-ref -s --verify refs/heads/master) &&\n+\tmaster_add=$(cd master && git show-ref -s --verify refs/heads/add) &&\n+\tmirror_master=$(cd mirror && git show-ref -s --verify refs/heads/master) &&\n+\tmirror_add=$(cd mirror && git show-ref -s --verify refs/heads/add) &&\n+\ttest \"$master_master\" = \"$mirror_master\" &&\n+\ttest \"$master_add\" = \"$mirror_add\" &&\n+\t(\n+\t\tcd mirror &&\n+\t\tinvert git show-ref -s --verify refs/heads/remove\n+\t)\n+\n+'\n+\n+test_done\n"},{"id":"59058","messageId":"1194619555.0@pinky","threadId":"10730","inReplyTo":"1194603673.0@pinky","subject":"[PATCH] tests: git push mirror mode tests V2 -- add tag tests","fromName":"Andy Whitcroft","fromEmail":"apw@shadowen.org","sentAt":null,"receivedAt":"2007-11-09T14:43:49Z","isPatch":true,"sender":{"key":"apw@shadowen.org","avatar":"https://gravatar.com/avatar/d3088262854661a913ef35cc40fedcc270142d4461791142bc1ea0b2a4e2e147?d=mp&s=160"},"body":"\nAdd additional tests to the the V2 tests testing the handling of\ntags in --mirror mode.  We expect these to be tracked in line with\nthe master.\n\nSigned-off-by: Andy Whitcroft <apw@shadowen.org>\n---\n\tNote that this patch is cumulative on top of the following\n\tpatch:\n\t\ttests: git push mirror mode tests V2\n\n\tThese two patches together replace the 4/4 from the original\n\tseries.\n---\n t/t5517-push-mirror.sh |  105 +++++++++++++++++++++++++++++++++++++++++++++++-\n 1 files changed, 104 insertions(+), 1 deletions(-)\ndiff --git a/t/t5517-push-mirror.sh b/t/t5517-push-mirror.sh\nindex a65d2f5..ec87ce5 100755\n--- a/t/t5517-push-mirror.sh\n+++ b/t/t5517-push-mirror.sh\n@@ -30,6 +30,7 @@ mk_repo_pair () {\n }\n \n \n+# BRANCH tests\n test_expect_success 'push mirror does not create new branches' '\n \n \tmk_repo_pair &&\n@@ -96,7 +97,7 @@ test_expect_success 'push mirror does not remove branches' '\n \n '\n \n-test_expect_success 'push mirror does not add, update and remove together' '\n+test_expect_success 'push mirror does not add, update and remove branches together' '\n \n \tmk_repo_pair &&\n \t(\n@@ -122,4 +123,106 @@ test_expect_success 'push mirror does not add, update and remove together' '\n \n '\n \n+\n+# TAG tests\n+test_expect_success 'push mirror does not create new tags' '\n+\n+\tmk_repo_pair &&\n+\t(\n+\t\tcd master &&\n+\t\techo one >foo && git add foo && git commit -m one &&\n+\t\tgit tag -f tmaster master &&\n+\t\tgit push --mirror up\n+\t) &&\n+\tmaster_master=$(cd master && git show-ref -s --verify refs/tags/tmaster) &&\n+\tmirror_master=$(cd mirror && git show-ref -s --verify refs/tags/tmaster) &&\n+\ttest \"$master_master\" = \"$mirror_master\"\n+\n+'\n+\n+test_expect_success 'push mirror does not update existing tags' '\n+\n+\tmk_repo_pair &&\n+\t(\n+\t\tcd master &&\n+\t\techo one >foo && git add foo && git commit -m one &&\n+\t\tgit tag -f tmaster master &&\n+\t\tgit push --mirror up &&\n+\t\techo two >foo && git add foo && git commit -m two &&\n+\t\tgit tag -f tmaster master &&\n+\t\tgit push --mirror up\n+\t) &&\n+\tmaster_master=$(cd master && git show-ref -s --verify refs/tags/tmaster) &&\n+\tmirror_master=$(cd mirror && git show-ref -s --verify refs/tags/tmaster) &&\n+\ttest \"$master_master\" = \"$mirror_master\"\n+\n+'\n+\n+test_expect_success 'push mirror does not force update existing tags' '\n+\n+\tmk_repo_pair &&\n+\t(\n+\t\tcd master &&\n+\t\techo one >foo && git add foo && git commit -m one &&\n+\t\tgit tag -f tmaster master &&\n+\t\tgit push --mirror up &&\n+\t\techo two >foo && git add foo && git commit -m two &&\n+\t\tgit tag -f tmaster master &&\n+\t\tgit push --mirror up &&\n+\t\tgit reset --hard HEAD^\n+\t\tgit tag -f tmaster master &&\n+\t\tgit push --mirror up\n+\t) &&\n+\tmaster_master=$(cd master && git show-ref -s --verify refs/tags/tmaster) &&\n+\tmirror_master=$(cd mirror && git show-ref -s --verify refs/tags/tmaster) &&\n+\ttest \"$master_master\" = \"$mirror_master\"\n+\n+'\n+\n+test_expect_success 'push mirror does not remove tags' '\n+\n+\tmk_repo_pair &&\n+\t(\n+\t\tcd master &&\n+\t\techo one >foo && git add foo && git commit -m one &&\n+\t\tgit tag -f tremove master &&\n+\t\tgit push --mirror up &&\n+\t\tgit tag -d tremove\n+\t\tgit push --mirror up \n+\t) &&\n+\t(\n+\t\tcd mirror &&\n+\t\tinvert git show-ref -s --verify refs/tags/tremove\n+\t)\n+\n+'\n+\n+test_expect_success 'push mirror does not add, update and remove tags together' '\n+\n+\tmk_repo_pair &&\n+\t(\n+\t\tcd master &&\n+\t\techo one >foo && git add foo && git commit -m one &&\n+\t\tgit tag -f tmaster master &&\n+\t\tgit tag -f tremove master &&\n+\t\tgit push --mirror up &&\n+\t\tgit tag -d tremove &&\n+\t\tgit tag tadd master &&\n+\t\techo two >foo && git add foo && git commit -m two &&\n+\t\tgit tag -f tmaster master &&\n+\t\tgit push --mirror up\n+\t) &&\n+\tmaster_master=$(cd master && git show-ref -s --verify refs/tags/tmaster) &&\n+\tmaster_add=$(cd master && git show-ref -s --verify refs/tags/tadd) &&\n+\tmirror_master=$(cd mirror && git show-ref -s --verify refs/tags/tmaster) &&\n+\tmirror_add=$(cd mirror && git show-ref -s --verify refs/tags/tadd) &&\n+\ttest \"$master_master\" = \"$mirror_master\" &&\n+\ttest \"$master_add\" = \"$mirror_add\" &&\n+\t(\n+\t\tcd mirror &&\n+\t\tinvert git show-ref -s --verify refs/tags/tremove\n+\t)\n+\n+'\n+\n test_done\n"},{"id":"59059","messageId":"1194620467.0@pinky","threadId":"10730","inReplyTo":"1194619555.0@pinky","subject":"[PATCH] git-push: add documentation for the newly add --mirror mode","fromName":"Andy Whitcroft","fromEmail":"apw@shadowen.org","sentAt":null,"receivedAt":"2007-11-09T14:43:49Z","isPatch":true,"sender":{"key":"apw@shadowen.org","avatar":"https://gravatar.com/avatar/d3088262854661a913ef35cc40fedcc270142d4461791142bc1ea0b2a4e2e147?d=mp&s=160"},"body":"\nAdd some basic documentation on the --mirror mode for git-push.\n\nSigned-off-by: Andy Whitcroft <apw@shadowen.org>\n---\n Documentation/git-push.txt |    8 ++++++++\n 1 files changed, 8 insertions(+), 0 deletions(-)\ndiff --git a/Documentation/git-push.txt b/Documentation/git-push.txt\nindex e5dd4c1..2403621 100644\n--- a/Documentation/git-push.txt\n+++ b/Documentation/git-push.txt\n@@ -62,6 +62,14 @@ the remote repository.\n \\--all::\n \tInstead of naming each ref to push, specifies that all\n \trefs under `$GIT_DIR/refs/heads/` be pushed.\n+\t\n+\\--mirror::\n+\tInstead of naming each ref to push, specifies that all\n+\trefs under `$GIT_DIR/refs/heads/` and `$GIT_DIR/refs/tags/`\n+\tbe mirrored to the remote repository.  Newly created local\n+\trefs will be pushed to the remote end, locally updated refs\n+\twill be force updated on the remote end, and deleted refs\n+\twill be removed from the remote end.\n \n \\--dry-run::\n \tDo everything except actually send the updates.\n"},{"id":"59121","messageId":"7vsl3frxpk.fsf@gitster.siamese.dyndns.org","threadId":"10730","inReplyTo":"1194603673.0@pinky","subject":"Re: [PATCH] tests: git push mirror mode tests V2","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-11-09T20:05:43Z","receivedAt":"2007-11-09T20:05:43Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Andy Whitcroft <apw@shadowen.org> writes:\n\n> +test_expect_success 'push mirror does not create new branches' '\n> +\n> +\tmk_repo_pair &&\n> +\t(\n> +\t\tcd master &&\n> +\t\techo one >foo && git add foo && git commit -m one &&\n> +\t\tgit push --mirror up\n> +\t) &&\n> +\tmaster_master=$(cd master && git show-ref -s --verify refs/heads/master) &&\n> +\tmirror_master=$(cd mirror && git show-ref -s --verify refs/heads/master) &&\n> +\ttest \"$master_master\" = \"$mirror_master\"\n> +\n> +'\n\nI am quite puzzled by this and many other \"does not\" in the test\ndescription.  The --mirror option is advertised as\n\n - newly created will be pushed;\n - locally updated will be force pushed;\n - locally deleted will be removed.\n\nwhich makes sense as we do want these things to happen for\n\"mirrors\".  Indeed the above updates master branch at the master\nrepository and makes sure that change is propagated to the\nmirror repository.  The description should read \"push mirror\ncreates new branches\" shouldn't it?\n"},{"id":"59500","messageId":"20071112152541.GJ301@shadowen.org","threadId":"10730","inReplyTo":"7vsl3frxpk.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH] tests: git push mirror mode tests V2","fromName":"Andy Whitcroft","fromEmail":"apw@shadowen.org","sentAt":"2007-11-12T15:25:41Z","receivedAt":"2007-11-12T15:25:41Z","isPatch":true,"sender":{"key":"apw@shadowen.org","avatar":"https://gravatar.com/avatar/d3088262854661a913ef35cc40fedcc270142d4461791142bc1ea0b2a4e2e147?d=mp&s=160"},"body":"On Fri, Nov 09, 2007 at 12:05:43PM -0800, Junio C Hamano wrote:\n> Andy Whitcroft <apw@shadowen.org> writes:\n> \n> > +test_expect_success 'push mirror does not create new branches' '\n> > +\n> > +\tmk_repo_pair &&\n> > +\t(\n> > +\t\tcd master &&\n> > +\t\techo one >foo && git add foo && git commit -m one &&\n> > +\t\tgit push --mirror up\n> > +\t) &&\n> > +\tmaster_master=$(cd master && git show-ref -s --verify refs/heads/master) &&\n> > +\tmirror_master=$(cd mirror && git show-ref -s --verify refs/heads/master) &&\n> > +\ttest \"$master_master\" = \"$mirror_master\"\n> > +\n> > +'\n> \n> I am quite puzzled by this and many other \"does not\" in the test\n> description.  The --mirror option is advertised as\n> \n>  - newly created will be pushed;\n>  - locally updated will be force pushed;\n>  - locally deleted will be removed.\n> \n> which makes sense as we do want these things to happen for\n> \"mirrors\".  Indeed the above updates master branch at the master\n> repository and makes sure that change is propagated to the\n> mirror repository.  The description should read \"push mirror\n> creates new branches\" shouldn't it?\n\nIndeed, I think the problem was a miss-understanding of the example I\ncopied from.  I think partly I thought that the message was only\ndisplayed on failure.  Which is firstly demonstrably false, and secondly\nI am not consistent in applying that false knowledge.\n\nIf these are not already fixed up in pu I will check and sort them out.\n\n-apw\n"}]}