From: Jay Soffian <jaysoffian@gmail.com>
To: Junio C Hamano <junio@kernel.org>
Cc: Jay Soffian <jaysoffian@gmail.com>,
"Shawn O . Pearce" <spearce@spearce.org>,
git@vger.kernel.org
Subject: [PATCH v3 0/3] js/maint-receive-pack-symref-alias
Date: Mon, 19 Apr 2010 18:08:29 -0400 [thread overview]
Message-ID: <1271714912-56659-1-git-send-email-jaysoffian@gmail.com> (raw)
In-Reply-To: <1271694343-31876-2-git-send-email-jaysoffian@gmail.com>
- Incorporated Junio's feedback from v1 and v2.
- Rebuilt on-top of f78683f, which is where v1 was applied in pu.
- Added an additional patch to the series to reformat the tests in
t5516-fetch-push.sh to use a consistent style, per Junio's tweaks to the
test I wrote for v1.
Jay Soffian (3):
receive-pack: switch global variable 'commands' to a parameter
t5516-fetch-push.sh: style cleanup
receive-pack: detect aliased updates which can occur with symrefs
builtin-receive-pack.c | 128 ++++++++++++++++++++++++++++++++++--------------
t/t5516-fetch-push.sh | 118 +++++++++++++++++++++++++++++++++++---------
2 files changed, 186 insertions(+), 60 deletions(-)
interdiff from what's in pu:
builtin-receive-pack.c | 76 +++++++++++++++++++++++++------------
t/t5516-fetch-push.sh | 98 ++++++++++++++++++++++++++++++++++++------------
2 files changed, 126 insertions(+), 48 deletions(-)
diff --git a/builtin-receive-pack.c b/builtin-receive-pack.c
index a2e3bc8..bb34757 100644
--- a/builtin-receive-pack.c
+++ b/builtin-receive-pack.c
@@ -130,6 +130,7 @@ static void write_head_info(void)
struct command {
struct command *next;
const char *error_string;
+ unsigned int skip_update;
unsigned char old_sha1[20];
unsigned char new_sha1[20];
char ref_name[FLEX_ARRAY]; /* more */
@@ -487,30 +488,67 @@ static void run_update_post_hook(struct command *commands)
}
}
-static int aliased_ref(struct command *cmd, struct string_list *list)
+static void check_aliased_update(struct command *cmd, struct string_list *list)
{
struct string_list_item *item;
+ struct command *dst_cmd;
unsigned char sha1[20];
+ char cmd_oldh[41], cmd_newh[41], dst_oldh[41], dst_newh[41];
int flag;
const char *dst_name = resolve_ref(cmd->ref_name, sha1, 0, &flag);
if (!(flag & REF_ISSYMREF))
- return 0;
+ return;
+
+ if ((item = string_list_lookup(dst_name, list)) == NULL)
+ return;
+
+ cmd->skip_update = 1;
+
+ dst_cmd = (struct command *) item->util;
+
+ if (!hashcmp(cmd->old_sha1, dst_cmd->old_sha1) &&
+ !hashcmp(cmd->new_sha1, dst_cmd->new_sha1))
+ return;
+
+ dst_cmd->skip_update = 1;
+
+ strcpy(cmd_oldh, find_unique_abbrev(cmd->old_sha1, DEFAULT_ABBREV));
+ strcat(cmd_newh, find_unique_abbrev(cmd->new_sha1, DEFAULT_ABBREV));
+ strcpy(dst_oldh, find_unique_abbrev(dst_cmd->old_sha1, DEFAULT_ABBREV));
+ strcat(dst_newh, find_unique_abbrev(dst_cmd->new_sha1, DEFAULT_ABBREV));
+ rp_error("refusing inconsistent update between symref '%s' (%s..%s) and"
+ " its target '%s' (%s..%s)",
+ cmd->ref_name, cmd_oldh, cmd_newh,
+ dst_cmd->ref_name, dst_oldh, dst_newh);
- if ((item = string_list_lookup(dst_name, list)) != NULL) {
- struct command *other_cmd = (struct command *) item->util;
- return (!(hashcmp(cmd->old_sha1, other_cmd->old_sha1) &&
- hashcmp(cmd->new_sha1, other_cmd->new_sha1)));
+ cmd->error_string = dst_cmd->error_string =
+ "inconsistent aliased update";
+}
+
+static void check_aliased_updates(struct command *commands)
+{
+ struct command *cmd;
+ struct string_list ref_list = { NULL, 0, 0, 0 };
+
+ for (cmd = commands; cmd; cmd = cmd->next) {
+ struct string_list_item *item =
+ string_list_append(cmd->ref_name, &ref_list);
+ item->util = (void *)cmd;
}
- return 0;
+ sort_string_list(&ref_list);
+
+ for (cmd = commands; cmd; cmd = cmd->next)
+ check_aliased_update(cmd, &ref_list);
+
+ string_list_clear(&ref_list, 0);
}
static void execute_commands(struct command *commands, const char *unpacker_error)
{
struct command *cmd;
unsigned char sha1[20];
- struct string_list ref_list = { NULL, 0, 0, 0 };
if (unpacker_error) {
for (cmd = commands; cmd; cmd = cmd->next)
@@ -524,27 +562,19 @@ static void execute_commands(struct command *commands, const char *unpacker_erro
return;
}
- head_name = resolve_ref("HEAD", sha1, 0, NULL);
+ check_aliased_updates(commands);
- for (cmd = commands; cmd; cmd = cmd->next) {
- struct string_list_item *item =
- string_list_append(cmd->ref_name, &ref_list);
- item->util = (void *)cmd;
- }
- sort_string_list(&ref_list);
+ head_name = resolve_ref("HEAD", sha1, 0, NULL);
- for (cmd = commands; cmd; cmd = cmd->next) {
- if (!aliased_ref(cmd, &ref_list))
+ for (cmd = commands; cmd; cmd = cmd->next)
+ if (!cmd->skip_update)
cmd->error_string = update(cmd);
- }
- string_list_clear(&ref_list, 0);
}
static struct command *read_head_info(void)
{
struct command *commands = NULL;
struct command **p = &commands;
-
for (;;) {
static char line[1000];
unsigned char old_sha1[20], new_sha1[20];
@@ -573,12 +603,10 @@ static struct command *read_head_info(void)
if (strstr(refname + reflen + 1, "side-band-64k"))
use_sideband = LARGE_PACKET_MAX;
}
- cmd = xmalloc(sizeof(struct command) + len - 80);
+ cmd = xcalloc(1, sizeof(struct command) + len - 80);
hashcpy(cmd->old_sha1, old_sha1);
hashcpy(cmd->new_sha1, new_sha1);
memcpy(cmd->ref_name, line + 82, len - 81);
- cmd->error_string = NULL;
- cmd->next = NULL;
*p = cmd;
p = &cmd->next;
}
@@ -671,8 +699,8 @@ static const char *unpack(void)
static void report(struct command *commands, const char *unpack_status)
{
- struct strbuf buf = STRBUF_INIT;
struct command *cmd;
+ struct strbuf buf = STRBUF_INIT;
packet_buf_write(&buf, "unpack %s\n",
unpack_status ? unpack_status : "ok");
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 350e734..f0813e0 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -64,13 +64,13 @@ check_push_result () {
test_expect_success setup '
- : >path1 &&
+ >path1 &&
git add path1 &&
test_tick &&
git commit -a -m repo &&
the_first_commit=$(git show-ref -s --verify refs/heads/master) &&
- : >path2 &&
+ >path2 &&
git add path2 &&
test_tick &&
git commit -a -m second &&
@@ -483,8 +483,10 @@ git config --remove-section remote.there
test_expect_success 'push with dry-run' '
mk_test heads/master &&
- (cd testrepo &&
- old_commit=$(git show-ref -s --verify refs/heads/master)) &&
+ (
+ cd testrepo &&
+ old_commit=$(git show-ref -s --verify refs/heads/master)
+ ) &&
git push --dry-run testrepo &&
check_push_result $old_commit heads/master
'
@@ -493,10 +495,13 @@ test_expect_success 'push updates local refs' '
mk_test heads/master &&
mk_child child &&
- (cd child &&
+ (
+ cd child &&
git pull .. master &&
git push &&
- test $(git rev-parse master) = $(git rev-parse remotes/origin/master))
+ test $(git rev-parse master) = \
+ $(git rev-parse remotes/origin/master)
+ )
'
@@ -506,10 +511,13 @@ test_expect_success 'push updates up-to-date local refs' '
mk_child child1 &&
mk_child child2 &&
(cd child1 && git pull .. master && git push) &&
- (cd child2 &&
+ (
+ cd child2 &&
git pull ../child1 master &&
git push &&
- test $(git rev-parse master) = $(git rev-parse remotes/origin/master))
+ test $(git rev-parse master) = \
+ $(git rev-parse remotes/origin/master)
+ )
'
@@ -517,9 +525,11 @@ test_expect_success 'push preserves up-to-date packed refs' '
mk_test heads/master &&
mk_child child &&
- (cd child &&
+ (
+ cd child &&
git push &&
- ! test -f .git/refs/remotes/origin/master)
+ ! test -f .git/refs/remotes/origin/master
+ )
'
@@ -530,11 +540,13 @@ test_expect_success 'push does not update local refs on failure' '
mkdir testrepo/.git/hooks &&
echo exit 1 >testrepo/.git/hooks/pre-receive &&
chmod +x testrepo/.git/hooks/pre-receive &&
- (cd child &&
+ (
+ cd child &&
git pull .. master
test_must_fail git push &&
test $(git rev-parse master) != \
- $(git rev-parse remotes/origin/master))
+ $(git rev-parse remotes/origin/master)
+ )
'
@@ -575,34 +587,41 @@ test_expect_success 'push --delete refuses src:dest refspecs' '
test_expect_success 'warn on push to HEAD of non-bare repository' '
mk_test heads/master
- (cd testrepo &&
+ (
+ cd testrepo &&
git checkout master &&
- git config receive.denyCurrentBranch warn) &&
+ git config receive.denyCurrentBranch warn
+ ) &&
git push testrepo master 2>stderr &&
grep "warning: updating the current branch" stderr
'
test_expect_success 'deny push to HEAD of non-bare repository' '
mk_test heads/master
- (cd testrepo &&
+ (
+ cd testrepo &&
git checkout master &&
- git config receive.denyCurrentBranch true) &&
+ git config receive.denyCurrentBranch true
+ ) &&
test_must_fail git push testrepo master
'
test_expect_success 'allow push to HEAD of bare repository (bare)' '
mk_test heads/master
- (cd testrepo &&
+ (
+ cd testrepo &&
git checkout master &&
git config receive.denyCurrentBranch true &&
- git config core.bare true) &&
+ git config core.bare true
+ ) &&
git push testrepo master 2>stderr &&
! grep "warning: updating the current branch" stderr
'
test_expect_success 'allow push to HEAD of non-bare repository (config)' '
mk_test heads/master
- (cd testrepo &&
+ (
+ cd testrepo &&
git checkout master &&
git config receive.denyCurrentBranch false
) &&
@@ -615,7 +634,8 @@ test_expect_success 'fetch with branches' '
git branch second $the_first_commit &&
git checkout second &&
echo ".." > testrepo/.git/branches/branch1 &&
- (cd testrepo &&
+ (
+ cd testrepo &&
git fetch branch1 &&
r=$(git show-ref -s --verify refs/heads/branch1) &&
test "z$r" = "z$the_commit" &&
@@ -627,7 +647,8 @@ test_expect_success 'fetch with branches' '
test_expect_success 'fetch with branches containing #' '
mk_empty &&
echo "..#second" > testrepo/.git/branches/branch2 &&
- (cd testrepo &&
+ (
+ cd testrepo &&
git fetch branch2 &&
r=$(git show-ref -s --verify refs/heads/branch2) &&
test "z$r" = "z$the_first_commit" &&
@@ -641,7 +662,8 @@ test_expect_success 'push with branches' '
git checkout second &&
echo "testrepo" > .git/branches/branch1 &&
git push branch1 &&
- (cd testrepo &&
+ (
+ cd testrepo &&
r=$(git show-ref -s --verify refs/heads/master) &&
test "z$r" = "z$the_first_commit" &&
test 1 = $(git for-each-ref refs/heads | wc -l)
@@ -652,7 +674,8 @@ test_expect_success 'push with branches containing #' '
mk_empty &&
echo "testrepo#branch3" > .git/branches/branch2 &&
git push branch2 &&
- (cd testrepo &&
+ (
+ cd testrepo &&
r=$(git show-ref -s --verify refs/heads/branch3) &&
test "z$r" = "z$the_first_commit" &&
test 1 = $(git for-each-ref refs/heads | wc -l)
@@ -660,7 +683,7 @@ test_expect_success 'push with branches containing #' '
git checkout master
'
-test_expect_success 'push into aliased refs' '
+test_expect_success 'push into aliased refs (consistent)' '
mk_test heads/master &&
mk_child child1 &&
mk_child child2 &&
@@ -682,4 +705,31 @@ test_expect_success 'push into aliased refs' '
)
'
+test_expect_success 'push into aliased refs (inconsistent)' '
+ mk_test heads/master &&
+ mk_child child1 &&
+ mk_child child2 &&
+ (
+ cd child1 &&
+ git branch foo &&
+ git symbolic-ref refs/heads/bar refs/heads/foo
+ git config receive.denyCurrentBranch false
+ ) &&
+ (
+ cd child2 &&
+ >path2 &&
+ git add path2 &&
+ test_tick &&
+ git commit -a -m child2 &&
+ git branch foo &&
+ >path3 &&
+ git add path3 &&
+ test_tick &&
+ git commit -a -m child2 &&
+ git branch bar &&
+ test_must_fail git push ../child1 foo bar 2>stderr &&
+ grep "refusing inconsistent update" stderr
+ )
+'
+
test_done
next prev parent reply other threads:[~2010-04-19 22:09 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-04-19 16:25 [PATCH v2 1/2] receive-pack: switch global variable 'commands' to a parameter Jay Soffian
2010-04-19 16:25 ` [PATCH v2 2/2] receive-pack: detect aliased updates which can occur with symrefs Jay Soffian
2010-04-19 16:31 ` Jay Soffian
2010-04-19 16:39 ` Jay Soffian
2010-04-19 20:39 ` Junio C Hamano
2010-04-19 20:57 ` Jay Soffian
2010-04-19 22:08 ` Jay Soffian [this message]
2012-12-11 19:46 ` [RFC/PATCH] ignoring a fetch that overwrites local symref Junio C Hamano
2012-12-11 22:32 ` [PATCH] fetch: ignore wildcarded refspecs that update local symbolic refs Junio C Hamano
2012-12-12 17:17 ` Jay Soffian
2012-12-12 19:13 ` [RFC/PATCH] ignoring a fetch that overwrites local symref Shawn Pearce
2012-12-12 19:38 ` Junio C Hamano
2010-04-19 22:08 ` [PATCH v3 1/3] receive-pack: switch global variable 'commands' to a parameter Jay Soffian
2010-04-19 22:08 ` [PATCH v3 2/3] t5516-fetch-push.sh: style cleanup Jay Soffian
2010-04-19 22:08 ` [PATCH v3 3/3] receive-pack: detect aliased updates which can occur with symrefs Jay Soffian
2010-04-19 22:19 ` Jay Soffian
2010-06-10 18:06 ` Ævar Arnfjörð Bjarmason
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1271714912-56659-1-git-send-email-jaysoffian@gmail.com \
--to=jaysoffian@gmail.com \
--cc=git@vger.kernel.org \
--cc=junio@kernel.org \
--cc=spearce@spearce.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.