Skip to content

Commit

Permalink
Merge branch 'aw/mirror-push' into jk/send-pack
Browse files Browse the repository at this point in the history
* aw/mirror-push:
  git-push: add documentation for the newly added --mirror mode
  Add tests for git push'es mirror mode
  git-push: plumb in --mirror mode
  Teach send-pack a mirror mode
  send-pack: segfault fix on forced push
  send-pack: require --verbose to show update of tracking refs
  receive-pack: don't mention successful updates
  more terse push output

Conflicts:

	transport.c
	transport.h
  • Loading branch information
gitster committed Nov 14, 2007
2 parents 2d4eb71 + ff20674 commit bcd2e26
Show file tree
Hide file tree
Showing 12 changed files with 418 additions and 42 deletions.
8 changes: 8 additions & 0 deletions Documentation/git-push.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,14 @@ the remote repository.
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.

Expand Down
14 changes: 12 additions & 2 deletions builtin-push.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand Down Expand Up @@ -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;
Expand All @@ -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"),
Expand All @@ -121,13 +123,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);
}
127 changes: 99 additions & 28 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 @@ -195,7 +195,8 @@ static void update_tracking_ref(struct remote *remote, struct ref *ref)
return;

if (!remote_find_tracking(remote, &rs)) {
fprintf(stderr, "updating local tracking ref '%s'\n", rs.dst);
if (args.verbose)
fprintf(stderr, "updating local tracking ref '%s'\n", rs.dst);
if (is_null_sha1(ref->peer_ref->new_sha1)) {
if (delete_ref(rs.dst, NULL))
error("Failed to delete");
Expand All @@ -206,14 +207,32 @@ static void update_tracking_ref(struct remote *remote, struct ref *ref)
}
}

static int do_send_pack(int in, int out, struct remote *remote, int nr_refspec, const char **refspec)
static const char *prettify_ref(const char *name)
{
return name + (
!prefixcmp(name, "refs/heads/") ? 11 :
!prefixcmp(name, "refs/tags/") ? 10 :
!prefixcmp(name, "refs/remotes/") ? 13 :
0);
}

#define SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)

static int do_send_pack(int in, int out, struct remote *remote, const char *dest, int nr_refspec, const char **refspec)
{
struct ref *ref;
int new_refs;
int ret = 0;
int ask_for_status_report = 0;
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 @@ -229,7 +248,7 @@ static int do_send_pack(int in, int out, struct remote *remote, int nr_refspec,
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 @@ -245,21 +264,41 @@ static int do_send_pack(int in, int out, struct remote *remote, int nr_refspec,
for (ref = remote_refs; ref; ref = ref->next) {
char old_hex[60], *new_hex;
int will_delete_ref;
const char *pretty_ref;
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);
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) {
error("remote does not support 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': up-to-date\n", ref->name);
fprintf(stderr, " = %-*s %s -> %s\n",
SUMMARY_WIDTH, "[up to date]",
pretty_peer, pretty_ref);
continue;
}

Expand Down Expand Up @@ -287,26 +326,22 @@ static int do_send_pack(int in, int out, struct remote *remote, int nr_refspec,
!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
* push. Either way this can be losing
* commits at the remote end and likely
* we were not up to date to begin with.
*/
error("remote '%s' is not an ancestor of\n"
" local '%s'.\n"
" Maybe you are not up-to-date and "
"need to pull first?",
ref->name,
ref->peer_ref->name);
fprintf(stderr, " ! %-*s %s -> %s (non-fast forward)\n",
SUMMARY_WIDTH, "[rejected]",
pretty_peer, pretty_ref);
ret = -2;
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 All @@ -325,14 +360,41 @@ static int do_send_pack(int in, int out, struct remote *remote, int nr_refspec,
old_hex, new_hex, ref->name);
}
if (will_delete_ref)
fprintf(stderr, "deleting '%s'\n", ref->name);
fprintf(stderr, " - %-*s %s\n",
SUMMARY_WIDTH, "[deleting]",
pretty_ref);
else if (is_null_sha1(ref->old_sha1)) {
const char *msg;

if (!prefixcmp(ref->name, "refs/tags/"))
msg = "[new tag]";
else
msg = "[new branch]";
fprintf(stderr, " * %-*s %s -> %s\n",
SUMMARY_WIDTH, msg,
pretty_peer, pretty_ref);
}
else {
fprintf(stderr, "updating '%s'", ref->name);
if (strcmp(ref->name, ref->peer_ref->name))
fprintf(stderr, " using '%s'",
ref->peer_ref->name);
fprintf(stderr, "\n from %s\n to %s\n",
old_hex, new_hex);
char quickref[83];
char type = ' ';
const char *msg = "";
const char *old_abb;
old_abb = find_unique_abbrev(ref->old_sha1, DEFAULT_ABBREV);
strcpy(quickref, old_abb ? old_abb : old_hex);
if (ref_newer(ref->peer_ref->new_sha1, ref->old_sha1))
strcat(quickref, "..");
else {
strcat(quickref, "...");
type = '+';
msg = " (forced update)";
}
strcat(quickref, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV));

fprintf(stderr, " %c %-*s %s -> %s%s\n",
type,
SUMMARY_WIDTH, quickref,
pretty_peer, pretty_ref,
msg);
}
}

Expand Down Expand Up @@ -411,6 +473,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 @@ -435,7 +501,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 All @@ -461,7 +532,7 @@ int send_pack(struct send_pack_args *my_args,
verify_remote_names(nr_heads, heads);

conn = git_connect(fd, dest, args.receivepack, args.verbose ? CONNECT_VERBOSE : 0);
ret = do_send_pack(fd[0], fd[1], remote, nr_heads, heads);
ret = do_send_pack(fd[0], fd[1], remote, dest, nr_heads, heads);
close(fd[0]);
close(fd[1]);
ret |= finish_connect(conn);
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
4 changes: 0 additions & 4 deletions receive-pack.c
Original file line number Diff line number Diff line change
Expand Up @@ -204,8 +204,6 @@ static const char *update(struct command *cmd)
error("failed to delete %s", name);
return "failed to delete";
}
fprintf(stderr, "%s: %s -> deleted\n", name,
sha1_to_hex(old_sha1));
return NULL; /* good */
}
else {
Expand All @@ -217,8 +215,6 @@ static const char *update(struct command *cmd)
if (write_ref_sha1(lock, new_sha1, "push")) {
return "failed to write"; /* error() already called */
}
fprintf(stderr, "%s: %s -> %s\n", name,
sha1_to_hex(old_sha1), sha1_to_hex(new_sha1));
return NULL; /* good */
}
}
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
Loading

0 comments on commit bcd2e26

Please sign in to comment.