Permalink
Browse files

Merge branch 'aw/mirror-push' into jk/send-pack

* 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...
2 parents 2d4eb71 + ff20674 commit bcd2e266a6270254212603e90186251116d3cd16 @gitster committed Nov 14, 2007
Showing with 418 additions and 42 deletions.
  1. +8 −0 Documentation/git-push.txt
  2. +12 −2 builtin-push.c
  3. +99 −28 builtin-send-pack.c
  4. +2 −2 http-push.c
  5. +0 −4 receive-pack.c
  6. +10 −5 remote.c
  7. +7 −0 remote.h
  8. +1 −0 send-pack.h
  9. +42 −0 t/t5405-send-pack-rewind.sh
  10. +228 −0 t/t5517-push-mirror.sh
  11. +7 −0 transport.c
  12. +2 −1 transport.h
@@ -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.
View
@@ -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"),
@@ -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);
}
View
@@ -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 = {
@@ -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");
@@ -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);
@@ -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) {
@@ -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;
}
@@ -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));
@@ -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);
}
}
@@ -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;
@@ -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) {
@@ -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);
View
@@ -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")) {
View
@@ -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 {
@@ -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 */
}
}
View
@@ -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;
@@ -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 */
View
@@ -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
View
@@ -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;
Oops, something went wrong.

0 comments on commit bcd2e26

Please sign in to comment.