Skip to content

Commit

Permalink
Teach send-pack a mirror mode
Browse files Browse the repository at this point in the history
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.

Original patch by Junio C Hamano.

Signed-off-by: Andy Whitcroft <apw@shadowen.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
awhitcroft authored and gitster committed Nov 10, 2007
1 parent 0d9d89f commit 28b9d6e
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 19 deletions.
46 changes: 34 additions & 12 deletions builtin-send-pack.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -227,6 +227,12 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
int 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);
Expand All @@ -242,7 +248,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
if (!remote_tail)
remote_tail = &remote_refs;
if (match_refs(local_refs, remote_refs, &remote_tail,
nr_refspec, refspec, args.send_all))
nr_refspec, refspec, flags))
return -1;

if (!remote_refs) {
Expand All @@ -259,28 +265,36 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
char 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);
ret = -2;
continue;
}
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]",
Expand Down Expand Up @@ -312,8 +326,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
Expand All @@ -328,7 +341,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
continue;
}
}
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));
Expand Down Expand Up @@ -459,6 +472,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;
Expand All @@ -483,7 +500,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) {
Expand Down
4 changes: 2 additions & 2 deletions http-push.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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")) {
Expand Down
15 changes: 10 additions & 5 deletions remote.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 & MATCH_REFS_ALL;
int send_mirror = flags & MATCH_REFS_MIRROR;

if (match_explicit_refs(src, dst, dst_tail, rs, nr_refspec))
return -1;
Expand All @@ -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
Expand All @@ -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 */
Expand Down
7 changes: 7 additions & 0 deletions remote.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
1 change: 1 addition & 0 deletions send-pack.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 28b9d6e

Please sign in to comment.