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
This commit is contained in:
commit
bcd2e266a6
@ -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.
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,7 +207,18 @@ 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;
|
||||
@ -214,6 +226,13 @@ static int do_send_pack(int in, int out, struct remote *remote, int nr_refspec,
|
||||
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,8 +326,7 @@ 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
|
||||
@ -296,17 +334,14 @@ static int do_send_pack(int in, int out, struct remote *remote, int nr_refspec,
|
||||
* 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);
|
||||
|
@ -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")) {
|
||||
|
@ -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 */
|
||||
}
|
||||
}
|
||||
|
15
remote.c
15
remote.c
@ -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 */
|
||||
|
7
remote.h
7
remote.h
@ -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
|
||||
|
@ -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;
|
||||
|
42
t/t5405-send-pack-rewind.sh
Executable file
42
t/t5405-send-pack-rewind.sh
Executable file
@ -0,0 +1,42 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='forced push to replace commit we do not have'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success setup '
|
||||
|
||||
>file1 && git add file1 && test_tick &&
|
||||
git commit -m Initial &&
|
||||
|
||||
mkdir another && (
|
||||
cd another &&
|
||||
git init &&
|
||||
git fetch .. master:master
|
||||
) &&
|
||||
|
||||
>file2 && git add file2 && test_tick &&
|
||||
git commit -m Second
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'non forced push should die not segfault' '
|
||||
|
||||
(
|
||||
cd another &&
|
||||
git push .. master:master
|
||||
test $? = 1
|
||||
)
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'forced push should succeed' '
|
||||
|
||||
(
|
||||
cd another &&
|
||||
git push .. +master:master
|
||||
)
|
||||
|
||||
'
|
||||
|
||||
test_done
|
228
t/t5517-push-mirror.sh
Executable file
228
t/t5517-push-mirror.sh
Executable file
@ -0,0 +1,228 @@
|
||||
#!/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
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
# BRANCH tests
|
||||
test_expect_success 'push mirror creates 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 updates 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 force updates 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 removes 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 adds, updates and removes branches 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
|
||||
)
|
||||
|
||||
'
|
||||
|
||||
|
||||
# TAG tests
|
||||
test_expect_success 'push mirror creates 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 updates 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 force updates 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 removes 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 adds, updates and removes 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
|
@ -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);
|
||||
@ -387,6 +390,9 @@ static int curl_transport_push(struct transport *transport, int refspec_nr, cons
|
||||
int argc;
|
||||
int err;
|
||||
|
||||
if (flags & TRANSPORT_PUSH_MIRROR)
|
||||
return error("http transport does not support mirror mode");
|
||||
|
||||
argv = xmalloc((refspec_nr + 12) * sizeof(char *));
|
||||
argv[0] = "http-push";
|
||||
argc = 1;
|
||||
@ -657,6 +663,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 = !!(flags & TRANSPORT_PUSH_VERBOSE);
|
||||
|
@ -30,7 +30,8 @@ struct transport {
|
||||
#define TRANSPORT_PUSH_ALL 1
|
||||
#define TRANSPORT_PUSH_FORCE 2
|
||||
#define TRANSPORT_PUSH_DRY_RUN 4
|
||||
#define TRANSPORT_PUSH_VERBOSE 8
|
||||
#define TRANSPORT_PUSH_MIRROR 8
|
||||
#define TRANSPORT_PUSH_VERBOSE 16
|
||||
|
||||
/* Returns a transport suitable for the url */
|
||||
struct transport *transport_get(struct remote *, const char *);
|
||||
|
Loading…
Reference in New Issue
Block a user