* git clone silently aborts if stdout gets a broken pipe
@ 2013-09-18 16:52 Peter Kjellerstedt
2013-09-18 18:45 ` Jeff King
0 siblings, 1 reply; 11+ messages in thread
From: Peter Kjellerstedt @ 2013-09-18 16:52 UTC (permalink / raw)
To: git@vger.kernel.org
[-- Attachment #1: Type: text/plain, Size: 1028 bytes --]
One of our Perl scripts that does a git clone suddenly
started to fail when I upgraded to git 1.8.4 from 1.8.3.1.
The failing Perl code used a construct like this:
Git::command_oneline('clone', $url, $path);
There is no error raised, but the directory specified by
$path is not created. If I look at the process using strace
I can see the clone taking place, but then it seems to get
a broken pipe since the code above only cares about the
first line from stdout (and with the addition of "Checking
connectivity..." git clone now outputs two lines to stdout).
If I change the code to:
my @foo = Git::command('clone', $url, $path);
it works as expected.
I have attached a simple Perl script that shows the problem.
Run it as "clone_test.pl <git url>". With git 1.8.4 it will
fail for the first two test cases, whereas with older git
versions it succeeds for all four test cases.
I hope this is enough information for someone to look into
this regression.
Best regards,
//Peter
[-- Attachment #2: clone_test.pl --]
[-- Type: application/octet-stream, Size: 796 bytes --]
#!/bin/perl
use Git;
my $url = $ARGV[0] || die("You need to specify a Git URL!\n");
my $path = 'clone_test';
system("rm -rf ${path}1");
Git::command_oneline('clone', "$url", "${path}1");
warn("Failed to clone to ${path}1!\n") unless (-d "${path}1");
system("rm -rf ${path}2");
my $foo = Git::command_oneline('clone', $url, "${path}2");
warn("Failed to clone to ${path}2!\n") unless (-d "${path}2");
system("rm -rf ${path}3");
my $foo = Git::command('clone', $url, "${path}3");
warn("Failed to clone to ${path}3!\n") unless (-d "${path}3");
system("rm -rf ${path}4");
my @foo = Git::command('clone', $url, "${path}4");
warn("Failed to clone to ${path}4!\n") unless (-d "${path}4");
system("rm -rf ${path}1");
system("rm -rf ${path}2");
system("rm -rf ${path}3");
system("rm -rf ${path}4");
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: git clone silently aborts if stdout gets a broken pipe
2013-09-18 16:52 git clone silently aborts if stdout gets a broken pipe Peter Kjellerstedt
@ 2013-09-18 18:45 ` Jeff King
2013-09-18 19:04 ` Jeff King
2013-09-19 7:54 ` git clone silently aborts if stdout gets a broken pipe Peter Kjellerstedt
0 siblings, 2 replies; 11+ messages in thread
From: Jeff King @ 2013-09-18 18:45 UTC (permalink / raw)
To: Peter Kjellerstedt
Cc: Junio C Hamano, Nguyen Thai Ngoc Duy, git@vger.kernel.org
On Wed, Sep 18, 2013 at 06:52:13PM +0200, Peter Kjellerstedt wrote:
> The failing Perl code used a construct like this:
>
> Git::command_oneline('clone', $url, $path);
>
> There is no error raised, but the directory specified by
> $path is not created. If I look at the process using strace
> I can see the clone taking place, but then it seems to get
> a broken pipe since the code above only cares about the
> first line from stdout (and with the addition of "Checking
> connectivity..." git clone now outputs two lines to stdout).
I think your perl script is somewhat questionable, as it is making
assumptions about the output of git-clone, and you would do better to
accept arbitrary-sized output (or better yet, leave stdout pointing to
the user, so they can see the output, which is meant for them).
That being said, the new messages should almost certainly go to stderr.
-- >8 --
Subject: [PATCH] clone: write "checking connectivity" to stderr
In commit 0781aa4 (clone: let the user know when
check_everything_connected is run, 2013-05-03), we started
giving the user a progress report during clone. However,
since the actual work happens in a sub-process, we do not
use the usual progress code that counts the objects, but
rather just print a message ourselves.
This message goes to stdout via printf, which is unlike
other progress messages (both the eye candy within clone,
and the "checking connectivity" progress in other commands).
Let's send it to stderr for consistency.
Signed-off-by: Jeff King <peff@peff.net>
---
builtin/clone.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/builtin/clone.c b/builtin/clone.c
index ca3eb68..3c91844 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -551,12 +551,12 @@ static void update_remote_refs(const struct ref *refs,
if (check_connectivity) {
if (0 <= option_verbosity)
- printf(_("Checking connectivity... "));
+ fprintf(stderr, _("Checking connectivity... "));
if (check_everything_connected_with_transport(iterate_ref_map,
0, &rm, transport))
die(_("remote did not send all necessary objects"));
if (0 <= option_verbosity)
- printf(_("done\n"));
+ fprintf(stderr, _("done\n"));
}
if (refs) {
--
1.8.4.rc4.16.g228394f
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: git clone silently aborts if stdout gets a broken pipe
2013-09-18 18:45 ` Jeff King
@ 2013-09-18 19:04 ` Jeff King
2013-09-18 19:31 ` Junio C Hamano
2013-09-19 7:54 ` git clone silently aborts if stdout gets a broken pipe Peter Kjellerstedt
1 sibling, 1 reply; 11+ messages in thread
From: Jeff King @ 2013-09-18 19:04 UTC (permalink / raw)
To: Peter Kjellerstedt
Cc: Junio C Hamano, Nguyen Thai Ngoc Duy, git@vger.kernel.org
On Wed, Sep 18, 2013 at 02:45:51PM -0400, Jeff King wrote:
> That being said, the new messages should almost certainly go to stderr.
>
> -- >8 --
> Subject: [PATCH] clone: write "checking connectivity" to stderr
>
> In commit 0781aa4 (clone: let the user know when
> check_everything_connected is run, 2013-05-03), we started
> giving the user a progress report during clone. However,
> since the actual work happens in a sub-process, we do not
> use the usual progress code that counts the objects, but
> rather just print a message ourselves.
>
> This message goes to stdout via printf, which is unlike
> other progress messages (both the eye candy within clone,
> and the "checking connectivity" progress in other commands).
> Let's send it to stderr for consistency.
Hrm, this actually breaks t5701, which expects "clone 2>err" to print
nothing to stderr.
What should happen here? The message is emulating the usual progress
messages, which are silent when stderr is redirected. So we could
actually use isatty() in the usual way to suppress them. On the other
hand, the point of that suppression is that the regular progress code
produces long output that is not meant to be seen sequentially (i.e., it
is overwritten in the terminal with "\r"). But this message does not do
so. So we can just tweak t5701 to be more careful about what it is
looking for.
Also, we should arguably give the "Cloning into..." message the same
treatment. We have printed that to stdout for a very long time, so there
is a slim chance that somebody actually tries to parse it. But I think
they are wrong to do so; we already changed it once (in 28ba96a), and
these days it is internationalized, anyway.
In May of 2012 I posted this patch, but it got overlooked, and I forgot
about it but carried it in my tree since then. Maybe we should apply it
now (it fixes t5701; the "checking connectivity" patch can come on top,
or even just be squashed in).
-- >8 --
Subject: [PATCH] clone: send diagnostic messages to stderr
Putting messages like "Cloning into.." and "done" on stdout
is un-Unix and uselessly clutters the stdout channel. Send
them to stderr.
We have to tweak two tests to accommodate this:
1. t5601 checks for doubled output due to forking, and
doesn't actually care where the output goes; adjust it
to check stderr.
2. t5702 is trying to test whether progress output was
sent to stderr, but naively does so by checking
whether stderr produced any output. Instead, have it
look for "%", a token found in progress output but not
elsewhere (and which lets us avoid hard-coding the
progress text in the test).
Signed-off-by: Jeff King <peff@peff.net>
---
builtin/clone.c | 6 +++---
t/t5601-clone.sh | 2 +-
t/t5702-clone-options.sh | 4 ++--
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/builtin/clone.c b/builtin/clone.c
index 3c91844..8723a3a 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -379,7 +379,7 @@ static void clone_local(const char *src_repo, const char *dest_repo)
}
if (0 <= option_verbosity)
- printf(_("done.\n"));
+ fprintf(stderr, _("done.\n"));
}
static const char *junk_work_tree;
@@ -849,9 +849,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (0 <= option_verbosity) {
if (option_bare)
- printf(_("Cloning into bare repository '%s'...\n"), dir);
+ fprintf(stderr, _("Cloning into bare repository '%s'...\n"), dir);
else
- printf(_("Cloning into '%s'...\n"), dir);
+ fprintf(stderr, _("Cloning into '%s'...\n"), dir);
}
init_db(option_template, INIT_DB_QUIET);
write_config(&option_config);
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index 0629149..b3b11e6 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -36,7 +36,7 @@ test_expect_success C_LOCALE_OUTPUT 'output from clone' '
test_expect_success C_LOCALE_OUTPUT 'output from clone' '
rm -fr dst &&
- git clone -n "file://$(pwd)/src" dst >output &&
+ git clone -n "file://$(pwd)/src" dst >output 2>&1 &&
test $(grep Clon output | wc -l) = 1
'
diff --git a/t/t5702-clone-options.sh b/t/t5702-clone-options.sh
index 85cadfa..67e170e 100755
--- a/t/t5702-clone-options.sh
+++ b/t/t5702-clone-options.sh
@@ -22,14 +22,14 @@ test_expect_success 'redirected clone -v' '
test_expect_success 'redirected clone' '
git clone "file://$(pwd)/parent" clone-redirected >out 2>err &&
- test_must_be_empty err
+ ! grep % err
'
test_expect_success 'redirected clone -v' '
git clone --progress "file://$(pwd)/parent" clone-redirected-progress \
>out 2>err &&
- test -s err
+ grep % err
'
--
1.8.4.rc4.16.g228394f
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: git clone silently aborts if stdout gets a broken pipe
2013-09-18 19:04 ` Jeff King
@ 2013-09-18 19:31 ` Junio C Hamano
2013-09-18 20:01 ` Jeff King
0 siblings, 1 reply; 11+ messages in thread
From: Junio C Hamano @ 2013-09-18 19:31 UTC (permalink / raw)
To: Jeff King; +Cc: Peter Kjellerstedt, Nguyen Thai Ngoc Duy, git@vger.kernel.org
Jeff King <peff@peff.net> writes:
> On Wed, Sep 18, 2013 at 02:45:51PM -0400, Jeff King wrote:
>
>> That being said, the new messages should almost certainly go to stderr.
>>
>> -- >8 --
>> Subject: [PATCH] clone: write "checking connectivity" to stderr
>>
>> In commit 0781aa4 (clone: let the user know when
>> check_everything_connected is run, 2013-05-03), we started
>> giving the user a progress report during clone. However,
>> since the actual work happens in a sub-process, we do not
>> use the usual progress code that counts the objects, but
>> rather just print a message ourselves.
>>
>> This message goes to stdout via printf, which is unlike
>> other progress messages (both the eye candy within clone,
>> and the "checking connectivity" progress in other commands).
>> Let's send it to stderr for consistency.
>
> Hrm, this actually breaks t5701, which expects "clone 2>err" to print
> nothing to stderr.
Hmm, where in t5701? Ah, you meant t5702 and possibly t5601.
> What should happen here? The message is emulating the usual progress
> messages, which are silent when stderr is redirected. So we could
> actually use isatty() in the usual way to suppress them. On the other
> hand, the point of that suppression is that the regular progress code
> produces long output that is not meant to be seen sequentially (i.e., it
> is overwritten in the terminal with "\r"). But this message does not do
> so. So we can just tweak t5701 to be more careful about what it is
> looking for.
I actually think "it is long and not meant to be seen sequentially"
is a bad classifier; these new messages are also progress report in
that it reports "we are now in this phase". So if I were to vote, I
would say we should apply the same progress-silencing criteria,
preferrably by not checking isatty() again, but by recording the
decision we have already made when squelching the progress during
the transfer in order to make sure they stay consistent.
> Also, we should arguably give the "Cloning into..." message the same
> treatment. We have printed that to stdout for a very long time, so there
> is a slim chance that somebody actually tries to parse it. But I think
> they are wrong to do so; we already changed it once (in 28ba96a), and
> these days it is internationalized, anyway.
Good thinking. Please make it so ;-)
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: git clone silently aborts if stdout gets a broken pipe
2013-09-18 19:31 ` Junio C Hamano
@ 2013-09-18 20:01 ` Jeff King
2013-09-18 20:05 ` [PATCH 1/2] clone: send diagnostic messages to stderr Jeff King
2013-09-18 20:06 ` [PATCH 2/2] clone: treat "checking connectivity" like other progress Jeff King
0 siblings, 2 replies; 11+ messages in thread
From: Jeff King @ 2013-09-18 20:01 UTC (permalink / raw)
To: Junio C Hamano
Cc: Peter Kjellerstedt, Nguyen Thai Ngoc Duy, git@vger.kernel.org
On Wed, Sep 18, 2013 at 12:31:23PM -0700, Junio C Hamano wrote:
> > Hrm, this actually breaks t5701, which expects "clone 2>err" to print
> > nothing to stderr.
>
> Hmm, where in t5701? Ah, you meant t5702 and possibly t5601.
Yes, sorry, I meant t5702.
> I actually think "it is long and not meant to be seen sequentially"
> is a bad classifier; these new messages are also progress report in
> that it reports "we are now in this phase". So if I were to vote, I
> would say we should apply the same progress-silencing criteria,
> preferrably by not checking isatty() again, but by recording the
> decision we have already made when squelching the progress during
> the transfer in order to make sure they stay consistent.
Unfortunately that decision is made in the transport code, not by clone
itself. We can cheat and peek at "transport->progress" after
initializing the transport. That would require some refactoring, though;
we print "Cloning into" before setting up the transport. And we do not
even tell the transport about our progress options if we are doing a
local clone.
If we wanted to _just_ suppress "Checking connectivity" (and not
"Cloning into..."), that's a bit easier. And I could see an argument
that the former is the only one that falls into the "progress report"
category.
> > Also, we should arguably give the "Cloning into..." message the same
> > treatment. We have printed that to stdout for a very long time, so there
> > is a slim chance that somebody actually tries to parse it. But I think
> > they are wrong to do so; we already changed it once (in 28ba96a), and
> > these days it is internationalized, anyway.
>
> Good thinking. Please make it so ;-)
OK. I've squashed the "use stderr" patches into one, and added a patch
on top to correctly check the progress flag.
[1/2]: clone: send diagnostic messages to stderr
[2/2]: clone: treat "checking connectivity" like other progress
-Peff
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 1/2] clone: send diagnostic messages to stderr
2013-09-18 20:01 ` Jeff King
@ 2013-09-18 20:05 ` Jeff King
2013-09-18 20:06 ` [PATCH 2/2] clone: treat "checking connectivity" like other progress Jeff King
1 sibling, 0 replies; 11+ messages in thread
From: Jeff King @ 2013-09-18 20:05 UTC (permalink / raw)
To: Junio C Hamano
Cc: Peter Kjellerstedt, Nguyen Thai Ngoc Duy, git@vger.kernel.org
Putting messages like "Cloning into.." and "done" on stdout
is un-Unix and uselessly clutters the stdout channel. Send
them to stderr.
We have to tweak two tests to accommodate this:
1. t5601 checks for doubled output due to forking, and
doesn't actually care where the output goes; adjust it
to check stderr.
2. t5702 is trying to test whether progress output was
sent to stderr, but naively does so by checking
whether stderr produced any output. Instead, have it
look for "%", a token found in progress output but not
elsewhere (and which lets us avoid hard-coding the
progress text in the test).
This should not regress any scripts that try to parse the
current output, as the output is already internationalized
and therefore unstable.
Signed-off-by: Jeff King <peff@peff.net>
---
builtin/clone.c | 10 +++++-----
t/t5601-clone.sh | 2 +-
t/t5702-clone-options.sh | 9 +++++----
3 files changed, 11 insertions(+), 10 deletions(-)
diff --git a/builtin/clone.c b/builtin/clone.c
index ca3eb68..8723a3a 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -379,7 +379,7 @@ static void clone_local(const char *src_repo, const char *dest_repo)
}
if (0 <= option_verbosity)
- printf(_("done.\n"));
+ fprintf(stderr, _("done.\n"));
}
static const char *junk_work_tree;
@@ -551,12 +551,12 @@ static void update_remote_refs(const struct ref *refs,
if (check_connectivity) {
if (0 <= option_verbosity)
- printf(_("Checking connectivity... "));
+ fprintf(stderr, _("Checking connectivity... "));
if (check_everything_connected_with_transport(iterate_ref_map,
0, &rm, transport))
die(_("remote did not send all necessary objects"));
if (0 <= option_verbosity)
- printf(_("done\n"));
+ fprintf(stderr, _("done\n"));
}
if (refs) {
@@ -849,9 +849,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (0 <= option_verbosity) {
if (option_bare)
- printf(_("Cloning into bare repository '%s'...\n"), dir);
+ fprintf(stderr, _("Cloning into bare repository '%s'...\n"), dir);
else
- printf(_("Cloning into '%s'...\n"), dir);
+ fprintf(stderr, _("Cloning into '%s'...\n"), dir);
}
init_db(option_template, INIT_DB_QUIET);
write_config(&option_config);
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index 0629149..b3b11e6 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -36,7 +36,7 @@ test_expect_success C_LOCALE_OUTPUT 'output from clone' '
test_expect_success C_LOCALE_OUTPUT 'output from clone' '
rm -fr dst &&
- git clone -n "file://$(pwd)/src" dst >output &&
+ git clone -n "file://$(pwd)/src" dst >output 2>&1 &&
test $(grep Clon output | wc -l) = 1
'
diff --git a/t/t5702-clone-options.sh b/t/t5702-clone-options.sh
index 85cadfa..d3dbdfe 100755
--- a/t/t5702-clone-options.sh
+++ b/t/t5702-clone-options.sh
@@ -19,17 +19,18 @@ test_expect_success 'redirected clone -v' '
'
-test_expect_success 'redirected clone' '
+test_expect_success 'redirected clone does not show progress' '
git clone "file://$(pwd)/parent" clone-redirected >out 2>err &&
- test_must_be_empty err
+ ! grep % err
'
-test_expect_success 'redirected clone -v' '
+
+test_expect_success 'redirected clone -v does show progress' '
git clone --progress "file://$(pwd)/parent" clone-redirected-progress \
>out 2>err &&
- test -s err
+ grep % err
'
--
1.8.4.rc4.16.g228394f
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 2/2] clone: treat "checking connectivity" like other progress
2013-09-18 20:01 ` Jeff King
2013-09-18 20:05 ` [PATCH 1/2] clone: send diagnostic messages to stderr Jeff King
@ 2013-09-18 20:06 ` Jeff King
2013-09-18 20:35 ` [PATCH 3/2] clone: always set transport options Jeff King
1 sibling, 1 reply; 11+ messages in thread
From: Jeff King @ 2013-09-18 20:06 UTC (permalink / raw)
To: Junio C Hamano
Cc: Peter Kjellerstedt, Nguyen Thai Ngoc Duy, git@vger.kernel.org
When stderr does not point to a tty, we typically suppress
"we are now in this phase" progress reporting (e.g., we ask
the server not to send us "counting objects" and the like).
The new "checking connectivity" message is in the same vein,
and should be suppressed. Since clone relies on the
transport code to make the decision, we can simply sneak a
peek at the "progress" field of the transport struct. That
properly takes into account both the verbosity and progress
options we were given, as well as the result of isatty().
Note that we do not set up that progress flag for a local
clone, as we do not fetch using the transport at all. That's
acceptable here, though, because we also do not perform a
connectivity check in that case.
Signed-off-by: Jeff King <peff@peff.net>
---
Though the last paragraph explains why this is OK, it feels a bit
fragile. I wonder if we should hoist the call to transport_set_verbosity
outside the "!is_local" conditional. I do not think it would hurt
anything.
builtin/clone.c | 4 ++--
t/t5702-clone-options.sh | 3 ++-
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/builtin/clone.c b/builtin/clone.c
index 8723a3a..7c62298 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -550,12 +550,12 @@ static void update_remote_refs(const struct ref *refs,
const struct ref *rm = mapped_refs;
if (check_connectivity) {
- if (0 <= option_verbosity)
+ if (transport->progress)
fprintf(stderr, _("Checking connectivity... "));
if (check_everything_connected_with_transport(iterate_ref_map,
0, &rm, transport))
die(_("remote did not send all necessary objects"));
- if (0 <= option_verbosity)
+ if (transport->progress)
fprintf(stderr, _("done\n"));
}
diff --git a/t/t5702-clone-options.sh b/t/t5702-clone-options.sh
index d3dbdfe..9e24ec8 100755
--- a/t/t5702-clone-options.sh
+++ b/t/t5702-clone-options.sh
@@ -22,7 +22,8 @@ test_expect_success 'redirected clone does not show progress' '
test_expect_success 'redirected clone does not show progress' '
git clone "file://$(pwd)/parent" clone-redirected >out 2>err &&
- ! grep % err
+ ! grep % err &&
+ test_i18ngrep ! "Checking connectivity" err
'
--
1.8.4.rc4.16.g228394f
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 3/2] clone: always set transport options
2013-09-18 20:06 ` [PATCH 2/2] clone: treat "checking connectivity" like other progress Jeff King
@ 2013-09-18 20:35 ` Jeff King
0 siblings, 0 replies; 11+ messages in thread
From: Jeff King @ 2013-09-18 20:35 UTC (permalink / raw)
To: Junio C Hamano
Cc: Peter Kjellerstedt, Nguyen Thai Ngoc Duy, git@vger.kernel.org
On Wed, Sep 18, 2013 at 04:06:50PM -0400, Jeff King wrote:
> Note that we do not set up that progress flag for a local
> clone, as we do not fetch using the transport at all. That's
> acceptable here, though, because we also do not perform a
> connectivity check in that case.
>
> Signed-off-by: Jeff King <peff@peff.net>
> ---
> Though the last paragraph explains why this is OK, it feels a bit
> fragile. I wonder if we should hoist the call to transport_set_verbosity
> outside the "!is_local" conditional. I do not think it would hurt
> anything.
Actually, I think the option-setting in clone is a little bit broken.
Mostly it is just making fragile assumptions that happen to be true
(e.g., that fetching the ref list will never care about the progress
flag), but there are some options that should be respected in both
cases.
I think we should do this on top.
-- >8 --
Subject: [PATCH] clone: always set transport options
A clone will always create a transport struct, whether we
are cloning locally or using an actual protocol. In the
local case, we only use the transport to get the list of
refs, and then transfer the objects out-of-band.
However, there are many options that we do not bother
setting up in the local case. For the most part, these are
noops, because they only affect the object-fetching stage
(e.g., the --depth option). However, some options do have a
visible impact. For example, giving the path to upload-pack
via "-u" does not currently work for a local clone, even
though we need upload-pack to get the ref list.
We can just drop the conditional entirely and set these
options for both local and non-local clones. Rather than
keep track of which options impact the object versus the ref
fetching stage, we can simply let the noops be noops (and
the cost of setting the options in the first place is not
high).
The one exception is that we also check that the transport
provides both a "get_refs_list" and a "fetch" method. We
will now be checking the former for both cases (which is
good, since a transport that cannot fetch refs would not
work for a local clone), and we tweak the conditional to
check for a "fetch" only when we are non-local.
Signed-off-by: Jeff King <peff@peff.net>
---
The diff is rather unreadable, but using "show -b" reveals the actual
changes.
builtin/clone.c | 30 ++++++++++++++----------------
t/t5701-clone-local.sh | 4 ++++
2 files changed, 18 insertions(+), 16 deletions(-)
diff --git a/builtin/clone.c b/builtin/clone.c
index 7c62298..7ac677d 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -884,27 +884,25 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
remote = remote_get(option_origin);
transport = transport_get(remote, remote->url[0]);
- if (!is_local) {
- if (!transport->get_refs_list || !transport->fetch)
- die(_("Don't know how to clone %s"), transport->url);
+ if (!transport->get_refs_list || (!is_local && !transport->fetch))
+ die(_("Don't know how to clone %s"), transport->url);
- transport_set_option(transport, TRANS_OPT_KEEP, "yes");
+ transport_set_option(transport, TRANS_OPT_KEEP, "yes");
- if (option_depth)
- transport_set_option(transport, TRANS_OPT_DEPTH,
- option_depth);
- if (option_single_branch)
- transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, "1");
+ if (option_depth)
+ transport_set_option(transport, TRANS_OPT_DEPTH,
+ option_depth);
+ if (option_single_branch)
+ transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, "1");
- transport_set_verbosity(transport, option_verbosity, option_progress);
+ transport_set_verbosity(transport, option_verbosity, option_progress);
- if (option_upload_pack)
- transport_set_option(transport, TRANS_OPT_UPLOADPACK,
- option_upload_pack);
+ if (option_upload_pack)
+ transport_set_option(transport, TRANS_OPT_UPLOADPACK,
+ option_upload_pack);
- if (transport->smart_options && !option_depth)
- transport->smart_options->check_self_contained_and_connected = 1;
- }
+ if (transport->smart_options && !option_depth)
+ transport->smart_options->check_self_contained_and_connected = 1;
refs = transport_get_remote_refs(transport);
diff --git a/t/t5701-clone-local.sh b/t/t5701-clone-local.sh
index 7ff6e0e..c490368 100755
--- a/t/t5701-clone-local.sh
+++ b/t/t5701-clone-local.sh
@@ -134,4 +134,8 @@ test_expect_success 'cloning a local path with --no-local does not hardlink' '
! repo_is_hardlinked force-nonlocal
'
+test_expect_success 'cloning locally respects "-u" for fetching refs' '
+ test_must_fail git clone --bare -u false a should_not_work.git
+'
+
test_done
--
1.8.4.rc4.16.g228394f
^ permalink raw reply related [flat|nested] 11+ messages in thread
* RE: git clone silently aborts if stdout gets a broken pipe
2013-09-18 18:45 ` Jeff King
2013-09-18 19:04 ` Jeff King
@ 2013-09-19 7:54 ` Peter Kjellerstedt
2013-09-19 8:35 ` Jeff King
1 sibling, 1 reply; 11+ messages in thread
From: Peter Kjellerstedt @ 2013-09-19 7:54 UTC (permalink / raw)
To: Jeff King; +Cc: Junio C Hamano, Nguyen Thai Ngoc Duy, git@vger.kernel.org
> -----Original Message-----
> From: git-owner@vger.kernel.org [mailto:git-owner@vger.kernel.org] On
> Behalf Of Jeff King
> Sent: den 18 september 2013 20:46
> To: Peter Kjellerstedt
> Cc: Junio C Hamano; Nguyen Thai Ngoc Duy; git@vger.kernel.org
> Subject: Re: git clone silently aborts if stdout gets a broken pipe
>
> On Wed, Sep 18, 2013 at 06:52:13PM +0200, Peter Kjellerstedt wrote:
>
> > The failing Perl code used a construct like this:
> >
> > Git::command_oneline('clone', $url, $path);
> >
> > There is no error raised, but the directory specified by
> > $path is not created. If I look at the process using strace
> > I can see the clone taking place, but then it seems to get
> > a broken pipe since the code above only cares about the
> > first line from stdout (and with the addition of "Checking
> > connectivity..." git clone now outputs two lines to stdout).
>
> I think your perl script is somewhat questionable, as it is making
> assumptions about the output of git-clone, and you would do better to
> accept arbitrary-sized output
Well, the whole idea of using Git::command_oneline() is that we
are only interested in the first line of output, similar to using
"| head -1". If we had wanted all of the output we would have used
Git::command() instead. Since the Git Perl module is released as a
part of Git, I would expect it to work as documented regardless of
which Git command is used with Git::command_oneline().
In the case of git clone the output to stdout is pretty small so
retrieving all of it would of course not be much overhead, but for
some other commands retrieving all output when only the first line
is wanted (or maybe not even that one) seems unnecessary.
However, what surprised me most was that git clone failed silently
when it got a broken pipe. I cannot really see the reason for
aborting due to stdout getting a broken pipe in the first place.
But if it is, I would at least have expected an error which our
script would have caught and aborted with an appropriate error
message. Now it instead failed later when it actually tried to
access the files in the repository it thought it had cloned...
> (or better yet, leave stdout pointing to
> the user, so they can see the output, which is meant for them).
Well, in this specific case it is a script being run as a cron job
so anything sent to stdout would cause an unnecessary mail.
> That being said, the new messages should almost certainly go to stderr.
I can but agree.
> -- >8 --
> Subject: [PATCH] clone: write "checking connectivity" to stderr
>
> In commit 0781aa4 (clone: let the user know when
> check_everything_connected is run, 2013-05-03), we started
> giving the user a progress report during clone. However,
> since the actual work happens in a sub-process, we do not
> use the usual progress code that counts the objects, but
> rather just print a message ourselves.
>
> This message goes to stdout via printf, which is unlike
> other progress messages (both the eye candy within clone,
> and the "checking connectivity" progress in other commands).
> Let's send it to stderr for consistency.
>
> Signed-off-by: Jeff King <peff@peff.net>
> ---
> builtin/clone.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/builtin/clone.c b/builtin/clone.c
> index ca3eb68..3c91844 100644
> --- a/builtin/clone.c
> +++ b/builtin/clone.c
> @@ -551,12 +551,12 @@ static void update_remote_refs(const struct ref *refs,
>
> if (check_connectivity) {
> if (0 <= option_verbosity)
> - printf(_("Checking connectivity... "));
> + fprintf(stderr, _("Checking connectivity... "));
> if (check_everything_connected_with_transport(iterate_ref_map,
> 0, &rm, transport))
> die(_("remote did not send all necessary objects"));
> if (0 <= option_verbosity)
> - printf(_("done\n"));
> + fprintf(stderr, _("done\n"));
> }
>
> if (refs) {
> --
> 1.8.4.rc4.16.g228394f
>
> --
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
Thanks for taking the time to provide a solution to the problem.
//Peter
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: git clone silently aborts if stdout gets a broken pipe
2013-09-19 7:54 ` git clone silently aborts if stdout gets a broken pipe Peter Kjellerstedt
@ 2013-09-19 8:35 ` Jeff King
2013-09-19 15:48 ` Peter Kjellerstedt
0 siblings, 1 reply; 11+ messages in thread
From: Jeff King @ 2013-09-19 8:35 UTC (permalink / raw)
To: Peter Kjellerstedt
Cc: Junio C Hamano, Nguyen Thai Ngoc Duy, git@vger.kernel.org
On Thu, Sep 19, 2013 at 09:54:38AM +0200, Peter Kjellerstedt wrote:
> > I think your perl script is somewhat questionable, as it is making
> > assumptions about the output of git-clone, and you would do better to
> > accept arbitrary-sized output
>
> Well, the whole idea of using Git::command_oneline() is that we
> are only interested in the first line of output, similar to using
> "| head -1". If we had wanted all of the output we would have used
> Git::command() instead. Since the Git Perl module is released as a
> part of Git, I would expect it to work as documented regardless of
> which Git command is used with Git::command_oneline().
I think command_oneline is exactly like "| head -1" in this case. Doing
"git clone | head -1" would also fail, and should not be used. In
general, you do not want to put a limiting pipe on a command with side
effects beyond output. The design of unix pipes and SIGPIPE is such that
you can do "generate_output | head", and "generate_output" will get
SIGPIPE and die after realizing that its writer no longer cares about
the output. But if your command is doing something besides output, that
assumption doesn't hold.
Arguably, "git clone" should be taking the initiative to ignore SIGPIPE
itself. Its primary function is not output, but doing the clone. If
output fails, we would want to continue the clone, not die.
By the way, did you actually want to capture the stdout of git-clone, or
were you just trying to suppress it? Because the eventual patch I posted
sends it to stderr, under the assumption that what used to go to stdout
should not be captured and parsed (because it is localized and subject
to change).
> However, what surprised me most was that git clone failed silently
> when it got a broken pipe.
It's not "git clone" that is doing this, I think, but rather the design
of command_oneline. If I do:
(sleep 1; git clone ...; echo >&2 exit=$?) | false
then I see:
exit=141
That is, clone dies from SIGPIPE trying to write "Cloning into...". But
command_oneline is specifically designed to ignore SIGPIPE death,
because you would want something like:
command_oneline("git", "rev-list", "$A..$B");
to give you the first line, and then you do not care if the rest of the
rev-list dies due to SIGPIPE (it is a good thing, because by closing the
pipe you are telling it that its output is not needed). It may be that
the documentation for command_oneline can be improved to mention this
subtlety.
-Peff
^ permalink raw reply [flat|nested] 11+ messages in thread
* RE: git clone silently aborts if stdout gets a broken pipe
2013-09-19 8:35 ` Jeff King
@ 2013-09-19 15:48 ` Peter Kjellerstedt
0 siblings, 0 replies; 11+ messages in thread
From: Peter Kjellerstedt @ 2013-09-19 15:48 UTC (permalink / raw)
To: Jeff King; +Cc: Junio C Hamano, Nguyen Thai Ngoc Duy, git@vger.kernel.org
> -----Original Message-----
> From: git-owner@vger.kernel.org [mailto:git-owner@vger.kernel.org] On
> Behalf Of Jeff King
> Sent: den 19 september 2013 10:36
> To: Peter Kjellerstedt
> Cc: Junio C Hamano; Nguyen Thai Ngoc Duy; git@vger.kernel.org
> Subject: Re: git clone silently aborts if stdout gets a broken pipe
>
> On Thu, Sep 19, 2013 at 09:54:38AM +0200, Peter Kjellerstedt wrote:
>
> > > I think your perl script is somewhat questionable, as it is making
> > > assumptions about the output of git-clone, and you would do better
> to
> > > accept arbitrary-sized output
> >
> > Well, the whole idea of using Git::command_oneline() is that we
> > are only interested in the first line of output, similar to using
> > "| head -1". If we had wanted all of the output we would have used
> > Git::command() instead. Since the Git Perl module is released as a
> > part of Git, I would expect it to work as documented regardless of
> > which Git command is used with Git::command_oneline().
>
> I think command_oneline is exactly like "| head -1" in this case. Doing
> "git clone | head -1" would also fail, and should not be used. In
> general, you do not want to put a limiting pipe on a command with side
> effects beyond output. The design of unix pipes and SIGPIPE is such that
> you can do "generate_output | head", and "generate_output" will get
> SIGPIPE and die after realizing that its writer no longer cares about
> the output. But if your command is doing something besides output, that
> assumption doesn't hold.
A very valid point.
> Arguably, "git clone" should be taking the initiative to ignore SIGPIPE
> itself. Its primary function is not output, but doing the clone. If
> output fails, we would want to continue the clone, not die.
>
> By the way, did you actually want to capture the stdout of git-clone, or
> were you just trying to suppress it? Because the eventual patch I posted
> sends it to stderr, under the assumption that what used to go to stdout
> should not be captured and parsed (because it is localized and subject
> to change).
No, we were not really interested in the output to stdout (which is
why the return value from Git::command_oneline() was ignored).
> > However, what surprised me most was that git clone failed silently
> > when it got a broken pipe.
>
> It's not "git clone" that is doing this, I think, but rather the design
> of command_oneline. If I do:
>
> (sleep 1; git clone ...; echo >&2 exit=$?) | false
>
> then I see:
>
> exit=141
>
> That is, clone dies from SIGPIPE trying to write "Cloning into...". But
> command_oneline is specifically designed to ignore SIGPIPE death,
> because you would want something like:
>
> command_oneline("git", "rev-list", "$A..$B");
>
> to give you the first line, and then you do not care if the rest of the
> rev-list dies due to SIGPIPE (it is a good thing, because by closing the
> pipe you are telling it that its output is not needed). It may be that
> the documentation for command_oneline can be improved to mention this
> subtlety.
Ok, all of it makes sense now. Thank you for the explanation.
I have corrected our script so it now works correctly with
git 1.8.4 as well.
> -Peff
> --
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
//Peter
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2013-09-19 15:48 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-09-18 16:52 git clone silently aborts if stdout gets a broken pipe Peter Kjellerstedt
2013-09-18 18:45 ` Jeff King
2013-09-18 19:04 ` Jeff King
2013-09-18 19:31 ` Junio C Hamano
2013-09-18 20:01 ` Jeff King
2013-09-18 20:05 ` [PATCH 1/2] clone: send diagnostic messages to stderr Jeff King
2013-09-18 20:06 ` [PATCH 2/2] clone: treat "checking connectivity" like other progress Jeff King
2013-09-18 20:35 ` [PATCH 3/2] clone: always set transport options Jeff King
2013-09-19 7:54 ` git clone silently aborts if stdout gets a broken pipe Peter Kjellerstedt
2013-09-19 8:35 ` Jeff King
2013-09-19 15:48 ` Peter Kjellerstedt
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).