* [PATCH v3 0/3] tracking per-ref errors on push
@ 2007-11-17 12:53 Jeff King
2007-11-17 12:54 ` [PATCH 1/3] send-pack: track errors for each ref Jeff King
` (2 more replies)
0 siblings, 3 replies; 20+ messages in thread
From: Jeff King @ 2007-11-17 12:53 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, Alex Riesen, Pierre Habouzit, Daniel Barkalow
Here are cleaned-up versions of the previous patches I sent. The
improvements are:
1/3 send-pack: track errors for each ref
- there was a t5404 regression because I removed the is_null_sha1()
check before updating a tracking ref (but the replacement fix
doesn't come until 2/3). Even though this check is not correct,
it's better to fix it all at once correctly in 2/3.
- clarified the desired git-push exit code in t5404
- I renamed the struct elements to (hopefully) be a bit more obvious
- readability cleanups (fixed some very long lines, hoisted some
code into its own functions)
2/3 send-pack: check ref->status before updating tracking refs
- moved in fix from 1/3 mentioned above
- add test for deleting tracking branches, which was broken in next
but fixed by this patch
3/3 send-pack: assign remote errors to each ref
- squashed optimization patch
- remove bogus parsing drawback in commit message
- add test
I'm hoping to get feedback from the cc'd people:
- Alex: please OK the modifications to t5404
- Pierre: this should fix the tracking ref update issues you reported
- Daniel: a general OK, since I am mangling your code :)
-Peff
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 1/3] send-pack: track errors for each ref
2007-11-17 12:53 [PATCH v3 0/3] tracking per-ref errors on push Jeff King
@ 2007-11-17 12:54 ` Jeff King
2007-11-17 13:34 ` Alex Riesen
` (2 more replies)
2007-11-17 12:55 ` [PATCH 2/3] send-pack: check ref->status before updating tracking refs Jeff King
2007-11-17 12:56 ` [PATCH 3/3] send-pack: assign remote errors to each ref Jeff King
2 siblings, 3 replies; 20+ messages in thread
From: Jeff King @ 2007-11-17 12:54 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, Alex Riesen, Pierre Habouzit, Daniel Barkalow
Instead of keeping the 'ret' variable, we instead have a
status flag for each ref that tracks what happened to it.
We then print the ref status after all of the refs have
been examined.
This paves the way for three improvements:
- updating tracking refs only for non-error refs
- incorporating remote rejection into the printed status
- printing errors in a different order than we processed
(e.g., consolidating non-ff errors near the end with
a special message)
Signed-off-by: Jeff King <peff@peff.net>
---
builtin-send-pack.c | 225 +++++++++++++++++++++++++-----------------
cache.h | 13 ++-
t/t5404-tracking-branches.sh | 14 ++-
3 files changed, 157 insertions(+), 95 deletions(-)
diff --git a/builtin-send-pack.c b/builtin-send-pack.c
index 418925e..90ca2d3 100644
--- a/builtin-send-pack.c
+++ b/builtin-send-pack.c
@@ -207,8 +207,9 @@ static void update_tracking_ref(struct remote *remote, struct ref *ref)
}
}
-static const char *prettify_ref(const char *name)
+static const char *prettify_ref(const struct ref *ref)
{
+ const char *name = ref->name;
return name + (
!prefixcmp(name, "refs/heads/") ? 11 :
!prefixcmp(name, "refs/tags/") ? 10 :
@@ -218,15 +219,105 @@ static const char *prettify_ref(const char *name)
#define SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)
+static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg)
+{
+ fprintf(stderr, " %c %-*s ", flag, SUMMARY_WIDTH, summary);
+ if (from)
+ fprintf(stderr, "%s -> %s", prettify_ref(from), prettify_ref(to));
+ else
+ fputs(prettify_ref(to), stderr);
+ if (msg) {
+ fputs(" (", stderr);
+ fputs(msg, stderr);
+ fputc(')', stderr);
+ }
+ fputc('\n', stderr);
+}
+
+static const char *status_abbrev(unsigned char sha1[20])
+{
+ const char *abbrev;
+ abbrev = find_unique_abbrev(sha1, DEFAULT_ABBREV);
+ return abbrev ? abbrev : sha1_to_hex(sha1);
+}
+
+static void print_ok_ref_status(struct ref *ref)
+{
+ if (ref->deletion)
+ print_ref_status('-', "[deleted]", ref, NULL, NULL);
+ else if (is_null_sha1(ref->old_sha1))
+ print_ref_status('*',
+ (!prefixcmp(ref->name, "refs/tags/") ? "[new tag]" :
+ "[new branch]"),
+ ref, ref->peer_ref, NULL);
+ else {
+ char quickref[83];
+ char type;
+ const char *msg;
+
+ strcpy(quickref, status_abbrev(ref->old_sha1));
+ if (ref->nonfastforward) {
+ strcat(quickref, "...");
+ type = '+';
+ msg = " (forced update)";
+ }
+ else {
+ strcat(quickref, "..");
+ type = ' ';
+ msg = NULL;
+ }
+ strcat(quickref, status_abbrev(ref->new_sha1));
+
+ print_ref_status(type, quickref, ref, ref->peer_ref, msg);
+ }
+}
+
+static void print_push_status(const char *dest, struct ref *refs)
+{
+ struct ref *ref;
+ int shown_dest = 0;
+
+ for (ref = refs; ref; ref = ref->next) {
+ if (!ref->status)
+ continue;
+ if (ref->status == REF_STATUS_UPTODATE && !args.verbose)
+ continue;
+
+ if (!shown_dest) {
+ fprintf(stderr, "To %s\n", dest);
+ shown_dest = 1;
+ }
+
+ switch(ref->status) {
+ case REF_STATUS_NONE:
+ print_ref_status('X', "[no match]", ref, NULL, NULL);
+ break;
+ case REF_STATUS_REJECT_NODELETE:
+ print_ref_status('!', "[rejected]", ref, NULL,
+ "remote does not support deleting refs");
+ break;
+ case REF_STATUS_UPTODATE:
+ print_ref_status('=', "[up to date]", ref,
+ ref->peer_ref, NULL);
+ break;
+ case REF_STATUS_REJECT_NONFASTFORWARD:
+ print_ref_status('!', "[rejected]", ref, ref->peer_ref,
+ "non-fast forward");
+ break;
+ case REF_STATUS_OK:
+ print_ok_ref_status(ref);
+ break;
+ }
+ }
+}
+
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)
@@ -262,10 +353,6 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
*/
new_refs = 0;
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) {
@@ -276,29 +363,15 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
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);
-
- 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;
+ ref->deletion = is_null_sha1(new_sha1);
+ if (ref->deletion && !allow_deleting_refs) {
+ ref->status = REF_STATUS_REJECT_NODELETE;
continue;
}
- if (!will_delete_ref &&
+ if (!ref->deletion &&
!hashcmp(ref->old_sha1, new_sha1)) {
- if (args.verbose)
- fprintf(stderr, " = %-*s %s -> %s\n",
- SUMMARY_WIDTH, "[up to date]",
- pretty_peer, pretty_ref);
+ ref->status = REF_STATUS_UPTODATE;
continue;
}
@@ -321,33 +394,26 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
* always allowed.
*/
- if (!args.force_update &&
- !will_delete_ref &&
+ ref->nonfastforward =
+ !ref->deletion &&
!is_null_sha1(ref->old_sha1) &&
- !ref->force) {
- if (!has_sha1_file(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.
- */
- fprintf(stderr, " ! %-*s %s -> %s (non-fast forward)\n",
- SUMMARY_WIDTH, "[rejected]",
- pretty_peer, pretty_ref);
- ret = -2;
- continue;
- }
+ (!has_sha1_file(ref->old_sha1)
+ || !ref_newer(new_sha1, ref->old_sha1));
+
+ if (ref->nonfastforward && !ref->force && !args.force_update) {
+ ref->status = REF_STATUS_REJECT_NONFASTFORWARD;
+ continue;
}
+
hashcpy(ref->new_sha1, new_sha1);
- if (!will_delete_ref)
+ if (!ref->deletion)
new_refs++;
- strcpy(old_hex, sha1_to_hex(ref->old_sha1));
- new_hex = sha1_to_hex(ref->new_sha1);
+ ref->status = REF_STATUS_OK;
if (!args.dry_run) {
+ char *old_hex = sha1_to_hex(ref->old_sha1);
+ char *new_hex = sha1_to_hex(ref->new_sha1);
+
if (ask_for_status_report) {
packet_write(out, "%s %s %s%c%s",
old_hex, new_hex, ref->name, 0,
@@ -359,64 +425,43 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
packet_write(out, "%s %s %s",
old_hex, new_hex, ref->name);
}
- if (will_delete_ref)
- 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 {
- 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);
- }
}
packet_flush(out);
- if (new_refs && !args.dry_run)
- ret = pack_objects(out, remote_refs);
+ if (new_refs && !args.dry_run) {
+ if (pack_objects(out, remote_refs) < 0) {
+ close(out);
+ return -1;
+ }
+ }
close(out);
+ print_push_status(dest, remote_refs);
+
if (expect_status_report) {
if (receive_status(in))
- ret = -4;
+ return -1;
}
- if (!args.dry_run && remote && ret == 0) {
+ if (!args.dry_run && remote) {
for (ref = remote_refs; ref; ref = ref->next)
if (!is_null_sha1(ref->new_sha1))
update_tracking_ref(remote, ref);
}
- if (!new_refs && ret == 0)
+ if (!new_refs)
fprintf(stderr, "Everything up-to-date\n");
- return ret;
+ for (ref = remote_refs; ref; ref = ref->next) {
+ switch (ref->status) {
+ case REF_STATUS_NONE:
+ case REF_STATUS_UPTODATE:
+ case REF_STATUS_OK:
+ break;
+ default:
+ return -1;
+ }
+ }
+ return 0;
}
static void verify_remote_names(int nr_heads, const char **heads)
diff --git a/cache.h b/cache.h
index e9b3ce3..2768342 100644
--- a/cache.h
+++ b/cache.h
@@ -500,8 +500,17 @@ struct ref {
struct ref *next;
unsigned char old_sha1[20];
unsigned char new_sha1[20];
- unsigned char force;
- unsigned char merge;
+ unsigned char force : 1;
+ unsigned char merge : 1;
+ unsigned char nonfastforward : 1;
+ unsigned char deletion : 1;
+ enum {
+ REF_STATUS_NONE = 0,
+ REF_STATUS_OK,
+ REF_STATUS_REJECT_NONFASTFORWARD,
+ REF_STATUS_REJECT_NODELETE,
+ REF_STATUS_UPTODATE,
+ } status;
struct ref *peer_ref; /* when renaming */
char name[FLEX_ARRAY]; /* more */
};
diff --git a/t/t5404-tracking-branches.sh b/t/t5404-tracking-branches.sh
index 20718d4..799e47e 100755
--- a/t/t5404-tracking-branches.sh
+++ b/t/t5404-tracking-branches.sh
@@ -19,7 +19,7 @@ test_expect_success 'setup' '
git commit -a -m b2
'
-test_expect_success 'check tracking branches updated correctly after push' '
+test_expect_success 'prepare pushable branches' '
cd aa &&
b1=$(git rev-parse origin/b1) &&
b2=$(git rev-parse origin/b2) &&
@@ -31,8 +31,16 @@ test_expect_success 'check tracking branches updated correctly after push' '
git commit -a -m aa-b2 &&
git checkout master &&
echo aa-master >>file &&
- git commit -a -m aa-master &&
- git push &&
+ git commit -a -m aa-master
+'
+
+test_expect_success 'mixed-success push returns error' '! git push'
+
+test_expect_success 'check tracking branches updated correctly after push' '
+ test "$(git rev-parse origin/master)" = "$(git rev-parse master)"
+'
+
+test_expect_success 'check tracking branches not updated for failed refs' '
test "$(git rev-parse origin/b1)" = "$b1" &&
test "$(git rev-parse origin/b2)" = "$b2"
'
--
1.5.3.5.1795.gf2a4e-dirty
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 2/3] send-pack: check ref->status before updating tracking refs
2007-11-17 12:53 [PATCH v3 0/3] tracking per-ref errors on push Jeff King
2007-11-17 12:54 ` [PATCH 1/3] send-pack: track errors for each ref Jeff King
@ 2007-11-17 12:55 ` Jeff King
2007-11-17 13:45 ` Alex Riesen
2007-11-17 18:05 ` Daniel Barkalow
2007-11-17 12:56 ` [PATCH 3/3] send-pack: assign remote errors to each ref Jeff King
2 siblings, 2 replies; 20+ messages in thread
From: Jeff King @ 2007-11-17 12:55 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, Alex Riesen, Pierre Habouzit, Daniel Barkalow
Previously, we manually checked the 'NONE' and 'UPTODATE'
conditions. Now that we have ref->status, we can easily
say "only update if we pushed successfully".
This adds a test for and fixes a regression introduced in
ed31df31 where deleted refs did not have their tracking
branches removed. This was due to a bogus per-ref error test
that is superseded by the more accurate ref->status flag.
Signed-off-by: Jeff King <peff@peff.net>
---
builtin-send-pack.c | 18 +++++-------------
t/t5404-tracking-branches.sh | 5 +++++
2 files changed, 10 insertions(+), 13 deletions(-)
diff --git a/builtin-send-pack.c b/builtin-send-pack.c
index 90ca2d3..c7d07aa 100644
--- a/builtin-send-pack.c
+++ b/builtin-send-pack.c
@@ -180,24 +180,17 @@ static int receive_status(int in)
static void update_tracking_ref(struct remote *remote, struct ref *ref)
{
struct refspec rs;
- int will_delete_ref;
- rs.src = ref->name;
- rs.dst = NULL;
-
- if (!ref->peer_ref)
+ if (ref->status != REF_STATUS_OK)
return;
- will_delete_ref = is_null_sha1(ref->peer_ref->new_sha1);
-
- if (!will_delete_ref &&
- !hashcmp(ref->old_sha1, ref->peer_ref->new_sha1))
- return;
+ rs.src = ref->name;
+ rs.dst = NULL;
if (!remote_find_tracking(remote, &rs)) {
if (args.verbose)
fprintf(stderr, "updating local tracking ref '%s'\n", rs.dst);
- if (is_null_sha1(ref->peer_ref->new_sha1)) {
+ if (ref->deletion) {
if (delete_ref(rs.dst, NULL))
error("Failed to delete");
} else
@@ -445,8 +438,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
if (!args.dry_run && remote) {
for (ref = remote_refs; ref; ref = ref->next)
- if (!is_null_sha1(ref->new_sha1))
- update_tracking_ref(remote, ref);
+ update_tracking_ref(remote, ref);
}
if (!new_refs)
diff --git a/t/t5404-tracking-branches.sh b/t/t5404-tracking-branches.sh
index 799e47e..1493a92 100755
--- a/t/t5404-tracking-branches.sh
+++ b/t/t5404-tracking-branches.sh
@@ -45,4 +45,9 @@ test_expect_success 'check tracking branches not updated for failed refs' '
test "$(git rev-parse origin/b2)" = "$b2"
'
+test_expect_success 'deleted branches have their tracking branches removed' '
+ git push origin :b1 &&
+ test "$(git rev-parse origin/b1)" = "origin/b1"
+'
+
test_done
--
1.5.3.5.1795.gf2a4e-dirty
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 3/3] send-pack: assign remote errors to each ref
2007-11-17 12:53 [PATCH v3 0/3] tracking per-ref errors on push Jeff King
2007-11-17 12:54 ` [PATCH 1/3] send-pack: track errors for each ref Jeff King
2007-11-17 12:55 ` [PATCH 2/3] send-pack: check ref->status before updating tracking refs Jeff King
@ 2007-11-17 12:56 ` Jeff King
2007-11-17 18:05 ` Daniel Barkalow
2007-11-18 1:03 ` Junio C Hamano
2 siblings, 2 replies; 20+ messages in thread
From: Jeff King @ 2007-11-17 12:56 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, Alex Riesen, Pierre Habouzit, Daniel Barkalow
This lets us show remote errors (e.g., a denied hook) along
with the usual push output.
There is a slightly clever optimization in receive_status
that bears explanation. We need to correlate the returned
status and our ref objects, which naively could be an O(m*n)
operation. However, since the current implementation of
receive-pack returns the errors to us in the same order that
we sent them, we optimistically look for the next ref to be
looked up to come after the last one we have found. So it
should be an O(m+n) merge if the receive-pack behavior
holds, but we fall back to a correct but slower behavior if
it should change.
Signed-off-by: Jeff King <peff@peff.net>
---
builtin-send-pack.c | 51 +++++++++++++++++++++++++++++++++++++++-----
cache.h | 2 +
t/t5406-remote-rejects.sh | 24 +++++++++++++++++++++
3 files changed, 71 insertions(+), 6 deletions(-)
create mode 100755 t/t5406-remote-rejects.sh
diff --git a/builtin-send-pack.c b/builtin-send-pack.c
index c7d07aa..bcf7143 100644
--- a/builtin-send-pack.c
+++ b/builtin-send-pack.c
@@ -146,19 +146,43 @@ static void get_local_heads(void)
for_each_ref(one_local_ref, NULL);
}
-static int receive_status(int in)
+static struct ref *set_ref_error(struct ref *refs, const char *line)
{
+ struct ref *ref;
+
+ for (ref = refs; ref; ref = ref->next) {
+ const char *msg;
+ if (prefixcmp(line, ref->name))
+ continue;
+ msg = line + strlen(ref->name);
+ if (*msg++ != ' ')
+ continue;
+ ref->status = REF_STATUS_REMOTE_REJECT;
+ ref->error = xstrdup(msg);
+ ref->error[strlen(ref->error)-1] = '\0';
+ return ref;
+ }
+ return NULL;
+}
+
+/* a return value of -1 indicates that an error occurred,
+ * but we were able to set individual ref errors. A return
+ * value of -2 means we couldn't even get that far. */
+static int receive_status(int in, struct ref *refs)
+{
+ struct ref *hint;
char line[1000];
int ret = 0;
int len = packet_read_line(in, line, sizeof(line));
if (len < 10 || memcmp(line, "unpack ", 7)) {
fprintf(stderr, "did not receive status back\n");
- return -1;
+ return -2;
}
if (memcmp(line, "unpack ok\n", 10)) {
fputs(line, stderr);
ret = -1;
}
+ hint = NULL;
while (1) {
len = packet_read_line(in, line, sizeof(line));
if (!len)
@@ -171,7 +195,10 @@ static int receive_status(int in)
}
if (!memcmp(line, "ok", 2))
continue;
- fputs(line, stderr);
+ if (hint)
+ hint = set_ref_error(hint, line + 3);
+ if (!hint)
+ hint = set_ref_error(refs, line + 3);
ret = -1;
}
return ret;
@@ -297,6 +324,12 @@ static void print_push_status(const char *dest, struct ref *refs)
print_ref_status('!', "[rejected]", ref, ref->peer_ref,
"non-fast forward");
break;
+ case REF_STATUS_REMOTE_REJECT:
+ if (ref->deletion)
+ print_ref_status('!', "[remote rejected]", ref, NULL, ref->error);
+ else
+ print_ref_status('!', "[remote rejected]", ref, ref->peer_ref, ref->error);
+ break;
case REF_STATUS_OK:
print_ok_ref_status(ref);
break;
@@ -312,6 +345,7 @@ 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 flags = MATCH_REFS_NONE;
+ int ret;
if (args.send_all)
flags |= MATCH_REFS_ALL;
@@ -429,12 +463,15 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
}
close(out);
- print_push_status(dest, remote_refs);
-
if (expect_status_report) {
- if (receive_status(in))
+ ret = receive_status(in, remote_refs);
+ if (ret == -2)
return -1;
}
+ else
+ ret = 0;
+
+ print_push_status(dest, remote_refs);
if (!args.dry_run && remote) {
for (ref = remote_refs; ref; ref = ref->next)
@@ -443,6 +480,8 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
if (!new_refs)
fprintf(stderr, "Everything up-to-date\n");
+ if (ret < 0)
+ return ret;
for (ref = remote_refs; ref; ref = ref->next) {
switch (ref->status) {
case REF_STATUS_NONE:
diff --git a/cache.h b/cache.h
index 2768342..ba9178f 100644
--- a/cache.h
+++ b/cache.h
@@ -510,7 +510,9 @@ struct ref {
REF_STATUS_REJECT_NONFASTFORWARD,
REF_STATUS_REJECT_NODELETE,
REF_STATUS_UPTODATE,
+ REF_STATUS_REMOTE_REJECT,
} status;
+ char *error;
struct ref *peer_ref; /* when renaming */
char name[FLEX_ARRAY]; /* more */
};
diff --git a/t/t5406-remote-rejects.sh b/t/t5406-remote-rejects.sh
new file mode 100755
index 0000000..46b2cb4
--- /dev/null
+++ b/t/t5406-remote-rejects.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+test_description='remote push rejects are reported by client'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+ mkdir .git/hooks &&
+ (echo "#!/bin/sh" ; echo "exit 1") >.git/hooks/update &&
+ chmod +x .git/hooks/update &&
+ echo 1 >file &&
+ git add file &&
+ git commit -m 1 &&
+ git clone . child &&
+ cd child &&
+ echo 2 >file &&
+ git commit -a -m 2
+'
+
+test_expect_success 'push reports error' '! git push 2>stderr'
+
+test_expect_success 'individual ref reports error' 'grep rejected stderr'
+
+test_done
--
1.5.3.5.1795.gf2a4e-dirty
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH 1/3] send-pack: track errors for each ref
2007-11-17 12:54 ` [PATCH 1/3] send-pack: track errors for each ref Jeff King
@ 2007-11-17 13:34 ` Alex Riesen
2007-11-17 18:05 ` Daniel Barkalow
2007-11-17 20:53 ` Junio C Hamano
2 siblings, 0 replies; 20+ messages in thread
From: Alex Riesen @ 2007-11-17 13:34 UTC (permalink / raw)
To: Jeff King; +Cc: Junio C Hamano, git, Pierre Habouzit, Daniel Barkalow
Jeff King, Sat, Nov 17, 2007 13:54:27 +0100:
> Instead of keeping the 'ret' variable, we instead have a
> status flag for each ref that tracks what happened to it.
> We then print the ref status after all of the refs have
> been examined.
>
> This paves the way for three improvements:
> - updating tracking refs only for non-error refs
> - incorporating remote rejection into the printed status
> - printing errors in a different order than we processed
> (e.g., consolidating non-ff errors near the end with
> a special message)
>
> Signed-off-by: Jeff King <peff@peff.net>
Acked-by: Alex Riesen <raa.lkml@gmail.com>
Still would like to see the deletion of tracing branches checked.
Like this perhaps?
diff --git a/t/t5404-tracking-branches.sh b/t/t5404-tracking-branches.sh
index 799e47e..4fe4a07 100755
--- a/t/t5404-tracking-branches.sh
+++ b/t/t5404-tracking-branches.sh
@@ -10,6 +10,7 @@ test_expect_success 'setup' '
git commit -m 1 &&
git branch b1 &&
git branch b2 &&
+ git branch b3 &&
git clone . aa &&
git checkout b1 &&
echo b1 >>file &&
@@ -23,6 +24,7 @@ test_expect_success 'prepare pushable branches' '
cd aa &&
b1=$(git rev-parse origin/b1) &&
b2=$(git rev-parse origin/b2) &&
+ b3=$(git rev-parse origin/b3) &&
git checkout -b b1 origin/b1 &&
echo aa-b1 >>file &&
git commit -a -m aa-b1 &&
@@ -45,4 +47,12 @@ test_expect_success 'check tracking branches not updated for failed refs' '
test "$(git rev-parse origin/b2)" = "$b2"
'
+test_expect_success 'delete remote branch' '
+ git push origin :refs/heads/b3 &&
+ {
+ git rev-parse --verify origin/b3
+ test $? != 0
+ }
+'
+
test_done
--
1.5.3.5.747.gf06543
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH 2/3] send-pack: check ref->status before updating tracking refs
2007-11-17 12:55 ` [PATCH 2/3] send-pack: check ref->status before updating tracking refs Jeff King
@ 2007-11-17 13:45 ` Alex Riesen
2007-11-17 13:53 ` Jeff King
2007-11-17 18:05 ` Daniel Barkalow
1 sibling, 1 reply; 20+ messages in thread
From: Alex Riesen @ 2007-11-17 13:45 UTC (permalink / raw)
To: Jeff King; +Cc: Junio C Hamano, git, Pierre Habouzit, Daniel Barkalow
Jeff King, Sat, Nov 17, 2007 13:55:15 +0100:
> diff --git a/t/t5404-tracking-branches.sh b/t/t5404-tracking-branches.sh
> index 799e47e..1493a92 100755
> --- a/t/t5404-tracking-branches.sh
> +++ b/t/t5404-tracking-branches.sh
> @@ -45,4 +45,9 @@ test_expect_success 'check tracking branches not updated for failed refs' '
> test "$(git rev-parse origin/b2)" = "$b2"
> '
>
> +test_expect_success 'deleted branches have their tracking branches removed' '
> + git push origin :b1 &&
> + test "$(git rev-parse origin/b1)" = "origin/b1"
> +'
> +
> test_done
Oh, missed that.
Completely-Acked-By: Alex "Sleepy" Riesen <raa.lkml@gmail.com>
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 2/3] send-pack: check ref->status before updating tracking refs
2007-11-17 13:45 ` Alex Riesen
@ 2007-11-17 13:53 ` Jeff King
0 siblings, 0 replies; 20+ messages in thread
From: Jeff King @ 2007-11-17 13:53 UTC (permalink / raw)
To: Alex Riesen; +Cc: Junio C Hamano, git, Pierre Habouzit, Daniel Barkalow
On Sat, Nov 17, 2007 at 02:45:46PM +0100, Alex Riesen wrote:
> > +test_expect_success 'deleted branches have their tracking branches removed' '
> > + git push origin :b1 &&
> > + test "$(git rev-parse origin/b1)" = "origin/b1"
> > +'
> > +
> > test_done
>
> Oh, missed that.
>
> Completely-Acked-By: Alex "Sleepy" Riesen <raa.lkml@gmail.com>
Yes, I didn't put it in the first patch, because it was broken there. ;)
-Peff
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 3/3] send-pack: assign remote errors to each ref
2007-11-17 12:56 ` [PATCH 3/3] send-pack: assign remote errors to each ref Jeff King
@ 2007-11-17 18:05 ` Daniel Barkalow
2007-11-18 0:03 ` Jeff King
2007-11-18 1:03 ` Junio C Hamano
1 sibling, 1 reply; 20+ messages in thread
From: Daniel Barkalow @ 2007-11-17 18:05 UTC (permalink / raw)
To: Jeff King; +Cc: Junio C Hamano, git, Alex Riesen, Pierre Habouzit
On Sat, 17 Nov 2007, Jeff King wrote:
> This lets us show remote errors (e.g., a denied hook) along
> with the usual push output.
>
> There is a slightly clever optimization in receive_status
> that bears explanation. We need to correlate the returned
> status and our ref objects, which naively could be an O(m*n)
> operation. However, since the current implementation of
> receive-pack returns the errors to us in the same order that
> we sent them, we optimistically look for the next ref to be
> looked up to come after the last one we have found. So it
> should be an O(m+n) merge if the receive-pack behavior
> holds, but we fall back to a correct but slower behavior if
> it should change.
>
> Signed-off-by: Jeff King <peff@peff.net>
> ---
> builtin-send-pack.c | 51 +++++++++++++++++++++++++++++++++++++++-----
> cache.h | 2 +
> t/t5406-remote-rejects.sh | 24 +++++++++++++++++++++
> 3 files changed, 71 insertions(+), 6 deletions(-)
> create mode 100755 t/t5406-remote-rejects.sh
>
> diff --git a/builtin-send-pack.c b/builtin-send-pack.c
> index c7d07aa..bcf7143 100644
> --- a/builtin-send-pack.c
> +++ b/builtin-send-pack.c
> @@ -146,19 +146,43 @@ static void get_local_heads(void)
> for_each_ref(one_local_ref, NULL);
> }
>
> -static int receive_status(int in)
> +static struct ref *set_ref_error(struct ref *refs, const char *line)
> {
> + struct ref *ref;
> +
> + for (ref = refs; ref; ref = ref->next) {
> + const char *msg;
> + if (prefixcmp(line, ref->name))
> + continue;
> + msg = line + strlen(ref->name);
> + if (*msg++ != ' ')
> + continue;
> + ref->status = REF_STATUS_REMOTE_REJECT;
> + ref->error = xstrdup(msg);
> + ref->error[strlen(ref->error)-1] = '\0';
> + return ref;
> + }
> + return NULL;
> +}
Maybe this should take both the full list and the hint and do both passes
internally? IMHO, the logic in receive_status() looks like it might be
setting the error twice or not at all, unless you read very carefully.
But, regardless,
Acked-by: Daniel Barkalow <barkalow@iabervon.org>
-Daniel
*This .sig left intentionally blank*
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 2/3] send-pack: check ref->status before updating tracking refs
2007-11-17 12:55 ` [PATCH 2/3] send-pack: check ref->status before updating tracking refs Jeff King
2007-11-17 13:45 ` Alex Riesen
@ 2007-11-17 18:05 ` Daniel Barkalow
1 sibling, 0 replies; 20+ messages in thread
From: Daniel Barkalow @ 2007-11-17 18:05 UTC (permalink / raw)
To: Jeff King; +Cc: Junio C Hamano, git, Alex Riesen, Pierre Habouzit
On Sat, 17 Nov 2007, Jeff King wrote:
> Previously, we manually checked the 'NONE' and 'UPTODATE'
> conditions. Now that we have ref->status, we can easily
> say "only update if we pushed successfully".
>
> This adds a test for and fixes a regression introduced in
> ed31df31 where deleted refs did not have their tracking
> branches removed. This was due to a bogus per-ref error test
> that is superseded by the more accurate ref->status flag.
>
> Signed-off-by: Jeff King <peff@peff.net>
Acked-by: Daniel Barkalow <barkalow@iabervon.org>
-Daniel
*This .sig left intentionally blank*
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 1/3] send-pack: track errors for each ref
2007-11-17 12:54 ` [PATCH 1/3] send-pack: track errors for each ref Jeff King
2007-11-17 13:34 ` Alex Riesen
@ 2007-11-17 18:05 ` Daniel Barkalow
2007-11-18 0:13 ` Jeff King
2007-11-17 20:53 ` Junio C Hamano
2 siblings, 1 reply; 20+ messages in thread
From: Daniel Barkalow @ 2007-11-17 18:05 UTC (permalink / raw)
To: Jeff King; +Cc: Junio C Hamano, git, Alex Riesen, Pierre Habouzit
On Sat, 17 Nov 2007, Jeff King wrote:
> diff --git a/builtin-send-pack.c b/builtin-send-pack.c
> index 418925e..90ca2d3 100644
> --- a/builtin-send-pack.c
> +++ b/builtin-send-pack.c
> @@ -218,15 +219,105 @@ static const char *prettify_ref(const char *name)
>
> #define SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)
>
> +static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg)
Isn't "from" always "to->peer_ref"? It'd be nice to make this function
unable to print something different from what we actually did. (Actually
it might be "to->deletion ? NULL : to->peer_ref", but that would also be
better to have as an explicit feature of how you display "to", rather than
implicit in the set of callers.
> +static const char *status_abbrev(unsigned char sha1[20])
> +{
> + const char *abbrev;
> + abbrev = find_unique_abbrev(sha1, DEFAULT_ABBREV);
> + return abbrev ? abbrev : sha1_to_hex(sha1);
> +}
Maybe we should have a find_unique_abbrev()-like function that doesn't
mind if the requested object doesn't exist?
> +
> +static void print_ok_ref_status(struct ref *ref)
> +{
> + if (ref->deletion)
> + print_ref_status('-', "[deleted]", ref, NULL, NULL);
> + else if (is_null_sha1(ref->old_sha1))
> + print_ref_status('*',
> + (!prefixcmp(ref->name, "refs/tags/") ? "[new tag]" :
> + "[new branch]"),
> + ref, ref->peer_ref, NULL);
> + else {
> + char quickref[83];
Shouldn't this be 40 + 3 + 40 + 1?
> + char type;
> + const char *msg;
> +
> + strcpy(quickref, status_abbrev(ref->old_sha1));
> + if (ref->nonfastforward) {
> + strcat(quickref, "...");
> + type = '+';
> + msg = " (forced update)";
> + }
> + else {
Coding style, IIRC.
Regardless of these nits, it all looks good to me.
Acked-by: Daniel Barkalow <barkalow@iabervon.org>
-Daniel
*This .sig left intentionally blank*
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 1/3] send-pack: track errors for each ref
2007-11-17 12:54 ` [PATCH 1/3] send-pack: track errors for each ref Jeff King
2007-11-17 13:34 ` Alex Riesen
2007-11-17 18:05 ` Daniel Barkalow
@ 2007-11-17 20:53 ` Junio C Hamano
2007-11-18 0:15 ` Jeff King
2 siblings, 1 reply; 20+ messages in thread
From: Junio C Hamano @ 2007-11-17 20:53 UTC (permalink / raw)
To: Jeff King; +Cc: git, Alex Riesen, Pierre Habouzit, Daniel Barkalow
Jeff King <peff@peff.net> writes:
> Instead of keeping the 'ret' variable, we instead have a
> status flag for each ref that tracks what happened to it.
> We then print the ref status after all of the refs have
> been examined.
>
> This paves the way for three improvements:
> - updating tracking refs only for non-error refs
> - incorporating remote rejection into the printed status
> - printing errors in a different order than we processed
> (e.g., consolidating non-ff errors near the end with
> a special message)
Looks good.
Except that
> @@ -218,15 +219,105 @@ static const char *prettify_ref(const char *name)
>
> #define SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)
>
> +static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg)
> +{
> + fprintf(stderr, " %c %-*s ", flag, SUMMARY_WIDTH, summary);
> + if (from)
> + fprintf(stderr, "%s -> %s", prettify_ref(from), prettify_ref(to));
> + else
> + fputs(prettify_ref(to), stderr);
> + if (msg) {
> + fputs(" (", stderr);
> + fputs(msg, stderr);
> + fputc(')', stderr);
> + }
> + fputc('\n', stderr);
> +}
msg is parenthesized here, so...
> +static void print_ok_ref_status(struct ref *ref)
> +{
> + if (ref->deletion)
> + print_ref_status('-', "[deleted]", ref, NULL, NULL);
> + else if (is_null_sha1(ref->old_sha1))
> + print_ref_status('*',
> + (!prefixcmp(ref->name, "refs/tags/") ? "[new tag]" :
> + "[new branch]"),
> + ref, ref->peer_ref, NULL);
> + else {
> + char quickref[83];
> + char type;
> + const char *msg;
> +
> + strcpy(quickref, status_abbrev(ref->old_sha1));
> + if (ref->nonfastforward) {
> + strcat(quickref, "...");
> + type = '+';
> + msg = " (forced update)";
... you do not need the " (" and ")" here.
All merged to 'next'. Thanks.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 3/3] send-pack: assign remote errors to each ref
2007-11-17 18:05 ` Daniel Barkalow
@ 2007-11-18 0:03 ` Jeff King
0 siblings, 0 replies; 20+ messages in thread
From: Jeff King @ 2007-11-18 0:03 UTC (permalink / raw)
To: Daniel Barkalow; +Cc: Junio C Hamano, git, Alex Riesen, Pierre Habouzit
On Sat, Nov 17, 2007 at 01:05:29PM -0500, Daniel Barkalow wrote:
> Maybe this should take both the full list and the hint and do both passes
> internally? IMHO, the logic in receive_status() looks like it might be
> setting the error twice or not at all, unless you read very carefully.
Not unreasonable, though I started in that direction and it ended up
being less readable (which isn't to say that it's not possible). But it
looks like Junio has merged to next, so I think it is best to leave it
as-is.
-Peff
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 1/3] send-pack: track errors for each ref
2007-11-17 18:05 ` Daniel Barkalow
@ 2007-11-18 0:13 ` Jeff King
2007-11-18 1:21 ` Junio C Hamano
0 siblings, 1 reply; 20+ messages in thread
From: Jeff King @ 2007-11-18 0:13 UTC (permalink / raw)
To: Daniel Barkalow; +Cc: Junio C Hamano, git, Alex Riesen, Pierre Habouzit
On Sat, Nov 17, 2007 at 01:05:35PM -0500, Daniel Barkalow wrote:
> > +static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg)
>
> Isn't "from" always "to->peer_ref"? It'd be nice to make this function
> unable to print something different from what we actually did. (Actually
> it might be "to->deletion ? NULL : to->peer_ref", but that would also be
> better to have as an explicit feature of how you display "to", rather than
> implicit in the set of callers.
Yes, I also considered changing "from" to "show peer" which might have
been nicer. I am not opposed to such a cleanup, but again, not sure if
it worth it now that we are merged.
> > +static const char *status_abbrev(unsigned char sha1[20])
> > +{
> > + const char *abbrev;
> > + abbrev = find_unique_abbrev(sha1, DEFAULT_ABBREV);
> > + return abbrev ? abbrev : sha1_to_hex(sha1);
> > +}
>
> Maybe we should have a find_unique_abbrev()-like function that doesn't
> mind if the requested object doesn't exist?
I agree, though I don't feel qualified to comment on what other places
that should be used (I was a bit surprised to find out that
find_unique_abbrev ever returned NULL, but changing the semantics at
this point is probably going to cause some subtle bug).
> > + char quickref[83];
> Shouldn't this be 40 + 3 + 40 + 1?
Oops, yes. I think it should be hard to trigger (both commits would have
to either not be in your db, or not be unique to 40 digits). But clearly
it should be fixed, and it looks like Junio did.
It was a stupid cut-and-paste from Nicolas' fetch code, but it looks
like he correctly allocates 84 bytes for the "..." case.
> > + char type;
> > + const char *msg;
> > +
> > + strcpy(quickref, status_abbrev(ref->old_sha1));
> > + if (ref->nonfastforward) {
> > + strcat(quickref, "...");
> > + type = '+';
> > + msg = " (forced update)";
> > + }
> > + else {
>
> Coding style, IIRC.
Sorry, I don't see the style nit you're mentioning here.
-Peff
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 1/3] send-pack: track errors for each ref
2007-11-17 20:53 ` Junio C Hamano
@ 2007-11-18 0:15 ` Jeff King
0 siblings, 0 replies; 20+ messages in thread
From: Jeff King @ 2007-11-18 0:15 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, Alex Riesen, Pierre Habouzit, Daniel Barkalow
On Sat, Nov 17, 2007 at 12:53:14PM -0800, Junio C Hamano wrote:
> > + strcpy(quickref, status_abbrev(ref->old_sha1));
> > + if (ref->nonfastforward) {
> > + strcat(quickref, "...");
> > + type = '+';
> > + msg = " (forced update)";
>
> ... you do not need the " (" and ")" here.
Oops, good catch.
> All merged to 'next'. Thanks.
I see you fixed up the off-by-one buffer, too. Thanks.
-Peff
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 3/3] send-pack: assign remote errors to each ref
2007-11-17 12:56 ` [PATCH 3/3] send-pack: assign remote errors to each ref Jeff King
2007-11-17 18:05 ` Daniel Barkalow
@ 2007-11-18 1:03 ` Junio C Hamano
2007-11-18 2:39 ` Jeff King
1 sibling, 1 reply; 20+ messages in thread
From: Junio C Hamano @ 2007-11-18 1:03 UTC (permalink / raw)
To: Jeff King; +Cc: git, Alex Riesen, Pierre Habouzit, Daniel Barkalow
Jeff King <peff@peff.net> writes:
> diff --git a/builtin-send-pack.c b/builtin-send-pack.c
> index c7d07aa..bcf7143 100644
> --- a/builtin-send-pack.c
> +++ b/builtin-send-pack.c
> @@ -146,19 +146,43 @@ static void get_local_heads(void)
> for_each_ref(one_local_ref, NULL);
> }
>
> -static int receive_status(int in)
> +static struct ref *set_ref_error(struct ref *refs, const char *line)
> {
> + struct ref *ref;
> +
> + for (ref = refs; ref; ref = ref->next) {
> + const char *msg;
> + if (prefixcmp(line, ref->name))
> + continue;
> + msg = line + strlen(ref->name);
> + if (*msg++ != ' ')
> + continue;
> + ref->status = REF_STATUS_REMOTE_REJECT;
> + ref->error = xstrdup(msg);
> + ref->error[strlen(ref->error)-1] = '\0';
> + return ref;
> + }
> + return NULL;
> +}
It probably would not matter for sane repositories, but with
thousands of refs, strlen() and prefixcmp() may start to hurt:
struct ref *ref;
int reflen;
const char *msg = strchr(line, ' ');
if (!msg)
return NULL;
reflen = msg - line;
msg++;
for (ref = refs; ref; ref = ref->next) {
if (strncmp(line, ref->name, reflen) || line[reflen] != ' ')
continue;
...
return ref->next;
}
return NULL;
but the "hint" optimization probably make the above
micro-optimization irrelevant.
> +/* a return value of -1 indicates that an error occurred,
> + * but we were able to set individual ref errors. A return
> + * value of -2 means we couldn't even get that far. */
It is preferred to have a multi-line comment like this:
/*
* A return value of -1 ...
* ...
* ... couldn't even get that far.
*/
> +static int receive_status(int in, struct ref *refs)
> ...
> + hint = NULL;
> while (1) {
> len = packet_read_line(in, line, sizeof(line));
> if (!len)
> @@ -171,7 +195,10 @@ static int receive_status(int in)
> }
> if (!memcmp(line, "ok", 2))
> continue;
> - fputs(line, stderr);
> + if (hint)
> + hint = set_ref_error(hint, line + 3);
> + if (!hint)
> + hint = set_ref_error(refs, line + 3);
Clever... taking advantage of the order receive-pack reports to
optimize.
Before receive_status() is called, can the refs already have the
error status and string set?
> @@ -429,12 +463,15 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
> }
> close(out);
>
> - print_push_status(dest, remote_refs);
> -
> if (expect_status_report) {
> - if (receive_status(in))
> + ret = receive_status(in, remote_refs);
> + if (ret == -2)
> return -1;
Hmm. When we did not receive status, we cannot tell what
succeeded or failed, but what we _can_ tell the user is which
refs we attempted to push. I wonder if robbing that information
from the user with this "return -1" is a good idea. Perhaps we
would instead want to set the status of all the refs to error
and call print_push_status() anyway? I dunno.
> }
> + else
> + ret = 0;
> +
> + print_push_status(dest, remote_refs);
>
> if (!args.dry_run && remote) {
> for (ref = remote_refs; ref; ref = ref->next)
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 1/3] send-pack: track errors for each ref
2007-11-18 0:13 ` Jeff King
@ 2007-11-18 1:21 ` Junio C Hamano
2007-11-18 3:12 ` Jeff King
0 siblings, 1 reply; 20+ messages in thread
From: Junio C Hamano @ 2007-11-18 1:21 UTC (permalink / raw)
To: Jeff King; +Cc: Daniel Barkalow, git, Alex Riesen, Pierre Habouzit
Jeff King <peff@peff.net> writes:
> On Sat, Nov 17, 2007 at 01:05:35PM -0500, Daniel Barkalow wrote:
>
>> > + if (ref->nonfastforward) {
>> > + strcat(quickref, "...");
>> > + type = '+';
>> > + msg = " (forced update)";
>> > + }
>> > + else {
>>
>> Coding style, IIRC.
>
> Sorry, I don't see the style nit you're mentioning here.
I think Daniel is referring to "Put 'else' on the same line as
the brace that closes the corresponding 'if' opened", iow:
if (...) {
...
} else {
...
}
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 3/3] send-pack: assign remote errors to each ref
2007-11-18 1:03 ` Junio C Hamano
@ 2007-11-18 2:39 ` Jeff King
2007-11-18 4:47 ` Junio C Hamano
0 siblings, 1 reply; 20+ messages in thread
From: Jeff King @ 2007-11-18 2:39 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, Alex Riesen, Pierre Habouzit, Daniel Barkalow
On Sat, Nov 17, 2007 at 05:03:57PM -0800, Junio C Hamano wrote:
> > + for (ref = refs; ref; ref = ref->next) {
> > + const char *msg;
> > + if (prefixcmp(line, ref->name))
> > + continue;
>
> It probably would not matter for sane repositories, but with
> thousands of refs, strlen() and prefixcmp() may start to hurt:
It is actually _just_ prefixcmp. Or do you mean the strlen we call in
prefixcmp? If so, I think the right solution is to make prefixcmp
faster. :)
> but the "hint" optimization probably make the above
> micro-optimization irrelevant.
Agreed.
> It is preferred to have a multi-line comment like this:
>
> /*
> * A return value of -1 ...
> * ...
> * ... couldn't even get that far.
> */
OK. Since it is already in next, do you want a style fixup patch?
> Before receive_status() is called, can the refs already have the
> error status and string set?
Nothing else sets the string, so the latter is not possible (perhaps it
should be "remote_error" for clarity). It is less clear that we are not
overwriting another status; however, if you look at do_send_pack, we
only actually send the remote refs that are getting REF_STATUS_OK.
A broken or malicious remote could change the push status of an
arbitrary ref to rejection, but I don't really see the point. We could
explicitly check that we are changing from OK to REMOTE_REJECTED in
set_ref_error.
> > if (expect_status_report) {
> > - if (receive_status(in))
> > + ret = receive_status(in, remote_refs);
> > + if (ret == -2)
> > return -1;
>
> Hmm. When we did not receive status, we cannot tell what
> succeeded or failed, but what we _can_ tell the user is which
> refs we attempted to push. I wonder if robbing that information
> from the user with this "return -1" is a good idea. Perhaps we
> would instead want to set the status of all the refs to error
> and call print_push_status() anyway? I dunno.
That is a reasonable behavior (although they have already seen an
"error: " message, I think). We might also consider returning something
besides "-1" to differentiate "ok, but some refs failed" from "terribly
broken". The old code used to use "-2" and "-4", but I checked and all
of the error checking paths seemed to end up as a boolean.
I can work up a patch if there is consensus.
-Peff
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 1/3] send-pack: track errors for each ref
2007-11-18 1:21 ` Junio C Hamano
@ 2007-11-18 3:12 ` Jeff King
0 siblings, 0 replies; 20+ messages in thread
From: Jeff King @ 2007-11-18 3:12 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Daniel Barkalow, git, Alex Riesen, Pierre Habouzit
On Sat, Nov 17, 2007 at 05:21:59PM -0800, Junio C Hamano wrote:
> > Sorry, I don't see the style nit you're mentioning here.
>
> I think Daniel is referring to "Put 'else' on the same line as
> the brace that closes the corresponding 'if' opened", iow:
>
> if (...) {
> ...
> } else {
> ...
> }
Ah. We are really inconsistent about that (I count about 333 non-cuddled
(but possible to cuddle) versus 499 cuddled). Should we put something in
the CodingGuidelines? I am also happy to roll this change into a style
patch.
For reference, I counted with:
# cuddled:
grep '} *else' *.c | wc -l
# possible but non-cuddled
# when we find an 'else', if the previous line had a '}'
# on it, then it is a hit. There are a few false positives
# when the "} else" is from an outer block scope
# And no, this sed invocation probably isn't totally portable. :)
sed -n '/else/{x; /}/{x;p}}; h' *.c | wc -l
# or to check the accuracy
sed -n '/else/{x; /}/{p;x;p}}; h' *.c
-Peff
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 3/3] send-pack: assign remote errors to each ref
2007-11-18 2:39 ` Jeff King
@ 2007-11-18 4:47 ` Junio C Hamano
2007-11-18 5:00 ` Jeff King
0 siblings, 1 reply; 20+ messages in thread
From: Junio C Hamano @ 2007-11-18 4:47 UTC (permalink / raw)
To: Jeff King; +Cc: git, Alex Riesen, Pierre Habouzit, Daniel Barkalow
Jeff King <peff@peff.net> writes:
> On Sat, Nov 17, 2007 at 05:03:57PM -0800, Junio C Hamano wrote:
>
>> > + for (ref = refs; ref; ref = ref->next) {
>> > + const char *msg;
>> > + if (prefixcmp(line, ref->name))
>> > + continue;
>>
>> It probably would not matter for sane repositories, but with
>> thousands of refs, strlen() and prefixcmp() may start to hurt:
>
> It is actually _just_ prefixcmp. Or do you mean the strlen we call in
> prefixcmp? If so, I think the right solution is to make prefixcmp
> faster. :)
I was referring to strlen(ref->name) taken for all refs during
the loop. Micro-optimized one finds the end of refname on the
"ng" line once before entering the loop.
> OK. Since it is already in next, do you want a style fixup patch?
I do not think it is particularly a big deal -- perhaps clean it
before we touch the vicinity of the code next time. The same
goes for the "} else {" stuff.
>> Before receive_status() is called, can the refs already have the
>> error status and string set?
>
> Nothing else sets the string, so the latter is not possible (perhaps it
> should be "remote_error" for clarity). It is less clear that we are not
> ... if you look at do_send_pack, we
> only actually send the remote refs that are getting REF_STATUS_OK.
Ah, Ok.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 3/3] send-pack: assign remote errors to each ref
2007-11-18 4:47 ` Junio C Hamano
@ 2007-11-18 5:00 ` Jeff King
0 siblings, 0 replies; 20+ messages in thread
From: Jeff King @ 2007-11-18 5:00 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, Alex Riesen, Pierre Habouzit, Daniel Barkalow
On Sat, Nov 17, 2007 at 08:47:11PM -0800, Junio C Hamano wrote:
>>> + for (ref = refs; ref; ref = ref->next) {
>>> + const char *msg;
>>> + if (prefixcmp(line, ref->name))
>>> + continue;
>>> + msg = line + strlen(ref->name);
>>> + if (*msg++ != ' ')
>>> + continue;
>>> + ref->status = REF_STATUS_REMOTE_REJECT;
>>> + ref->error = xstrdup(msg);
>>> + ref->error[strlen(ref->error)-1] = '\0';
>>> + return ref;
>>> + }
>>> + return NULL;
>>> +}
> > It is actually _just_ prefixcmp. Or do you mean the strlen we call in
> > prefixcmp? If so, I think the right solution is to make prefixcmp
> > faster. :)
> I was referring to strlen(ref->name) taken for all refs during
> the loop. Micro-optimized one finds the end of refname on the
> "ng" line once before entering the loop.
I don't see such a strlen, except in the implementation of prefixcmp,
because we continue most of the time based on its result. If you have a
false match on the prefixcmp (i.e., a prefix of another ref), you do an
extra strlen.
But I don't think this is worth micro-optimizing.
-Peff
^ permalink raw reply [flat|nested] 20+ messages in thread
end of thread, other threads:[~2007-11-18 5:00 UTC | newest]
Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-11-17 12:53 [PATCH v3 0/3] tracking per-ref errors on push Jeff King
2007-11-17 12:54 ` [PATCH 1/3] send-pack: track errors for each ref Jeff King
2007-11-17 13:34 ` Alex Riesen
2007-11-17 18:05 ` Daniel Barkalow
2007-11-18 0:13 ` Jeff King
2007-11-18 1:21 ` Junio C Hamano
2007-11-18 3:12 ` Jeff King
2007-11-17 20:53 ` Junio C Hamano
2007-11-18 0:15 ` Jeff King
2007-11-17 12:55 ` [PATCH 2/3] send-pack: check ref->status before updating tracking refs Jeff King
2007-11-17 13:45 ` Alex Riesen
2007-11-17 13:53 ` Jeff King
2007-11-17 18:05 ` Daniel Barkalow
2007-11-17 12:56 ` [PATCH 3/3] send-pack: assign remote errors to each ref Jeff King
2007-11-17 18:05 ` Daniel Barkalow
2007-11-18 0:03 ` Jeff King
2007-11-18 1:03 ` Junio C Hamano
2007-11-18 2:39 ` Jeff King
2007-11-18 4:47 ` Junio C Hamano
2007-11-18 5:00 ` Jeff King
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).