git push mirror mode
Ok, sometime back Junio sent out a proof-of-concept change to send-pack allowing a mirror mode. That patch seemed to interact badly dropping refs in the .git directorty and I did not have time to fix it up.
I've just rebased it to the latest next, and updated my follow up patch to make this available as 'git push --mirror <remote>'. I have only tested this lightly.
-apw
PATCH 1/2 mirror pushing
From: Junio C Hamano <[email protected]>
Existing "git push --all" is almost perfect for backing up to another repository, except that "--all" only means "all branches" in modern git, and it does not delete old branches and tags that exist at the back-up repository that you have removed from your local repository.
This teaches "git-send-pack" a new "--mirror" option. The difference from the "--all" option are that (1) it sends all refs, not just branches, and (2) it deletes old refs you no longer have on the local side from the remote side.
--- builtin-send-pack.c | 40 ++++++++++++++++++++++++++++------------ remote.c | 15 ++++++++++----- send-pack.h | 1 + 3 files changed, 39 insertions(+), 17 deletions(-)
builtin-send-pack.c +28 -12
@@ -8,7 +8,7 @@#include "send-pack.h" static const char send_pack_usage[] = -"git-send-pack [--all] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n" +"git-send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n" " --all and explicit <ref> specification are mutually exclusive." ;static struct send_pack_args args = {
@@ -242,7 +242,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *destif (!remote_tail) remote_tail = &remote_refs;if (match_refs (local_refs, remote_refs, &remote_tail, - nr_refspec, refspec, args.send_all)) + nr_refspec, refspec, args.send_all | (args.send_mirror <<1 )))return -1 ;if (!remote_refs) {
@@ -259,20 +259,28 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *destchar old_hex[60 ], *new_hex;int will_delete_ref;const char *pretty_ref; -const char *pretty_peer; +const char *pretty_peer =NULL ;/* only used when not deleting */ +const unsigned char *new_sha1; -if (!ref->peer_ref) -continue ; +if (!ref->peer_ref) { +if (!args.send_mirror) +continue ; + new_sha1 = null_sha1; + } +else + new_sha1 = ref->peer_ref->new_sha1;if (!shown_dest) {fprintf (stderr,"To %s\n" , dest); shown_dest =1 ; } + will_delete_ref =is_null_sha1 (new_sha1); + pretty_ref =prettify_ref (ref->name); - pretty_peer =prettify_ref (ref->peer_ref->name); +if (!will_delete_ref) + pretty_peer =prettify_ref (ref->peer_ref->name); - will_delete_ref =is_null_sha1 (ref->peer_ref->new_sha1);if (will_delete_ref && !allow_deleting_refs) {fprintf (stderr," ! %-*s %s (remote does not support deleting refs)\n" ,SUMMARY_WIDTH ,"[rejected]" , pretty_ref);
@@ -280,7 +288,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *destcontinue ; }if (!will_delete_ref && - !hashcmp (ref->old_sha1, ref->peer_ref->new_sha1)) { + !hashcmp (ref->old_sha1, new_sha1)) {if (args.verbose) fprintf(stderr, " = %-*s %s -> %s\n", SUMMARY_WIDTH, "[up to date]",
@@ -312,8 +320,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest !is_null_sha1(ref->old_sha1) && !ref->force) {if (!has_sha1_file (ref->old_sha1) || - !ref_newer (ref->peer_ref->new_sha1, - ref->old_sha1)) { + !ref_newer (new_sha1, ref->old_sha1)) {/* We do not have the remote ref, or * we know that the remote ref is not * an ancestor of what we are trying to
@@ -328,7 +335,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *destcontinue ; } } -hashcpy (ref->new_sha1, ref->peer_ref->new_sha1); +hashcpy (ref->new_sha1, new_sha1);if (!will_delete_ref) new_refs++;strcpy (old_hex,sha1_to_hex (ref->old_sha1));
@@ -459,6 +466,10 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) args.dry_run =1 ;continue ; } +if (!strcmp (arg,"--mirror" )) { + args.send_mirror =1 ; +continue ; + }if (!strcmp (arg,"--force" )) { args.force_update =1 ;continue ;
@@ -483,7 +494,12 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) }if (!dest)usage (send_pack_usage); -if (heads && args.send_all) +/* +* --all and --mirror are incompatible; neither makes sense +* with any refspecs. +*/ +if ((heads && (args.send_all || args.send_mirror)) || + (args.send_all && args.send_mirror))usage (send_pack_usage);if (remote_name) {
remote.c +10 -5
@@ -722,10 +722,12 @@ static const struct refspec *check_pattern_match(const struct refspec *rs,* without thinking. */ int match_refs (struct ref *src,struct ref *dst,struct ref ***dst_tail, -int nr_refspec,const char **refspec,int all) +int nr_refspec,const char **refspec,int flags) {struct refspec *rs =parse_ref_spec (nr_refspec, (const char **) refspec); +int send_all = flags &01 ; +int send_mirror = flags &02 ;if (match_explicit_refs (src, dst, dst_tail, rs, nr_refspec))return -1 ;
@@ -742,7 +744,7 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,if (!pat)continue ; } -else if (prefixcmp (src->name,"refs/heads/" )) +else if (!send_mirror &&prefixcmp (src->name,"refs/heads/" ))/* * "matching refs"; traditionally we pushed everything * including refs outside refs/heads/ hierarchy, but
@@ -763,10 +765,13 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,if (dst_peer && dst_peer->peer_ref)/* We're already sending something to this ref. */ goto free_name; -if (!dst_peer && !nr_refspec && !all) -/* Remote doesn't have it, and we have no + +if (!dst_peer && !nr_refspec && !(send_all || send_mirror)) +/* +* Remote doesn't have it, and we have no * explicit pattern, and we don't have -* --all. */ +* --all nor --mirror. +*/ goto free_name;if (!dst_peer) {/* Create a new one and link it */
send-pack.h +1 -0
@@ -5,6 +5,7 @@ struct send_pack_args {const char *receivepack; unsigned verbose:1, send_all:1, + send_mirror:1, force_update:1, use_thin_pack:1, dry_run:1;
Re: [PATCH 1/2] mirror pushing
Hi,
builtin-send-pack.c static int do_send_pack(int in, int out, struct remote *remote, const char *dest · line 245
Quoted 2 lines · Andy Whitcroft
builtin-send-pack.c +1
-1- nr_refspec, refspec, args.send_all)) + nr_refspec, refspec, args.send_all | (args.send_mirror << 1)))
This line is too long. But it needsmore love: it's all too magic to have a 1 for send_all, and a 2 for mirror. Please introduce an enum for that in remote.h, and use those constants, so that this hunk and the following one cannot get out of sync that easily.
Quoted 5 lines
+++
b/remote.cremote.c +0
-0@@ -722,10 +722,12 @@ static const struct refspec *check_pattern_match(const struct refspec *rs,* without thinking. */ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
remote.c static const struct refspec *check_pattern_match(const struct refspec *rs, · line 733
Quoted 10 lines
remote.c +3
-1- int nr_refspec, const char **refspec, int all) + int nr_refspec, const char **refspec, int flags) { struct refspec *rs =parse_ref_spec (nr_refspec, (const char **) refspec); +int send_all = flags &01 ; +int send_mirror = flags &02 ;if (match_explicit_refs (src, dst, dst_tail, rs, nr_refspec))return -1 ;
Thanks,
Dscho
PATCH 1/2 mirror pushing
In reply to Andy WhitcroftExisting "git push --all" is almost perfect for backing up to another repository, except that "--all" only means "all branches" in modern git, and it does not delete old branches and tags that exist at the back-up repository that you have removed from your local repository.
This teaches "git-send-pack" a new "--mirror" option. The difference from the "--all" option are that (1) it sends all refs, not just branches, and (2) it deletes old refs you no longer have on the local side from the remote side.
--- builtin-send-pack.c | 40 ++++++++++++++++++++++++++++------------ remote.c | 15 ++++++++++----- send-pack.h | 1 + 3 files changed, 39 insertions(+), 17 deletions(-)
builtin-send-pack.c +28 -12
@@ -8,7 +8,7 @@#include "send-pack.h" static const char send_pack_usage[] = -"git-send-pack [--all] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n" +"git-send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n" " --all and explicit <ref> specification are mutually exclusive." ;static struct send_pack_args args = {
@@ -242,7 +242,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *destif (!remote_tail) remote_tail = &remote_refs;if (match_refs (local_refs, remote_refs, &remote_tail, - nr_refspec, refspec, args.send_all)) + nr_refspec, refspec, args.send_all | (args.send_mirror <<1 )))return -1 ;if (!remote_refs) {
@@ -259,20 +259,28 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *destchar old_hex[60 ], *new_hex;int will_delete_ref;const char *pretty_ref; -const char *pretty_peer; +const char *pretty_peer =NULL ;/* only used when not deleting */ +const unsigned char *new_sha1; -if (!ref->peer_ref) -continue ; +if (!ref->peer_ref) { +if (!args.send_mirror) +continue ; + new_sha1 = null_sha1; + } +else + new_sha1 = ref->peer_ref->new_sha1;if (!shown_dest) {fprintf (stderr,"To %s\n" , dest); shown_dest =1 ; } + will_delete_ref =is_null_sha1 (new_sha1); + pretty_ref =prettify_ref (ref->name); - pretty_peer =prettify_ref (ref->peer_ref->name); +if (!will_delete_ref) + pretty_peer =prettify_ref (ref->peer_ref->name); - will_delete_ref =is_null_sha1 (ref->peer_ref->new_sha1);if (will_delete_ref && !allow_deleting_refs) {fprintf (stderr," ! %-*s %s (remote does not support deleting refs)\n" ,SUMMARY_WIDTH ,"[rejected]" , pretty_ref);
@@ -280,7 +288,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *destcontinue ; }if (!will_delete_ref && - !hashcmp (ref->old_sha1, ref->peer_ref->new_sha1)) { + !hashcmp (ref->old_sha1, new_sha1)) {if (args.verbose) fprintf(stderr, " = %-*s %s -> %s\n", SUMMARY_WIDTH, "[up to date]",
@@ -312,8 +320,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest !is_null_sha1(ref->old_sha1) && !ref->force) {if (!has_sha1_file (ref->old_sha1) || - !ref_newer (ref->peer_ref->new_sha1, - ref->old_sha1)) { + !ref_newer (new_sha1, ref->old_sha1)) {/* We do not have the remote ref, or * we know that the remote ref is not * an ancestor of what we are trying to
@@ -328,7 +335,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *destcontinue ; } } -hashcpy (ref->new_sha1, ref->peer_ref->new_sha1); +hashcpy (ref->new_sha1, new_sha1);if (!will_delete_ref) new_refs++;strcpy (old_hex,sha1_to_hex (ref->old_sha1));
@@ -459,6 +466,10 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) args.dry_run =1 ;continue ; } +if (!strcmp (arg,"--mirror" )) { + args.send_mirror =1 ; +continue ; + }if (!strcmp (arg,"--force" )) { args.force_update =1 ;continue ;
@@ -483,7 +494,12 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) }if (!dest)usage (send_pack_usage); -if (heads && args.send_all) +/* +* --all and --mirror are incompatible; neither makes sense +* with any refspecs. +*/ +if ((heads && (args.send_all || args.send_mirror)) || + (args.send_all && args.send_mirror))usage (send_pack_usage);if (remote_name) {
remote.c +10 -5
@@ -722,10 +722,12 @@ static const struct refspec *check_pattern_match(const struct refspec *rs,* without thinking. */ int match_refs (struct ref *src,struct ref *dst,struct ref ***dst_tail, -int nr_refspec,const char **refspec,int all) +int nr_refspec,const char **refspec,int flags) {struct refspec *rs =parse_ref_spec (nr_refspec, (const char **) refspec); +int send_all = flags &01 ; +int send_mirror = flags &02 ;if (match_explicit_refs (src, dst, dst_tail, rs, nr_refspec))return -1 ;
@@ -742,7 +744,7 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,if (!pat)continue ; } -else if (prefixcmp (src->name,"refs/heads/" )) +else if (!send_mirror &&prefixcmp (src->name,"refs/heads/" ))/* * "matching refs"; traditionally we pushed everything * including refs outside refs/heads/ hierarchy, but
@@ -763,10 +765,13 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,if (dst_peer && dst_peer->peer_ref)/* We're already sending something to this ref. */ goto free_name; -if (!dst_peer && !nr_refspec && !all) -/* Remote doesn't have it, and we have no + +if (!dst_peer && !nr_refspec && !(send_all || send_mirror)) +/* +* Remote doesn't have it, and we have no * explicit pattern, and we don't have -* --all. */ +* --all nor --mirror. +*/ goto free_name;if (!dst_peer) {/* Create a new one and link it */
send-pack.h +1 -0
@@ -5,6 +5,7 @@ struct send_pack_args {const char *receivepack; unsigned verbose:1, send_all:1, + send_mirror:1, force_update:1, use_thin_pack:1, dry_run:1;
PATCH 2/2 git-push: plumb in --mirror mode
In reply to Andy WhitcroftPlumb in the --mirror mode for git-push.
--- builtin-push.c | 14 ++++++++++++-- transport.c | 7 +++++++ transport.h | 1 + 3 files changed, 20 insertions(+), 2 deletions(-)
builtin-push.c +12 -2
@@ -10,7 +10,7 @@#include "parse-options.h" static const char *const push_usage[] = { -"git-push [--all] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]" , +"git-push [--all | --mirror] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]" ,NULL , };
@@ -91,6 +91,7 @@ int cmd_push(int argc, const char **argv, const char *prefix) {int flags =0 ;int all =0 ; +int mirror =0 ;int dry_run =0 ;int force =0 ;int tags =0 ;
@@ -100,6 +101,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)OPT__VERBOSE (&verbose),OPT_STRING (0 ,"repo" , &repo,"repository" ,"repository" ),OPT_BOOLEAN (0 ,"all" , &all,"push all refs" ), +OPT_BOOLEAN (0 ,"mirror" , &mirror,"mirror all refs" ),OPT_BOOLEAN (0 ,"tags" , &tags,"push tags" ),OPT_BOOLEAN (0 ,"dry-run" , &dry_run,"dry run" ), OPT_BOOLEAN('f', "force", &force, "force updates"),
@@ -119,13 +121,21 @@ int cmd_push(int argc, const char **argv, const char *prefix)add_refspec ("refs/tags/*" );if (all) flags |=TRANSPORT_PUSH_ALL ; +if (mirror) + flags |= (TRANSPORT_PUSH_MIRROR |TRANSPORT_PUSH_FORCE );if (argc >0 ) { repo = argv[0 ];set_refspecs (argv +1 , argc -1 ); } -if ((flags &TRANSPORT_PUSH_ALL ) && refspec) +if ((flags & (TRANSPORT_PUSH_ALL |TRANSPORT_PUSH_MIRROR )) && refspec)usage_with_options (push_usage, options); +if ((flags & (TRANSPORT_PUSH_ALL |TRANSPORT_PUSH_MIRROR )) == + (TRANSPORT_PUSH_ALL |TRANSPORT_PUSH_MIRROR )) { +error ("--all and --mirror are incompatible" ); +usage_with_options (push_usage, options); + } +return do_push (repo, flags); }
transport.c +7 -0
@@ -284,6 +284,9 @@ static int rsync_transport_push(struct transport *transport,struct child_process rsync;const char *args[10 ]; +if (flags &TRANSPORT_PUSH_MIRROR ) +return error ("rsync transport does not support mirror mode" ); +/* first push the objects */ strbuf_addstr (&buf, transport->url);
@@ -386,6 +389,9 @@ static int curl_transport_push(struct transport *transport, int refspec_nr, consint argc;int err; +if (flags &TRANSPORT_PUSH_MIRROR ) +return error ("http transport does not support mirror mode" ); + argv =xmalloc ((refspec_nr +11 ) *sizeof (char *)); argv[0 ] ="http-push" ; argc =1 ;
@@ -653,6 +659,7 @@ static int git_transport_push(struct transport *transport, int refspec_nr, const args.receivepack = data->receivepack; args.send_all = !!(flags &TRANSPORT_PUSH_ALL ); + args.send_mirror = !!(flags &TRANSPORT_PUSH_MIRROR ); args.force_update = !!(flags &TRANSPORT_PUSH_FORCE ); args.use_thin_pack = data->thin; args.verbose = transport->verbose;
transport.h +1 -0
@@ -30,6 +30,7 @@ struct transport {#define TRANSPORT_PUSH_ALL 1#define TRANSPORT_PUSH_FORCE 2#define TRANSPORT_PUSH_DRY_RUN 4 +#define TRANSPORT_PUSH_MIRROR 8/* Returns a transport suitable for the url */ struct transport *transport_get (struct remote *,const char *);
git push mirror mode V3
In reply to Andy WhitcroftOk, here is an update based on feedback from the list. I bit the bullet and added some basic tests. The stack passes the test suite. Hopefully the attribution is ok on the first patch now. I have kept my modifications to it a separate patch for the time being to keep attribution simple.
-apw
PATCH 1/4 mirror pushing
From: Junio C Hamano <[email protected]>
Existing "git push --all" is almost perfect for backing up to another repository, except that "--all" only means "all branches" in modern git, and it does not delete old branches and tags that exist at the back-up repository that you have removed from your local repository.
This teaches "git-send-pack" a new "--mirror" option. The difference from the "--all" option are that (1) it sends all refs, not just branches, and (2) it deletes old refs you no longer have on the local side from the remote side.
--- builtin-send-pack.c | 40 ++++++++++++++++++++++++++++------------ remote.c | 15 ++++++++++----- send-pack.h | 1 + 3 files changed, 39 insertions(+), 17 deletions(-)
builtin-send-pack.c +28 -12
@@ -8,7 +8,7 @@#include "send-pack.h" static const char send_pack_usage[] = -"git-send-pack [--all] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n" +"git-send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n" " --all and explicit <ref> specification are mutually exclusive." ;static struct send_pack_args args = {
@@ -242,7 +242,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *destif (!remote_tail) remote_tail = &remote_refs;if (match_refs (local_refs, remote_refs, &remote_tail, - nr_refspec, refspec, args.send_all)) + nr_refspec, refspec, args.send_all | (args.send_mirror <<1 )))return -1 ;if (!remote_refs) {
@@ -259,20 +259,28 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *destchar old_hex[60 ], *new_hex;int will_delete_ref;const char *pretty_ref; -const char *pretty_peer; +const char *pretty_peer =NULL ;/* only used when not deleting */ +const unsigned char *new_sha1; -if (!ref->peer_ref) -continue ; +if (!ref->peer_ref) { +if (!args.send_mirror) +continue ; + new_sha1 = null_sha1; + } +else + new_sha1 = ref->peer_ref->new_sha1;if (!shown_dest) {fprintf (stderr,"To %s\n" , dest); shown_dest =1 ; } + will_delete_ref =is_null_sha1 (new_sha1); + pretty_ref =prettify_ref (ref->name); - pretty_peer =prettify_ref (ref->peer_ref->name); +if (!will_delete_ref) + pretty_peer =prettify_ref (ref->peer_ref->name); - will_delete_ref =is_null_sha1 (ref->peer_ref->new_sha1);if (will_delete_ref && !allow_deleting_refs) {fprintf (stderr," ! %-*s %s (remote does not support deleting refs)\n" ,SUMMARY_WIDTH ,"[rejected]" , pretty_ref);
@@ -280,7 +288,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *destcontinue ; }if (!will_delete_ref && - !hashcmp (ref->old_sha1, ref->peer_ref->new_sha1)) { + !hashcmp (ref->old_sha1, new_sha1)) {if (args.verbose) fprintf(stderr, " = %-*s %s -> %s\n", SUMMARY_WIDTH, "[up to date]",
@@ -312,8 +320,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest !is_null_sha1(ref->old_sha1) && !ref->force) {if (!has_sha1_file (ref->old_sha1) || - !ref_newer (ref->peer_ref->new_sha1, - ref->old_sha1)) { + !ref_newer (new_sha1, ref->old_sha1)) {/* We do not have the remote ref, or * we know that the remote ref is not * an ancestor of what we are trying to
@@ -328,7 +335,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *destcontinue ; } } -hashcpy (ref->new_sha1, ref->peer_ref->new_sha1); +hashcpy (ref->new_sha1, new_sha1);if (!will_delete_ref) new_refs++;strcpy (old_hex,sha1_to_hex (ref->old_sha1));
@@ -459,6 +466,10 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) args.dry_run =1 ;continue ; } +if (!strcmp (arg,"--mirror" )) { + args.send_mirror =1 ; +continue ; + }if (!strcmp (arg,"--force" )) { args.force_update =1 ;continue ;
@@ -483,7 +494,12 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) }if (!dest)usage (send_pack_usage); -if (heads && args.send_all) +/* +* --all and --mirror are incompatible; neither makes sense +* with any refspecs. +*/ +if ((heads && (args.send_all || args.send_mirror)) || + (args.send_all && args.send_mirror))usage (send_pack_usage);if (remote_name) {
remote.c +10 -5
@@ -722,10 +722,12 @@ static const struct refspec *check_pattern_match(const struct refspec *rs,* without thinking. */ int match_refs (struct ref *src,struct ref *dst,struct ref ***dst_tail, -int nr_refspec,const char **refspec,int all) +int nr_refspec,const char **refspec,int flags) {struct refspec *rs =parse_ref_spec (nr_refspec, (const char **) refspec); +int send_all = flags &01 ; +int send_mirror = flags &02 ;if (match_explicit_refs (src, dst, dst_tail, rs, nr_refspec))return -1 ;
@@ -742,7 +744,7 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,if (!pat)continue ; } -else if (prefixcmp (src->name,"refs/heads/" )) +else if (!send_mirror &&prefixcmp (src->name,"refs/heads/" ))/* * "matching refs"; traditionally we pushed everything * including refs outside refs/heads/ hierarchy, but
@@ -763,10 +765,13 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,if (dst_peer && dst_peer->peer_ref)/* We're already sending something to this ref. */ goto free_name; -if (!dst_peer && !nr_refspec && !all) -/* Remote doesn't have it, and we have no + +if (!dst_peer && !nr_refspec && !(send_all || send_mirror)) +/* +* Remote doesn't have it, and we have no * explicit pattern, and we don't have -* --all. */ +* --all nor --mirror. +*/ goto free_name;if (!dst_peer) {/* Create a new one and link it */
send-pack.h +1 -0
@@ -5,6 +5,7 @@ struct send_pack_args {const char *receivepack; unsigned verbose:1, send_all:1, + send_mirror:1, force_update:1, use_thin_pack:1, dry_run:1;
PATCH 2/4 mirror pushing -- clean up match_refs flags
In reply to Andy WhitcroftAdd a new enum to define the match_refs flags field and switch all callers to it.
--- builtin-send-pack.c | 8 +++++++- http-push.c | 4 ++-- remote.c | 4 ++-- remote.h | 7 +++++++ 4 files changed, 18 insertions(+), 5 deletions(-)
builtin-send-pack.c +7 -1
@@ -227,6 +227,12 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *destint allow_deleting_refs =0 ;int expect_status_report =0 ;int shown_dest =0 ; +int flags =MATCH_REFS_NONE ; + +if (args.send_all) + flags |=MATCH_REFS_ALL ; +if (args.send_mirror) + flags |=MATCH_REFS_MIRROR ;/* No funny business with the matcher */ remote_tail =get_remote_heads (in, &remote_refs,0 ,NULL ,REF_NORMAL );
@@ -242,7 +248,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *destif (!remote_tail) remote_tail = &remote_refs;if (match_refs (local_refs, remote_refs, &remote_tail, - nr_refspec, refspec, args.send_all | (args.send_mirror <<1 ))) + nr_refspec, refspec, flags))return -1 ;if (!remote_refs) {
http-push.c +2 -2
@@ -78,7 +78,7 @@ static struct curl_slist *no_pragma_header;static struct curl_slist *default_headers;static int push_verbosely; -static int push_all; +static int push_all =MATCH_REFS_NONE ;static int force_all;static int dry_run;
@@ -2300,7 +2300,7 @@ int main(int argc, char **argv)if (*arg =='-' ) {if (!strcmp (arg,"--all" )) { - push_all =1 ; + push_all =MATCH_REFS_ALL ;continue ; }if (!strcmp (arg,"--force" )) {
remote.c +2 -2
@@ -726,8 +726,8 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail, {struct refspec *rs =parse_ref_spec (nr_refspec, (const char **) refspec); -int send_all = flags &01 ; -int send_mirror = flags &02 ; +int send_all = flags &MATCH_REFS_ALL ; +int send_mirror = flags &MATCH_REFS_MIRROR ;if (match_explicit_refs (src, dst, dst_tail, rs, nr_refspec))return -1 ;
remote.h +7 -0
@@ -102,4 +102,11 @@ struct branch *branch_get(const char *name);int branch_has_merge_config (struct branch *branch);int branch_merge_matches (struct branch *,int n,const char *); +/* Flags to match_refs. */ +enum match_refs_flags { +MATCH_REFS_NONE =0 , +MATCH_REFS_ALL = (1 <<0 ), +MATCH_REFS_MIRROR = (1 <<1 ), +}; +#endif
PATCH 3/4 git-push: plumb in --mirror mode
In reply to Andy WhitcroftPlumb in the --mirror mode for git-push.
--- builtin-push.c | 14 ++++++++++++-- transport.c | 7 +++++++ transport.h | 1 + 3 files changed, 20 insertions(+), 2 deletions(-)
builtin-push.c +12 -2
@@ -10,7 +10,7 @@#include "parse-options.h" static const char *const push_usage[] = { -"git-push [--all] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]" , +"git-push [--all | --mirror] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]" ,NULL , };
@@ -91,6 +91,7 @@ int cmd_push(int argc, const char **argv, const char *prefix) {int flags =0 ;int all =0 ; +int mirror =0 ;int dry_run =0 ;int force =0 ;int tags =0 ;
@@ -100,6 +101,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)OPT__VERBOSE (&verbose),OPT_STRING (0 ,"repo" , &repo,"repository" ,"repository" ),OPT_BOOLEAN (0 ,"all" , &all,"push all refs" ), +OPT_BOOLEAN (0 ,"mirror" , &mirror,"mirror all refs" ),OPT_BOOLEAN (0 ,"tags" , &tags,"push tags" ),OPT_BOOLEAN (0 ,"dry-run" , &dry_run,"dry run" ), OPT_BOOLEAN('f', "force", &force, "force updates"),
@@ -119,13 +121,21 @@ int cmd_push(int argc, const char **argv, const char *prefix)add_refspec ("refs/tags/*" );if (all) flags |=TRANSPORT_PUSH_ALL ; +if (mirror) + flags |= (TRANSPORT_PUSH_MIRROR |TRANSPORT_PUSH_FORCE );if (argc >0 ) { repo = argv[0 ];set_refspecs (argv +1 , argc -1 ); } -if ((flags &TRANSPORT_PUSH_ALL ) && refspec) +if ((flags & (TRANSPORT_PUSH_ALL |TRANSPORT_PUSH_MIRROR )) && refspec)usage_with_options (push_usage, options); +if ((flags & (TRANSPORT_PUSH_ALL |TRANSPORT_PUSH_MIRROR )) == + (TRANSPORT_PUSH_ALL |TRANSPORT_PUSH_MIRROR )) { +error ("--all and --mirror are incompatible" ); +usage_with_options (push_usage, options); + } +return do_push (repo, flags); }
transport.c +7 -0
@@ -284,6 +284,9 @@ static int rsync_transport_push(struct transport *transport,struct child_process rsync;const char *args[10 ]; +if (flags &TRANSPORT_PUSH_MIRROR ) +return error ("rsync transport does not support mirror mode" ); +/* first push the objects */ strbuf_addstr (&buf, transport->url);
@@ -386,6 +389,9 @@ static int curl_transport_push(struct transport *transport, int refspec_nr, consint argc;int err; +if (flags &TRANSPORT_PUSH_MIRROR ) +return error ("http transport does not support mirror mode" ); + argv =xmalloc ((refspec_nr +11 ) *sizeof (char *)); argv[0 ] ="http-push" ; argc =1 ;
@@ -653,6 +659,7 @@ static int git_transport_push(struct transport *transport, int refspec_nr, const args.receivepack = data->receivepack; args.send_all = !!(flags &TRANSPORT_PUSH_ALL ); + args.send_mirror = !!(flags &TRANSPORT_PUSH_MIRROR ); args.force_update = !!(flags &TRANSPORT_PUSH_FORCE ); args.use_thin_pack = data->thin; args.verbose = transport->verbose;
transport.h +1 -0
@@ -30,6 +30,7 @@ struct transport {#define TRANSPORT_PUSH_ALL 1#define TRANSPORT_PUSH_FORCE 2#define TRANSPORT_PUSH_DRY_RUN 4 +#define TRANSPORT_PUSH_MIRROR 8/* Returns a transport suitable for the url */ struct transport *transport_get (struct remote *,const char *);
PATCH 4/4 tests: git push mirror mode tests
In reply to Andy WhitcroftAdd some basic tests for git push --mirror mode.
--- t/t5517-push-mirror.sh | 101 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 101 insertions(+), 0 deletions(-)
t/t5517-push-mirror.sh new file +101 -0
@@ -0,0 +1,101 @@ +#!/bin/sh + +test_description='pushing to a mirror repository' + +. ./test-lib.sh + +D=`pwd` + +mk_repo_pair () { + rm -rf master mirror && + mkdir mirror && cd mirror && + git init && + cd .. && + mkdir master && cd master && + git init && + git config remote.up.url ../mirror && + cd .. +} + +test_expect_success 'push mirror does not create new branches' ' + + mk_repo_pair && + cd master && + echo one >foo && git add foo && git commit -m one && + master_master=$(git show-ref -s --verify refs/heads/master) && + git push --mirror up && + cd ../mirror && + mirror_master=$(git show-ref -s --verify refs/heads/master) && + test "$master_master" = "$mirror_master" + +' + +test_expect_success 'push mirror does not update existing branches' ' + + mk_repo_pair && + cd master && + echo one >foo && git add foo && git commit -m one && + git push --mirror up && + echo two >foo && git add foo && git commit -m two && + master_master=$(git show-ref -s --verify refs/heads/master) && + git push --mirror up && + cd ../mirror && + mirror_master=$(git show-ref -s --verify refs/heads/master) && + test "$master_master" = "$mirror_master" + +' + +test_expect_success 'push mirror does not force update existing branches' ' + + mk_repo_pair && + cd master && + echo one >foo && git add foo && git commit -m one && + git push --mirror up && + echo two >foo && git add foo && git commit -m two && + git push --mirror up && + git reset --hard HEAD^ + master_master=$(git show-ref -s --verify refs/heads/master) && + git push --mirror up && + cd ../mirror && + mirror_master=$(git show-ref -s --verify refs/heads/master) && + test "$master_master" = "$mirror_master" + +' + +test_expect_failure 'push mirror does not remove branches' ' + + mk_repo_pair && + cd master && + echo one >foo && git add foo && git commit -m one && + git branch remove master && + git push --mirror up && + git branch -D remove + git push --mirror up && + cd ../mirror && + git show-ref -s --verify refs/heads/remove + +' + +test_expect_success 'push mirror does not add, update and remove together' ' + + mk_repo_pair && + cd master && + echo one >foo && git add foo && git commit -m one && + git branch remove master && + git push --mirror up && + git branch -D remove && + git branch add master && + echo two >foo && git add foo && git commit -m two && + master_master=$(git show-ref -s --verify refs/heads/master) && + master_add=$(git show-ref -s --verify refs/heads/add) && + git push --mirror up && + cd ../mirror && + mirror_master=$(git show-ref -s --verify refs/heads/master) && + mirror_add=$(git show-ref -s --verify refs/heads/add) && + test "$master_master" = "$mirror_master" && + test "$master_add" = "$mirror_add" && + ! git show-ref -s --verify refs/heads/remove + +' + +test_done
PATCH 1/1 tests: git push mirror mode tests V2
Add some basic tests for git push --mirror mode.
---
Following the discussion on how tests which change directory should use subshells to prevent loss of CWD and of how ! is not something we can rely on, here is an updates to the tests.
--- t/t5517-push-mirror.sh | 125 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 125 insertions(+), 0 deletions(-)
t/t5517-push-mirror.sh new file +125 -0
@@ -0,0 +1,125 @@ +#!/bin/sh + +test_description='pushing to a mirror repository' + +. ./test-lib.sh + +D=`pwd` + +invert () { + if "$@"; then + return 1 + else + return 0 + fi +} + +mk_repo_pair () { + rm -rf master mirror && + mkdir mirror && + ( + cd mirror && + git init + ) && + mkdir master && + ( + cd master && + git init && + git config remote.up.url ../mirror + ) +} + + +test_expect_success 'push mirror does not create new branches' ' + + mk_repo_pair && + ( + cd master && + echo one >foo && git add foo && git commit -m one && + git push --mirror up + ) && + master_master=$(cd master && git show-ref -s --verify refs/heads/master) && + mirror_master=$(cd mirror && git show-ref -s --verify refs/heads/master) && + test "$master_master" = "$mirror_master" + +' + +test_expect_success 'push mirror does not update existing branches' ' + + mk_repo_pair && + ( + cd master && + echo one >foo && git add foo && git commit -m one && + git push --mirror up && + echo two >foo && git add foo && git commit -m two && + git push --mirror up + ) && + master_master=$(cd master && git show-ref -s --verify refs/heads/master) && + mirror_master=$(cd mirror && git show-ref -s --verify refs/heads/master) && + test "$master_master" = "$mirror_master" + +' + +test_expect_success 'push mirror does not force update existing branches' ' + + mk_repo_pair && + ( + cd master && + echo one >foo && git add foo && git commit -m one && + git push --mirror up && + echo two >foo && git add foo && git commit -m two && + git push --mirror up && + git reset --hard HEAD^ + git push --mirror up + ) && + master_master=$(cd master && git show-ref -s --verify refs/heads/master) && + mirror_master=$(cd mirror && git show-ref -s --verify refs/heads/master) && + test "$master_master" = "$mirror_master" + +' + +test_expect_success 'push mirror does not remove branches' ' + + mk_repo_pair && + ( + cd master && + echo one >foo && git add foo && git commit -m one && + git branch remove master && + git push --mirror up && + git branch -D remove + git push --mirror up + ) && + ( + cd mirror && + invert git show-ref -s --verify refs/heads/remove + ) + +' + +test_expect_success 'push mirror does not add, update and remove together' ' + + mk_repo_pair && + ( + cd master && + echo one >foo && git add foo && git commit -m one && + git branch remove master && + git push --mirror up && + git branch -D remove && + git branch add master && + echo two >foo && git add foo && git commit -m two && + git push --mirror up + ) && + master_master=$(cd master && git show-ref -s --verify refs/heads/master) && + master_add=$(cd master && git show-ref -s --verify refs/heads/add) && + mirror_master=$(cd mirror && git show-ref -s --verify refs/heads/master) && + mirror_add=$(cd mirror && git show-ref -s --verify refs/heads/add) && + test "$master_master" = "$mirror_master" && + test "$master_add" = "$mirror_add" && + ( + cd mirror && + invert git show-ref -s --verify refs/heads/remove + ) + +' + +test_done
PATCH 1/1 tests: git push mirror mode tests V2 -- add tag tests
Add additional tests to the the V2 tests testing the handling of tags in --mirror mode. We expect these to be tracked in line with the master.
---
Note that this patch is cumulative on top of the following patch:
tests: git push mirror mode tests V2
These two patches together replace the 4/4 from the original series.
--- t/t5517-push-mirror.sh | 105 +++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 104 insertions(+), 1 deletions(-)
t/t5517-push-mirror.sh +104 -1
@@ -30,6 +30,7 @@ mk_repo_pair () { } +# BRANCH tests test_expect_success 'push mirror does not create new branches' ' mk_repo_pair &&
@@ -96,7 +97,7 @@ test_expect_success 'push mirror does not remove branches' ' ' -test_expect_success 'push mirror does not add, update and remove together' ' +test_expect_success 'push mirror does not add, update and remove branches together' ' mk_repo_pair && (
@@ -122,4 +123,106 @@ test_expect_success 'push mirror does not add, update and remove together' ' ' + +# TAG tests +test_expect_success 'push mirror does not create new tags' ' + + mk_repo_pair && + ( + cd master && + echo one >foo && git add foo && git commit -m one && + git tag -f tmaster master && + git push --mirror up + ) && + master_master=$(cd master && git show-ref -s --verify refs/tags/tmaster) && + mirror_master=$(cd mirror && git show-ref -s --verify refs/tags/tmaster) && + test "$master_master" = "$mirror_master" + +' + +test_expect_success 'push mirror does not update existing tags' ' + + mk_repo_pair && + ( + cd master && + echo one >foo && git add foo && git commit -m one && + git tag -f tmaster master && + git push --mirror up && + echo two >foo && git add foo && git commit -m two && + git tag -f tmaster master && + git push --mirror up + ) && + master_master=$(cd master && git show-ref -s --verify refs/tags/tmaster) && + mirror_master=$(cd mirror && git show-ref -s --verify refs/tags/tmaster) && + test "$master_master" = "$mirror_master" + +' + +test_expect_success 'push mirror does not force update existing tags' ' + + mk_repo_pair && + ( + cd master && + echo one >foo && git add foo && git commit -m one && + git tag -f tmaster master && + git push --mirror up && + echo two >foo && git add foo && git commit -m two && + git tag -f tmaster master && + git push --mirror up && + git reset --hard HEAD^ + git tag -f tmaster master && + git push --mirror up + ) && + master_master=$(cd master && git show-ref -s --verify refs/tags/tmaster) && + mirror_master=$(cd mirror && git show-ref -s --verify refs/tags/tmaster) && + test "$master_master" = "$mirror_master" + +' + +test_expect_success 'push mirror does not remove tags' ' + + mk_repo_pair && + ( + cd master && + echo one >foo && git add foo && git commit -m one && + git tag -f tremove master && + git push --mirror up && + git tag -d tremove + git push --mirror up + ) && + ( + cd mirror && + invert git show-ref -s --verify refs/tags/tremove + ) + +' + +test_expect_success 'push mirror does not add, update and remove tags together' ' + + mk_repo_pair && + ( + cd master && + echo one >foo && git add foo && git commit -m one && + git tag -f tmaster master && + git tag -f tremove master && + git push --mirror up && + git tag -d tremove && + git tag tadd master && + echo two >foo && git add foo && git commit -m two && + git tag -f tmaster master && + git push --mirror up + ) && + master_master=$(cd master && git show-ref -s --verify refs/tags/tmaster) && + master_add=$(cd master && git show-ref -s --verify refs/tags/tadd) && + mirror_master=$(cd mirror && git show-ref -s --verify refs/tags/tmaster) && + mirror_add=$(cd mirror && git show-ref -s --verify refs/tags/tadd) && + test "$master_master" = "$mirror_master" && + test "$master_add" = "$mirror_add" && + ( + cd mirror && + invert git show-ref -s --verify refs/tags/tremove + ) + +' + test_done
PATCH 1/1 git-push: add documentation for the newly add --mirror mode
Add some basic documentation on the --mirror mode for git-push.
--- Documentation/git-push.txt | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-)
Documentation/git-push.txt +8 -0
@@ -62,6 +62,14 @@ the remote repository. \--all:: Instead of naming each ref to push, specifies that all refs under `$GIT_DIR/refs/heads/` be pushed. + +\--mirror:: + Instead of naming each ref to push, specifies that all + refs under `$GIT_DIR/refs/heads/` and `$GIT_DIR/refs/tags/` + be mirrored to the remote repository. Newly created local + refs will be pushed to the remote end, locally updated refs + will be force updated on the remote end, and deleted refs + will be removed from the remote end. \--dry-run:: Do everything except actually send the updates.
Re: [PATCH] tests: git push mirror mode tests V2
In reply to Andy Whitcroftt/t5517-push-mirror.sh line 45
Quoted 13 lines · Andy Whitcroft
t/t5517-push-mirror.sh new file +13
-0+test_expect_success 'push mirror does not create new branches' ' + + mk_repo_pair && + ( + cd master && + echo one >foo && git add foo && git commit -m one && + git push --mirror up + ) && + master_master=$(cd master && git show-ref -s --verify refs/heads/master) && + mirror_master=$(cd mirror && git show-ref -s --verify refs/heads/master) && + test "$master_master" = "$mirror_master" + +'
I am quite puzzled by this and many other "does not" in the test description. The --mirror option is advertised as
- newly created will be pushed;
- locally updated will be force pushed;
- locally deleted will be removed.
which makes sense as we do want these things to happen for "mirrors". Indeed the above updates master branch at the master repository and makes sure that change is propagated to the mirror repository. The description should read "push mirror creates new branches" shouldn't it?
Re: [PATCH] tests: git push mirror mode tests V2
Quoted 23 lines · Junio C Hamano
t/t5517-push-mirror.sh line 45
Quoted 13 lines · Andy Whitcroft
t/t5517-push-mirror.sh new file +13
-0+test_expect_success 'push mirror does not create new branches' ' + + mk_repo_pair && + ( + cd master && + echo one >foo && git add foo && git commit -m one && + git push --mirror up + ) && + master_master=$(cd master && git show-ref -s --verify refs/heads/master) && + mirror_master=$(cd mirror && git show-ref -s --verify refs/heads/master) && + test "$master_master" = "$mirror_master" + +'I am quite puzzled by this and many other "does not" in the test description. The --mirror option is advertised as
- newly created will be pushed;
- locally updated will be force pushed;
- locally deleted will be removed.
Quoted 5 lines
which makes sense as we do want these things to happen for "mirrors". Indeed the above updates master branch at the master repository and makes sure that change is propagated to the mirror repository. The description should read "push mirror creates new branches" shouldn't it?
Indeed, I think the problem was a miss-understanding of the example I copied from. I think partly I thought that the message was only displayed on failure. Which is firstly demonstrably false, and secondly I am not consistent in applying that false knowledge.
If these are not already fixed up in pu I will check and sort them out.
-apw
PATCH 2/2 git-push: plumb in --mirror mode
In reply to Andy WhitcroftPlumb in the --mirror mode for git-push.
--- builtin-push.c | 14 ++++++++++++-- transport.c | 7 +++++++ transport.h | 1 + 3 files changed, 20 insertions(+), 2 deletions(-)
builtin-push.c +12 -2
@@ -10,7 +10,7 @@#include "parse-options.h" static const char *const push_usage[] = { -"git-push [--all] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]" , +"git-push [--all | --mirror] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]" ,NULL , };
@@ -91,6 +91,7 @@ int cmd_push(int argc, const char **argv, const char *prefix) {int flags =0 ;int all =0 ; +int mirror =0 ;int dry_run =0 ;int force =0 ;int tags =0 ;
@@ -100,6 +101,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)OPT__VERBOSE (&verbose),OPT_STRING (0 ,"repo" , &repo,"repository" ,"repository" ),OPT_BOOLEAN (0 ,"all" , &all,"push all refs" ), +OPT_BOOLEAN (0 ,"mirror" , &mirror,"mirror all refs" ),OPT_BOOLEAN (0 ,"tags" , &tags,"push tags" ),OPT_BOOLEAN (0 ,"dry-run" , &dry_run,"dry run" ), OPT_BOOLEAN('f', "force", &force, "force updates"),
@@ -119,13 +121,21 @@ int cmd_push(int argc, const char **argv, const char *prefix)add_refspec ("refs/tags/*" );if (all) flags |=TRANSPORT_PUSH_ALL ; +if (mirror) + flags |= (TRANSPORT_PUSH_MIRROR |TRANSPORT_PUSH_FORCE );if (argc >0 ) { repo = argv[0 ];set_refspecs (argv +1 , argc -1 ); } -if ((flags &TRANSPORT_PUSH_ALL ) && refspec) +if ((flags & (TRANSPORT_PUSH_ALL |TRANSPORT_PUSH_MIRROR )) && refspec)usage_with_options (push_usage, options); +if ((flags & (TRANSPORT_PUSH_ALL |TRANSPORT_PUSH_MIRROR )) == + (TRANSPORT_PUSH_ALL |TRANSPORT_PUSH_MIRROR )) { +error ("--all and --mirror are incompatible" ); +usage_with_options (push_usage, options); + } +return do_push (repo, flags); }
transport.c +7 -0
@@ -284,6 +284,9 @@ static int rsync_transport_push(struct transport *transport,struct child_process rsync;const char *args[10 ]; +if (flags &TRANSPORT_PUSH_MIRROR ) +return error ("rsync transport does not support mirror mode" ); +/* first push the objects */ strbuf_addstr (&buf, transport->url);
@@ -386,6 +389,9 @@ static int curl_transport_push(struct transport *transport, int refspec_nr, consint argc;int err; +if (flags &TRANSPORT_PUSH_MIRROR ) +return error ("http transport does not support mirror mode" ); + argv =xmalloc ((refspec_nr +11 ) *sizeof (char *)); argv[0 ] ="http-push" ; argc =1 ;
@@ -653,6 +659,7 @@ static int git_transport_push(struct transport *transport, int refspec_nr, const args.receivepack = data->receivepack; args.send_all = !!(flags &TRANSPORT_PUSH_ALL ); + args.send_mirror = !!(flags &TRANSPORT_PUSH_MIRROR ); args.force_update = !!(flags &TRANSPORT_PUSH_FORCE ); args.use_thin_pack = data->thin; args.verbose = transport->verbose;
transport.h +1 -0
@@ -30,6 +30,7 @@ struct transport {#define TRANSPORT_PUSH_ALL 1#define TRANSPORT_PUSH_FORCE 2#define TRANSPORT_PUSH_DRY_RUN 4 +#define TRANSPORT_PUSH_MIRROR 8/* Returns a transport suitable for the url */ struct transport *transport_get (struct remote *,const char *);
Hi,
Quoted 2 lines · Andy Whitcroft
Ok, sometime back Junio sent out a proof-of-concept change to send-pack allowing a mirror mode.
You added/left his sign-off, but did not attribute the patches to him. Why?
Ciao,
Dscho
P.S.: Without tests I am opposed to inclusion. This _definitely_ needs some tests.
Quoted 9 lines · Johannes Schindelin
Hi,
Quoted 2 lines · Andy Whitcroft
Ok, sometime back Junio sent out a proof-of-concept change to send-pack allowing a mirror mode.
You added/left his sign-off, but did not attribute the patches to him. Why?
I believe I left his signed off by from the original (first) patch, and added mine to indicate that what I had modified was also unecombered. The second patch is only signed off by me as I am the author. In my world (admittedly a kernel hacker) the first Signed-off-by: indicates the primary authorship of that patch and the [apw@...] part tries to clarify the changes I made therein.
No intentional stripping of credit was intended, and I believe that the attribution as written states Junio is the originator of this patch. However that is the way I would read the meanings of these lines, if git has different rules or you think there is a clearer way of stating this I am happy to change it, and resend it so attributed.
-apw
Quoted 16 lines · Andy Whitcroft
Quoted 7 lines · Johannes Schindelin
Hi,
Quoted 2 lines · Andy Whitcroft
Ok, sometime back Junio sent out a proof-of-concept change to send-pack allowing a mirror mode.
You added/left his sign-off, but did not attribute the patches to him. Why?
I believe I left his signed off by from the original (first) patch, and added mine to indicate that what I had modified was also unecombered. The second patch is only signed off by me as I am the author. In my world (admittedly a kernel hacker) the first Signed-off-by: indicates the primary authorship of that patch and the [apw@...] part tries to clarify the changes I made therein.
Quoted 6 lines
No intentional stripping of credit was intended, and I believe that the attribution as written states Junio is the originator of this patch. However that is the way I would read the meanings of these lines, if git has different rules or you think there is a clearer way of stating this I am happy to change it, and resend it so attributed.
Barring any errors in my understanding of the matter, here's how it works for git.
git separates author from committer, so code attribution is done with author, and "I verified this is sane" is done by committer. Those two usually only ever differ when the user tells git commit that the author was someone else than him/her self, or when rewriting history with git rebase or similar. git am also maintains authorship (using the From:
line in emails), but sets $committer to the person running it, so when you apply patches sent by email from someone else you get the code attribution right by default.
The Signed-off-by line is, in git, used as "I touched the code here and agree that it may be included in the mothership repo and all future releases" (the spirit of that sentence is also in Documentation/SubmittingPatches).
We also have Acked-by (as does the kernel, no? I think we inherited it from there) to mean something along the lines of "I vote we include this", but not always based on technical merit (ie, patches can have many acks without having ever been tested).
Suggested-by, Tested-by and Reported-by are used less often, not always written in dash-form, but hopefully always self-explanatory ;-)
Signature · 3 lines
Andreas Ericsson [email protected] OP5 AB www.op5.se Tel: +46 8-230225 Fax: +46 8-230231
Quoted 17 lines · Andreas Ericsson
Barring any errors in my understanding of the matter, here's how it works for git.
git separates author from committer, so code attribution is done with author, and "I verified this is sane" is done by committer. Those two usually only ever differ when the user tells git commit that the author was someone else than him/her self, or when rewriting history with git rebase or similar. git am also maintains authorship (using the From:
line in emails), but sets $committer to the person running it, so when you apply patches sent by email from someone else you get the code attribution right by default.The Signed-off-by line is, in git, used as "I touched the code here and agree that it may be included in the mothership repo and all future releases" (the spirit of that sentence is also in
Documentation/SubmittingPatches).
Quoted 7 lines
We also have Acked-by (as does the kernel, no? I think we inherited it from there) to mean something along the lines of "I vote we include this", but not always based on technical merit (ie, patches can have many acks without having ever been tested).
Suggested-by, Tested-by and Reported-by are used less often, not always written in dash-form, but hopefully always self-explanatory ;-)
What that doesn't tell me is how when sending an email carrying a patch one ensures the attribution is correct when loaded into git.
Having messed about with it a bit it does seem that if one wants git to attribute the patch to junio I have to add a From: line to the top of the email payload.
I'll resend so attributed.
-apw
Quoted 24 lines · Andy Whitcroft
Quoted 22 lines · Andreas Ericsson
Barring any errors in my understanding of the matter, here's how it works for git.
git separates author from committer, so code attribution is done with author, and "I verified this is sane" is done by committer. Those two usually only ever differ when the user tells git commit that the author was someone else than him/her self, or when rewriting history with git rebase or similar. git am also maintains authorship (using the From:
line in emails), but sets $committer to the person running it, so when you apply patches sent by email from someone else you get the code attribution right by default.The Signed-off-by line is, in git, used as "I touched the code here and agree that it may be included in the mothership repo and all future releases" (the spirit of that sentence is also in
Documentation/SubmittingPatches).We also have Acked-by (as does the kernel, no? I think we inherited it from there) to mean something along the lines of "I vote we include this", but not always based on technical merit (ie, patches can have many acks without having ever been tested).
Quoted 6 lines
Quoted 2 lines
Suggested-by, Tested-by and Reported-by are used less often, not always written in dash-form, but hopefully always self-explanatory ;-)
What that doesn't tell me is how when sending an email carrying a patch one ensures the attribution is correct when loaded into git.
Ach damn. I had a sentence there reading "From: can also be specified in the email body to attribute code to someone else than the sender." It's in my clipboard, but I forgot to paste it :-/
Quoted 6 lines
Having messed about with it a bit it does seem that if one wants git to attribute the patch to junio I have to add a From: line to the top of the email payload.
I'll resend so attributed.
Thanks.
Signature · 3 lines
Andreas Ericsson [email protected] OP5 AB www.op5.se Tel: +46 8-230225 Fax: +46 8-230231
Quoted 2 lines · Johannes Schindelin
P.S.: Without tests I am opposed to inclusion. This _definitely_ needs some tests.
This is very much 'pu' material right now. I've used it for a day keeping some kernel repos in sync on a couple of test boxes. Hardly extensive testing.
Yes some tests would be advisable. However I am no expert in the git test system, so I am not going to be able to do that in short order. What little time I had to work on this this morning was wasted by some SarBox madness here (but that is another story). In the spirit of making progress on what is a useful feature I pulled Junio's original change forward, fixed up my patch to expose it the the user and gave it some testing.
Whats there does seem to work and has a prima-facie use case. Hopefully someone can provide the nessary tests before I can.
-apw
Quoted 6 lines · Johannes Schindelin
Quoted 2 lines · Andy Whitcroft
Ok, sometime back Junio sent out a proof-of-concept change to send-pack allowing a mirror mode.
You added/left his sign-off, but did not attribute the patches to him.
No big deal; I do not think much of my changes remain in the result. Mentioning "inspired by" would be nice as courtesy, but I think this is mostly Andy's work.
As I haven't seen _his_ part of the change before he posted this updated patch, copying my S-o-b line wasn't necessary either.