git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* "git am" and then "git am -3" regression?
@ 2015-07-24 17:48 Junio C Hamano
  2015-07-24 18:09 ` Jeff King
  0 siblings, 1 reply; 26+ messages in thread
From: Junio C Hamano @ 2015-07-24 17:48 UTC (permalink / raw)
  To: Remi Lespinet; +Cc: git, Paul Tan

Hmm, there seems to be some glitches around running "am -3"
after a failed "am" between 'maint' and 'master'.

When I try the following sequence, the 'am' from 'maint' succeeds,
but 'am' in 'master' fails:

 * Save Eric's "minor documetation improvements" $gmane/274537
   to a file.  

 * "git checkout e177995" (that's "next^0") and then apply them with
   "git am" (no -3 necessary).

 * "git checkout 272be14" (that's "es/worktree-add-cleanup^0") and
   then apply them with "git am" (without -3).

   This is expected to stop at 2/6, as the context has changed
   between 272be14 and the tip of 'next'.

 * "git am -3".  This should restart and resolve cleanly.

Reverting d96a275b91bae1800cd43be0651e886e7e042a17 seems to fix it,
so that is what I'll do for 2.5 final.

I think Paul's builtin-am has the same issues, that would need a
separate fix.

commit d96a275b91bae1800cd43be0651e886e7e042a17
Author: Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr>
Date:   Thu Jun 4 17:04:55 2015 +0200

    git-am: add am.threeWay config variable
    
    Add the am.threeWay configuration variable to use the -3 or --3way
    option of git am by default. When am.threeway is set and not desired
    for a specific git am command, the --no-3way option can be used to
    override it.

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: "git am" and then "git am -3" regression?
  2015-07-24 17:48 "git am" and then "git am -3" regression? Junio C Hamano
@ 2015-07-24 18:09 ` Jeff King
  2015-07-26  5:03   ` Paul Tan
  0 siblings, 1 reply; 26+ messages in thread
From: Jeff King @ 2015-07-24 18:09 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Remi Lespinet, git, Paul Tan

On Fri, Jul 24, 2015 at 10:48:18AM -0700, Junio C Hamano wrote:

> Hmm, there seems to be some glitches around running "am -3"
> after a failed "am" between 'maint' and 'master'.
> 
> When I try the following sequence, the 'am' from 'maint' succeeds,
> but 'am' in 'master' fails:
> 
>  * Save Eric's "minor documetation improvements" $gmane/274537
>    to a file.  
> 
>  * "git checkout e177995" (that's "next^0") and then apply them with
>    "git am" (no -3 necessary).
> 
>  * "git checkout 272be14" (that's "es/worktree-add-cleanup^0") and
>    then apply them with "git am" (without -3).
> 
>    This is expected to stop at 2/6, as the context has changed
>    between 272be14 and the tip of 'next'.
> 
>  * "git am -3".  This should restart and resolve cleanly.

Thanks for diagnosing. This bit me the other day, but I hadn't had time
to look at it yet (and I "am" a lot less than you do, I imagine).

> Reverting d96a275b91bae1800cd43be0651e886e7e042a17 seems to fix it,
> so that is what I'll do for 2.5 final.

Yeah, I think this hunk is to blame (though I just read the code and did not
test):

@@ -658,6 +665,8 @@ fi
 if test "$(cat "$dotest/threeway")" = t
 then
        threeway=t
+else
+       threeway=f
 fi

It comes after the command-line option parsing, so it overrides our option (I
think that running "git am -3" followed by "git am --no-3way" would have the
same problem). It cannot just check whether $threeway is unset, though, as it
may have come from the config. We'd need a separate variable, the way the code
is ordered now.

Ideally the code would just be ordered as:

  - load config from git-config

  - override that with defaults inherited from a previous run

  - override that with command-line parsing

but I don't know if there are other ordering gotchas that would break.
It does look like that is how Paul's builtin/am.c does it, which makes
me think it might not be broken. It's also possibly I've horribly
misdiagnosed the bug. ;)

-Peff

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: "git am" and then "git am -3" regression?
  2015-07-24 18:09 ` Jeff King
@ 2015-07-26  5:03   ` Paul Tan
  2015-07-26  5:21     ` Jeff King
  2015-07-27 14:21     ` Junio C Hamano
  0 siblings, 2 replies; 26+ messages in thread
From: Paul Tan @ 2015-07-26  5:03 UTC (permalink / raw)
  To: Jeff King, Junio C Hamano; +Cc: Remi Lespinet, Git List

On Sat, Jul 25, 2015 at 2:09 AM, Jeff King <peff@peff.net> wrote:
> Yeah, I think this hunk is to blame (though I just read the code and did not
> test):
>
> @@ -658,6 +665,8 @@ fi
>  if test "$(cat "$dotest/threeway")" = t
>  then
>         threeway=t
> +else
> +       threeway=f
>  fi
>
> It comes after the command-line option parsing, so it overrides our option (I
> think that running "git am -3" followed by "git am --no-3way" would have the
> same problem). It cannot just check whether $threeway is unset, though, as it
> may have come from the config.

Thanks for the detailed analysis, I completely agree. Note that the
code that handles the --message-id option somewhat handles the case
where $messageid is unset:

case "$(cat "$dotest/messageid")" in
t)
    messageid=-m ;;
f)
    messageid= ;;
esac

However, it still does not handle "git am --no-message-id" followed by
"git am --message-id", or "git -c am.messageid=true am" followed by
"git am --no-message-id". I think the same thing occurs for
--scissors/--no-scissors, as well as the git-apply options as well.

The real problem is that the state directory loading code comes after
the config loading and option parsing code, and thus overrides any
variables set.

> We'd need a separate variable, the way the code
> is ordered now.

If we are just fixing --3way, adding one extra variable won't be that
bad. However, I think that if we are using this approach to fix all of
the options, then it would introduce too much code complexity.

> Ideally the code would just be ordered as:
>
>   - load config from git-config
>
>   - override that with defaults inherited from a previous run
>
>   - override that with command-line parsing

So I'm more in favor of this solution. It's feels much more natural to
me, rather than attempting to workaround the existing code structure.

> but I don't know if there are other ordering gotchas that would break.

For the C code, there won't be any problem, but yeah, fixing it in
git-am.sh might need a bit more effort.

> It does look like that is how Paul's builtin/am.c does it, which makes
> me think it might not be broken. It's also possibly I've horribly
> misdiagnosed the bug. ;)

Nah, it follows the same structure as git-am.sh and so will exhibit
the same behavior. It currently does something like this:

1. am_state_init() (config settings are loaded)
2. parse_options()
3. if (am_in_progress()) am_load(); else am_setup();

So it would be quite trivial to change the control flow such that it is:

1. am_state_init()
2. if (am_in_progress()) am_load()
3. parse_options();
4 if (!am_in_progress()) am_setup()

The next question is, should any options set on the command-line
affect subsequent invocations? If yes, then the control flow will be
like:

1. am_state_init();
2. if (am_in_progress()) am_load();
3. parse_options();
4. if (am_in_progress()) am_save_opts(); else am_setup();

where am_save_opts() will write the updated variables back to the
state directory. What do you think?

Since the builtin-am series is in 'next' already, and the fix in C is
straightforward, to save time and effort I'm wondering if we could
just do "am.threeWay patch -> builtin-am series -> bugfix patch in C".
My university term is starting soon so I may not have so much time,
but I'll see what I can do :-/

Junio, how do you want to proceed?

Thanks,
Paul

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: "git am" and then "git am -3" regression?
  2015-07-26  5:03   ` Paul Tan
@ 2015-07-26  5:21     ` Jeff King
  2015-07-27  8:09       ` Matthieu Moy
  2015-07-27 14:21     ` Junio C Hamano
  1 sibling, 1 reply; 26+ messages in thread
From: Jeff King @ 2015-07-26  5:21 UTC (permalink / raw)
  To: Paul Tan; +Cc: Junio C Hamano, Remi Lespinet, Git List

On Sun, Jul 26, 2015 at 01:03:59PM +0800, Paul Tan wrote:

> > Ideally the code would just be ordered as:
> >
> >   - load config from git-config
> >
> >   - override that with defaults inherited from a previous run
> >
> >   - override that with command-line parsing
> 
> So I'm more in favor of this solution. It's feels much more natural to
> me, rather than attempting to workaround the existing code structure.

Yeah, I really prefer it, too. I just didn't know if there would be
other confusing fallouts from changing the ordering. But since you have
been deep in this code recently, I trust your judgement. :)

> > It does look like that is how Paul's builtin/am.c does it, which makes
> > me think it might not be broken. It's also possibly I've horribly
> > misdiagnosed the bug. ;)
> 
> Nah, it follows the same structure as git-am.sh and so will exhibit
> the same behavior. It currently does something like this:
> 
> 1. am_state_init() (config settings are loaded)
> 2. parse_options()
> 3. if (am_in_progress()) am_load(); else am_setup();

Ah, right. I took the am_state_init() to be the part where we loaded the
existing options, and didn't notice the later am_load().

> The next question is, should any options set on the command-line
> affect subsequent invocations? If yes, then the control flow will be
> like:
> 
> 1. am_state_init();
> 2. if (am_in_progress()) am_load();
> 3. parse_options();
> 4. if (am_in_progress()) am_save_opts(); else am_setup();
> 
> where am_save_opts() will write the updated variables back to the
> state directory. What do you think?

I don't think we need to go that direction.  The usual thought process
(mine, anyway) is:

  1. I want to apply a series, and I want to use option A.

  2. Oops, one of the patches didn't apply. Let's retry it with option B
     (usually "-3").

  3. OK, that worked. Now let's try the rest of the patches.

I wouldn't expect in step 3 to have options from step 2 persist. That
was just about wiggling that _one_ patch. Whereas options from step 1
are about the whole series.

> Since the builtin-am series is in 'next' already, and the fix in C is
> straightforward, to save time and effort I'm wondering if we could
> just do "am.threeWay patch -> builtin-am series -> bugfix patch in C".
> My university term is starting soon so I may not have so much time,
> but I'll see what I can do :-/

Yeah, having to worry about two implementations of "git am" is a real
pain. If we are close on merging the builtin version, it makes sense to
me to hold off on the am.threeway feature until that is merged. Trying
to fix the ordering of the script that is going away isn't a good use of
anybody's time.

-Peff

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: "git am" and then "git am -3" regression?
  2015-07-26  5:21     ` Jeff King
@ 2015-07-27  8:09       ` Matthieu Moy
  2015-07-27  8:32         ` Jeff King
  0 siblings, 1 reply; 26+ messages in thread
From: Matthieu Moy @ 2015-07-27  8:09 UTC (permalink / raw)
  To: Jeff King; +Cc: Paul Tan, Junio C Hamano, Remi Lespinet, Git List

Jeff King <peff@peff.net> writes:

> Yeah, having to worry about two implementations of "git am" is a real
> pain. If we are close on merging the builtin version, it makes sense to
> me to hold off on the am.threeway feature until that is merged. Trying
> to fix the ordering of the script that is going away isn't a good use of
> anybody's time.

So, the best option seems to be:

1) Revert d96a275 (git-am: add am.threeWay config variable, 2015-06-04)

2) Include the C port of d96a275 together with tests and docs verbatim
   from d96a275 into Paul's series.

Actually, doing 1) is probably a good idea anyway, there's no reason to
hold the release for such minor feature.

-- 
Matthieu Moy
http://www-verimag.imag.fr/~moy/

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: "git am" and then "git am -3" regression?
  2015-07-27  8:09       ` Matthieu Moy
@ 2015-07-27  8:32         ` Jeff King
  0 siblings, 0 replies; 26+ messages in thread
From: Jeff King @ 2015-07-27  8:32 UTC (permalink / raw)
  To: Matthieu Moy; +Cc: Paul Tan, Junio C Hamano, Remi Lespinet, Git List

On Mon, Jul 27, 2015 at 10:09:43AM +0200, Matthieu Moy wrote:

> > Yeah, having to worry about two implementations of "git am" is a real
> > pain. If we are close on merging the builtin version, it makes sense to
> > me to hold off on the am.threeway feature until that is merged. Trying
> > to fix the ordering of the script that is going away isn't a good use of
> > anybody's time.
> 
> So, the best option seems to be:
> 
> 1) Revert d96a275 (git-am: add am.threeWay config variable, 2015-06-04)
> 
> 2) Include the C port of d96a275 together with tests and docs verbatim
>    from d96a275 into Paul's series.
> 
> Actually, doing 1) is probably a good idea anyway, there's no reason to
> hold the release for such minor feature.

I think step 1 is done already for v2.5.0, in 15dc5b5.

We _could_ fix it in the script version for the upcoming cycle, but if
we are merging builtin-am during this cycle, I do not see the point.

-Peff

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: "git am" and then "git am -3" regression?
  2015-07-26  5:03   ` Paul Tan
  2015-07-26  5:21     ` Jeff King
@ 2015-07-27 14:21     ` Junio C Hamano
  2015-07-28 16:43       ` [PATCH] am: let command-line options override saved options Paul Tan
  1 sibling, 1 reply; 26+ messages in thread
From: Junio C Hamano @ 2015-07-27 14:21 UTC (permalink / raw)
  To: Paul Tan; +Cc: Jeff King, Remi Lespinet, Git List

Paul Tan <pyokagan@gmail.com> writes:

> Junio, how do you want to proceed?

I'd expect that builtin series would graduate in 2 releases from now
at the latest, if not earlier.  Let's just revert the regressing
change from the scripted version and have it implemented in the
builtin one in the meantime.  I do not think it is worth adding
features to the scripted one at this point.

Thanks.

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH] am: let command-line options override saved options
  2015-07-27 14:21     ` Junio C Hamano
@ 2015-07-28 16:43       ` Paul Tan
  2015-07-28 16:48         ` Junio C Hamano
                           ` (3 more replies)
  0 siblings, 4 replies; 26+ messages in thread
From: Paul Tan @ 2015-07-28 16:43 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Remi Lespinet, Git List, Stefan Beller,
	Johannes Schindelin

When resuming, git-am ignores command-line options. For instance, when a
patch fails to apply with "git am patch", subsequently running "git am
--3way patch" would not cause git-am to fall back on attempting a
threeway merge. This occurs because by default the --3way option is
saved as "false", and the saved am options are loaded after the
command-line options are parsed, thus overwriting the command-line
options when resuming.

Fix this by moving the am_load() function call before parse_options(),
so that command-line options will override the saved am options.

Reported-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Jeff King <peff@peff.net>
Signed-off-by: Paul Tan <pyokagan@gmail.com>
---
 builtin/am.c                       |   9 ++-
 t/t4153-am-resume-override-opts.sh | 144 +++++++++++++++++++++++++++++++++++++
 2 files changed, 150 insertions(+), 3 deletions(-)
 create mode 100755 t/t4153-am-resume-override-opts.sh

diff --git a/builtin/am.c b/builtin/am.c
index 1116304..8a0b0e4 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -2131,6 +2131,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
 	int keep_cr = -1;
 	int patch_format = PATCH_FORMAT_UNKNOWN;
 	enum resume_mode resume = RESUME_FALSE;
+	int in_progress;
 
 	const char * const usage[] = {
 		N_("git am [options] [(<mbox>|<Maildir>)...]"),
@@ -2226,6 +2227,10 @@ int cmd_am(int argc, const char **argv, const char *prefix)
 
 	am_state_init(&state, git_path("rebase-apply"));
 
+	in_progress = am_in_progress(&state);
+	if (in_progress)
+		am_load(&state);
+
 	argc = parse_options(argc, argv, prefix, options, usage, 0);
 
 	if (binary >= 0)
@@ -2238,7 +2243,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
 	if (read_index_preload(&the_index, NULL) < 0)
 		die(_("failed to read the index"));
 
-	if (am_in_progress(&state)) {
+	if (in_progress) {
 		/*
 		 * Catch user error to feed us patches when there is a session
 		 * in progress:
@@ -2256,8 +2261,6 @@ int cmd_am(int argc, const char **argv, const char *prefix)
 
 		if (resume == RESUME_FALSE)
 			resume = RESUME_APPLY;
-
-		am_load(&state);
 	} else {
 		struct argv_array paths = ARGV_ARRAY_INIT;
 		int i;
diff --git a/t/t4153-am-resume-override-opts.sh b/t/t4153-am-resume-override-opts.sh
new file mode 100755
index 0000000..c49457c
--- /dev/null
+++ b/t/t4153-am-resume-override-opts.sh
@@ -0,0 +1,144 @@
+#!/bin/sh
+
+test_description='git-am command-line options override saved options'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+	test_commit initial file &&
+	test_commit first file &&
+
+	git checkout -b side initial &&
+	test_commit side-first file &&
+	test_commit side-second file &&
+
+	{
+		echo "Message-Id: <side-first@example.com>" &&
+		git format-patch --stdout -1 side-first | sed -e "1d"
+	} >side-first.patch &&
+	{
+		sed -ne "1,/^\$/p" side-first.patch &&
+		echo "-- >8 --" &&
+		sed -e "1,/^\$/d" side-first.patch
+	} >side-first.scissors &&
+
+	{
+		echo "Message-Id: <side-second@example.com>" &&
+		git format-patch --stdout -1 side-second | sed -e "1d"
+	} >side-second.patch &&
+	{
+		sed -ne "1,/^\$/p" side-second.patch &&
+		echo "-- >8 --" &&
+		sed -e "1,/^\$/d" side-second.patch
+	} >side-second.scissors
+'
+
+test_expect_success '--3way, --no-3way' '
+	rm -fr .git/rebase-apply &&
+	git reset --hard &&
+	git checkout first &&
+	test_must_fail git am --3way side-first.patch side-second.patch &&
+	test -n "$(git ls-files -u)" &&
+	echo will-conflict >file &&
+	git add file &&
+	test_must_fail git am --no-3way --continue &&
+	test -z "$(git ls-files -u)"
+'
+
+test_expect_success '--no-quiet, --quiet' '
+	rm -fr .git/rebase-apply &&
+	git reset --hard &&
+	git checkout first &&
+	test_must_fail git am --no-quiet side-first.patch side-second.patch &&
+	test_must_be_empty out &&
+	echo side-first >file &&
+	git add file &&
+	git am --quiet --continue >out &&
+	test_must_be_empty out
+'
+
+test_expect_success '--signoff, --no-signoff' '
+	rm -fr .git/rebase-apply &&
+	git reset --hard &&
+	git checkout first &&
+	test_must_fail git am --signoff side-first.patch side-second.patch &&
+	echo side-first >file &&
+	git add file &&
+	git am --no-signoff --continue &&
+
+	# applied side-first will be signed off
+	echo "Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" >expected &&
+	git cat-file commit HEAD^ | grep "Signed-off-by:" >actual &&
+	test_cmp expected actual &&
+
+	# applied side-second will not be signed off
+	test $(git cat-file commit HEAD | grep -c "Signed-off-by:") -eq 0
+'
+
+test_expect_success '--keep, --no-keep' '
+	rm -fr .git/rebase-apply &&
+	git reset --hard &&
+	git checkout first &&
+	test_must_fail git am --keep side-first.patch side-second.patch &&
+	echo side-first >file &&
+	git add file &&
+	git am --no-keep --continue &&
+
+	# applied side-first will keep the subject
+	git cat-file commit HEAD^ >actual &&
+	grep "^\[PATCH\] side-first" actual &&
+
+	# applied side-second will not have [PATCH]
+	git cat-file commit HEAD >actual &&
+	! grep "^\[PATCH\] side-second" actual
+'
+
+test_expect_success '--message-id, --no-message-id' '
+	rm -fr .git/rebase-apply &&
+	git reset --hard &&
+	git checkout first &&
+	test_must_fail git am --message-id side-first.patch side-second.patch &&
+	echo side-first >file &&
+	git add file &&
+	git am --no-message-id --continue &&
+
+	# applied side-first will have Message-Id
+	test -n "$(git cat-file commit HEAD^ | grep Message-Id)" &&
+
+	# applied side-second will not have Message-Id
+	test -z "$(git cat-file commit HEAD | grep Message-Id)"
+'
+
+test_expect_success '--scissors, --no-scissors' '
+	rm -fr .git/rebase-apply &&
+	git reset --hard &&
+	git checkout first &&
+	test_must_fail git am --scissors side-first.scissors side-second.scissors &&
+	echo side-first >file &&
+	git add file &&
+	git am --no-scissors --continue &&
+
+	# applied side-first will not have scissors line
+	git cat-file commit HEAD^ >actual &&
+	! grep "^-- >8 --" actual &&
+
+	# applied side-second will have scissors line
+	git cat-file commit HEAD >actual &&
+	grep "^-- >8 --" actual
+'
+
+test_expect_success '--reject, --no-reject' '
+	rm -fr .git/rebase-apply &&
+	git reset --hard &&
+	git checkout first &&
+	rm -f file.rej &&
+	test_must_fail git am --reject side-first.patch side-second.patch &&
+	test_path_is_file file.rej &&
+	rm -f file.rej &&
+	echo will-conflict >file &&
+	git add file &&
+	test_must_fail git am --no-reject --continue &&
+	test_path_is_missing file.rej
+'
+
+test_done
-- 
2.5.0.77.gd180035

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [PATCH] am: let command-line options override saved options
  2015-07-28 16:43       ` [PATCH] am: let command-line options override saved options Paul Tan
@ 2015-07-28 16:48         ` Junio C Hamano
  2015-07-28 17:09         ` Junio C Hamano
                           ` (2 subsequent siblings)
  3 siblings, 0 replies; 26+ messages in thread
From: Junio C Hamano @ 2015-07-28 16:48 UTC (permalink / raw)
  To: Paul Tan
  Cc: Jeff King, Remi Lespinet, Git List, Stefan Beller,
	Johannes Schindelin

Paul Tan <pyokagan@gmail.com> writes:

> When resuming, git-am ignores command-line options. For instance, when a
> patch fails to apply with "git am patch", subsequently running "git am
> --3way patch" would not cause git-am to fall back on attempting a

The second one goes without any file argument, i.e. "git am -3".

> threeway merge. This occurs because by default the --3way option is
> saved as "false", and the saved am options are loaded after the
> command-line options are parsed, thus overwriting the command-line
> options when resuming.
>
> Fix this by moving the am_load() function call before parse_options(),
> so that command-line options will override the saved am options.

Makes sense.

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH] am: let command-line options override saved options
  2015-07-28 16:43       ` [PATCH] am: let command-line options override saved options Paul Tan
  2015-07-28 16:48         ` Junio C Hamano
@ 2015-07-28 17:09         ` Junio C Hamano
  2015-07-31 10:58           ` Paul Tan
  2015-08-04 14:05         ` [PATCH v2 0/3] " Paul Tan
  2015-08-04 14:08         ` Paul Tan
  3 siblings, 1 reply; 26+ messages in thread
From: Junio C Hamano @ 2015-07-28 17:09 UTC (permalink / raw)
  To: Paul Tan
  Cc: Jeff King, Remi Lespinet, Git List, Stefan Beller,
	Johannes Schindelin

Paul Tan <pyokagan@gmail.com> writes:

> diff --git a/t/t4153-am-resume-override-opts.sh b/t/t4153-am-resume-override-opts.sh
> new file mode 100755
> index 0000000..c49457c
> --- /dev/null
> +++ b/t/t4153-am-resume-override-opts.sh
> @@ -0,0 +1,144 @@
> +#!/bin/sh
> +
> +test_description='git-am command-line options override saved options'
> +
> +. ./test-lib.sh
> +
> +test_expect_success 'setup' '
> +	test_commit initial file &&
> +	test_commit first file &&
> +
> +	git checkout -b side initial &&
> +	test_commit side-first file &&
> +	test_commit side-second file &&
> +
> +	{
> +		echo "Message-Id: <side-first@example.com>" &&
> +		git format-patch --stdout -1 side-first | sed -e "1d"
> +	} >side-first.patch &&

Hmm, puzzled...  Ah, you want to make sure Message-Id comes at the
very beginning, and you are going to use a single e-mail per mailbox
so it is easier to strip the Beginning of Message marker than to
insert Message-Id after it.  I can understand what is going on.

> +	{
> +		sed -ne "1,/^\$/p" side-first.patch &&

sed -e "/^\$/q" would work just as well here

> +		echo "-- >8 --" &&
> +		sed -e "1,/^\$/d" side-first.patch
> +	} >side-first.scissors &&

So *.scissors version has -- >8 -- inserted at the beginning of the
body.

> +	{
> +		echo "Message-Id: <side-second@example.com>" &&
> +		git format-patch --stdout -1 side-second | sed -e "1d"
> +	} >side-second.patch &&
> +	{
> +		sed -ne "1,/^\$/p" side-second.patch &&
> +		echo "-- >8 --" &&
> +		sed -e "1,/^\$/d" side-second.patch
> +	} >side-second.scissors
> +'

A helper function that takes the branch name may be a good idea,
not just to consolidate the implementation but as a place to
document how these pairs of files are constructed and why.

> +test_expect_success '--3way, --no-3way' '
> +	rm -fr .git/rebase-apply &&
> +	git reset --hard &&
> +	git checkout first &&
> +	test_must_fail git am --3way side-first.patch side-second.patch &&
> +	test -n "$(git ls-files -u)" &&
> +	echo will-conflict >file &&
> +	git add file &&
> +	test_must_fail git am --no-3way --continue &&
> +	test -z "$(git ls-files -u)"
> +'
> +
> +test_expect_success '--no-quiet, --quiet' '
> +	rm -fr .git/rebase-apply &&
> +	git reset --hard &&
> +	git checkout first &&
> +	test_must_fail git am --no-quiet side-first.patch side-second.patch &&
> +	test_must_be_empty out &&

Where did this 'out' come from?

> +	echo side-first >file &&
> +	git add file &&
> +	git am --quiet --continue >out &&
> +	test_must_be_empty out

I can see this one, though I am not sure if it is sensible to see
what the command says under --quiet option, especially if you are
making sure it does not fail, which you already have checked for its
exit status.

> +'
> +
> +test_expect_success '--signoff, --no-signoff' '
> +	rm -fr .git/rebase-apply &&
> +	git reset --hard &&
> +	git checkout first &&
> +	test_must_fail git am --signoff side-first.patch side-second.patch &&
> +	echo side-first >file &&
> +	git add file &&
> +	git am --no-signoff --continue &&
> +
> +	# applied side-first will be signed off
> +	echo "Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" >expected &&
> +	git cat-file commit HEAD^ | grep "Signed-off-by:" >actual &&
> +	test_cmp expected actual &&
> +
> +	# applied side-second will not be signed off
> +	test $(git cat-file commit HEAD | grep -c "Signed-off-by:") -eq 0
> +'

Hmm, the command was run with --signoff at the start, first gets
applied with "am --no-signoff --resolved" so I would expect it does
not get signed off, but the second one will apply cleanly on top, so
shouldn't it get signed off?  Or perhaps somehow I misread Peff's
idea to make these override one-shot in $gmane/274635?

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH] am: let command-line options override saved options
  2015-07-28 17:09         ` Junio C Hamano
@ 2015-07-31 10:58           ` Paul Tan
  2015-07-31 16:04             ` Junio C Hamano
  0 siblings, 1 reply; 26+ messages in thread
From: Paul Tan @ 2015-07-31 10:58 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Remi Lespinet, Git List, Stefan Beller,
	Johannes Schindelin

On Wed, Jul 29, 2015 at 1:09 AM, Junio C Hamano <gitster@pobox.com> wrote:
> Paul Tan <pyokagan@gmail.com> writes:
>
>> diff --git a/t/t4153-am-resume-override-opts.sh b/t/t4153-am-resume-override-opts.sh
>> new file mode 100755
>> index 0000000..c49457c
>> --- /dev/null
>> +++ b/t/t4153-am-resume-override-opts.sh
>> @@ -0,0 +1,144 @@
>> +#!/bin/sh
>> +
>> +test_description='git-am command-line options override saved options'
>> +
>> +. ./test-lib.sh
>> +
>> +test_expect_success 'setup' '
>> +     test_commit initial file &&
>> +     test_commit first file &&
>> +
>> +     git checkout -b side initial &&
>> +     test_commit side-first file &&
>> +     test_commit side-second file &&
>> +
>> +     {
>> +             echo "Message-Id: <side-first@example.com>" &&
>> +             git format-patch --stdout -1 side-first | sed -e "1d"
>> +     } >side-first.patch &&
>> +     {
>> +             sed -ne "1,/^\$/p" side-first.patch &&
>
> sed -e "/^\$/q" would work just as well here

OK.

>> +             echo "-- >8 --" &&
>> +             sed -e "1,/^\$/d" side-first.patch
>> +     } >side-first.scissors &&
>> +     {
>> +             echo "Message-Id: <side-second@example.com>" &&
>> +             git format-patch --stdout -1 side-second | sed -e "1d"
>> +     } >side-second.patch &&
>> +     {
>> +             sed -ne "1,/^\$/p" side-second.patch &&
>> +             echo "-- >8 --" &&
>> +             sed -e "1,/^\$/d" side-second.patch
>> +     } >side-second.scissors
>> +'
>
> A helper function that takes the branch name may be a good idea,
> not just to consolidate the implementation but as a place to
> document how these pairs of files are constructed and why.

I think I will introduce a format_patch() function that takes a single
commit-ish so that we can use tag names to name the patches:

# Given a single commit $commit, formats the following patches with
# git-format-patch:
#
# 1. $commit.eml: an email patch with a Message-Id header.
# 2. $commit.scissors: like $commit.eml but contains a scissors line at the
#    start of the commit message body.
format_patch () {
    {
        echo "Message-Id: <$1@example.com>" &&
        git format-patch --stdout -1 "$1" | sed -e '1d'
    } >"$1".eml &&
    {
        sed -e '/^$/q' "$1".eml &&
        echo '-- >8 --' &&
        sed -e '1,/^$/d' "$1".eml
    } >"$1".scissors
}

>> +'
>> +
>> +test_expect_success '--signoff, --no-signoff' '
>> +     rm -fr .git/rebase-apply &&
>> +     git reset --hard &&
>> +     git checkout first &&
>> +     test_must_fail git am --signoff side-first.patch side-second.patch &&
>> +     echo side-first >file &&
>> +     git add file &&
>> +     git am --no-signoff --continue &&
>> +
>> +     # applied side-first will be signed off
>> +     echo "Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" >expected &&
>> +     git cat-file commit HEAD^ | grep "Signed-off-by:" >actual &&
>> +     test_cmp expected actual &&
>> +
>> +     # applied side-second will not be signed off
>> +     test $(git cat-file commit HEAD | grep -c "Signed-off-by:") -eq 0
>> +'
>
> Hmm, the command was run with --signoff at the start, first gets
> applied with "am --no-signoff --resolved" so I would expect it does
> not get signed off, but the second one will apply cleanly on top, so
> shouldn't it get signed off?  Or perhaps somehow I misread Peff's
> idea to make these override one-shot in $gmane/274635?

Ah, I was just following the structure of the code, but stepping back
to think about it, I think there are 2 bugs:

1. The signoff is appended during the email-parsing stage. As such,
when we are resuming, --no-signoff will have no effect, because the
signoff has already been appended at that stage.

A solution for this is tricky though, as there are functions of git-am
that probably depend on the present behavior of the appended signoff
being present in the commit message:

* The applypatch-msg hook

* The --interactive prompt, where the user can edit the commit message
(to remove or edit the signoff maybe?)

These functions are called before we attempt to apply the patch, so we
should probably call append_signoff before then. However, this still
means that --no-signoff will have no effect should the patch
application fail and we resume, as the signoff would still have
already been appended...

So I dunno. I think the cleanest solution would be to change the
behavior so the commit message passed to the applypatch-msg hook and
--interactive prompt  do not contain the appended signoff, and instead
only append the signoff just before we commit. That way, both
--signoff and --no-signoff overriding will work. What do you think?

2. Re-reading Peff's message, I see that he expects the command-line
options to affect just the current patch, which makes sense. This
patch would need to be extended to call am_load() after we finish
processing the current patch when resuming. Something like:

diff --git a/builtin/am.c b/builtin/am.c
index 8a0b0e4..228d4b1 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -1779,7 +1779,6 @@ static void am_run(struct am_state *state, int resume)

         if (resume) {
             validate_resume_state(state);
-            resume = 0;
         } else {
             int skip;

@@ -1841,6 +1840,10 @@ static void am_run(struct am_state *state, int resume)

 next:
         am_next(state);
+
+        if (resume)
+            am_load(state);
+        resume = 0;
     }

     if (!is_empty_file(am_path(state, "rewritten"))) {
@@ -1895,6 +1898,7 @@ static void am_resolve(struct am_state *state)

 next:
     am_next(state);
+    am_load(state);
     am_run(state, 0);
 }

@@ -2022,6 +2026,7 @@ static void am_skip(struct am_state *state)
         die(_("failed to clean index"));

     am_next(state);
+    am_load(state);
     am_run(state, 0);
 }

The tests will also need to be modified as well.

>> +test_expect_success '--3way, --no-3way' '
>> +     rm -fr .git/rebase-apply &&
>> +     git reset --hard &&
>> +     git checkout first &&
>> +     test_must_fail git am --3way side-first.patch side-second.patch &&
>> +     test -n "$(git ls-files -u)" &&
>> +     echo will-conflict >file &&
>> +     git add file &&
>> +     test_must_fail git am --no-3way --continue &&
>> +     test -z "$(git ls-files -u)"
>> +'
>> +

... Although if I implement the above change, I can't implement the
test for --3way, as I think the only way to check if --3way/--no-3way
successfully overrides the saved options for the current patch only is
to run "git am --3way", but that does not work in the test runner as
it expects stdin to be a TTY :-/ So I may have to remove this test.
This shouldn't be a problem though, as all the tests in this test
suite all test the same mechanism.

>> +test_expect_success '--no-quiet, --quiet' '
>> +     rm -fr .git/rebase-apply &&
>> +     git reset --hard &&
>> +     git checkout first &&
>> +     test_must_fail git am --no-quiet side-first.patch side-second.patch &&
>> +     test_must_be_empty out &&
>
> Where did this 'out' come from?

It was a leftover from a previous iteration. Will fix.

>
>> +     echo side-first >file &&
>> +     git add file &&
>> +     git am --quiet --continue >out &&
>> +     test_must_be_empty out
>
> I can see this one, though I am not sure if it is sensible to see
> what the command says under --quiet option, especially if you are
> making sure it does not fail, which you already have checked for its
> exit status.

Well, if --quiet fails to override --no-quiet, then there would be
something written to the stdout, no?

But anyway, if we are implementing the above "command-line option
overriding only affects current patch" behavior, then this test would
be checking if --quiet only affects a single patch, which in practice
would be quite silly. Maybe I should flip it around to "--no-quiet
overrides --quiet", but even then it may still be unlikely to come up
with practice... Still, it may be useful to keep this test to check if
the option overriding mechanism is working properly.

Thanks,
Paul

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [PATCH] am: let command-line options override saved options
  2015-07-31 10:58           ` Paul Tan
@ 2015-07-31 16:04             ` Junio C Hamano
  2015-08-01  0:59               ` Paul Tan
  0 siblings, 1 reply; 26+ messages in thread
From: Junio C Hamano @ 2015-07-31 16:04 UTC (permalink / raw)
  To: Paul Tan
  Cc: Jeff King, Remi Lespinet, Git List, Stefan Beller,
	Johannes Schindelin

Paul Tan <pyokagan@gmail.com> writes:

> I think I will introduce a format_patch() function that takes a single
> commit-ish so that we can use tag names to name the patches:
>
> # Given a single commit $commit, formats the following patches with
> # git-format-patch:
> #
> # 1. $commit.eml: an email patch with a Message-Id header.
> # 2. $commit.scissors: like $commit.eml but contains a scissors line at the
> #    start of the commit message body.
> format_patch () {
>     {
>         echo "Message-Id: <$1@example.com>" &&
>         git format-patch --stdout -1 "$1" | sed -e '1d'
>     } >"$1".eml &&

I only said I can "understand" what is going on, though.

It feels a bit unnatural for a test to feed a message that lack the
"From " header line.  Perhaps

	git format-patch --add-header="Message-Id: ..." --stdout -1

or something?

> Ah, I was just following the structure of the code, but stepping back
> to think about it, I think there are 2 bugs:
>
> 1. The signoff is appended during the email-parsing stage. As such,
> when we are resuming, --no-signoff will have no effect, because the
> signoff has already been appended at that stage.
>
> A solution for this is tricky though, as there are functions of git-am
> that probably depend on the present behavior of the appended signoff
> being present in the commit message:
>
> * The applypatch-msg hook
>
> * The --interactive prompt, where the user can edit the commit message
> (to remove or edit the signoff maybe?)
>
> These functions are called before we attempt to apply the patch, so we
> should probably call append_signoff before then. However, this still
> means that --no-signoff will have no effect should the patch
> application fail and we resume, as the signoff would still have
> already been appended...

Ah, I see.  Let's not worry about this; we cannot change the
expectation existing hook scripts depends on.

> 2. Re-reading Peff's message, I see that he expects the command-line
> options to affect just the current patch, which makes sense. This
> patch would need to be extended to call am_load() after we finish
> processing the current patch when resuming.

Yeah, so the idea is:

 - upon the very first invocation, we parse the command line options
   and write the states out;

 - subsequent invocation, we read from the states and then override
   with the command line options, but we do not write the states out
   to update, so that subsequent invocations will keep reading from
   the very first one.

That sounds sensible.

> The tests will also need to be modified as well.
>
>>> +test_expect_success '--3way, --no-3way' '
>>> +     rm -fr .git/rebase-apply &&
>>> +     git reset --hard &&
>>> +     git checkout first &&
>>> +     test_must_fail git am --3way side-first.patch side-second.patch &&
>>> +     test -n "$(git ls-files -u)" &&
>>> +     echo will-conflict >file &&
>>> +     git add file &&
>>> +     test_must_fail git am --no-3way --continue &&
>>> +     test -z "$(git ls-files -u)"
>>> +'
>>> +
>
> ... Although if I implement the above change, I can't implement the
> test for --3way, as I think the only way to check if --3way/--no-3way
> successfully overrides the saved options for the current patch only is
> to run "git am --3way", but that does not work in the test runner as
> it expects stdin to be a TTY :-/ So I may have to remove this test.
> This shouldn't be a problem though, as all the tests in this test
> suite all test the same mechanism.

Sorry, you lost me.  Where does the TTY come into the picture only
for --3way (but not for other things like --quiet)?

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH] am: let command-line options override saved options
  2015-07-31 16:04             ` Junio C Hamano
@ 2015-08-01  0:59               ` Paul Tan
  0 siblings, 0 replies; 26+ messages in thread
From: Paul Tan @ 2015-08-01  0:59 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Remi Lespinet, Git List, Stefan Beller,
	Johannes Schindelin

On Sat, Aug 1, 2015 at 12:04 AM, Junio C Hamano <gitster@pobox.com> wrote:
> Paul Tan <pyokagan@gmail.com> writes:
>
>> I think I will introduce a format_patch() function that takes a single
>> commit-ish so that we can use tag names to name the patches:
>>
>> # Given a single commit $commit, formats the following patches with
>> # git-format-patch:
>> #
>> # 1. $commit.eml: an email patch with a Message-Id header.
>> # 2. $commit.scissors: like $commit.eml but contains a scissors line at the
>> #    start of the commit message body.
>> format_patch () {
>>     {
>>         echo "Message-Id: <$1@example.com>" &&
>>         git format-patch --stdout -1 "$1" | sed -e '1d'
>>     } >"$1".eml &&
>
> I only said I can "understand" what is going on, though.
>
> It feels a bit unnatural for a test to feed a message that lack the
> "From " header line.  Perhaps
>
>         git format-patch --add-header="Message-Id: ..." --stdout -1
>
> or something?

Ah, okay. I wasn't aware of the --add-header option, but this is
definitely better.

>> These functions are called before we attempt to apply the patch, so we
>> should probably call append_signoff before then. However, this still
>> means that --no-signoff will have no effect should the patch
>> application fail and we resume, as the signoff would still have
>> already been appended...
>
> Ah, I see.  Let's not worry about this; we cannot change the
> expectation existing hook scripts depends on.

Okay, although this means that with the below change, --[no-]signoff
will be the oddball option that does not work when resuming.

>> 2. Re-reading Peff's message, I see that he expects the command-line
>> options to affect just the current patch, which makes sense. This
>> patch would need to be extended to call am_load() after we finish
>> processing the current patch when resuming.
>
> Yeah, so the idea is:
>
>  - upon the very first invocation, we parse the command line options
>    and write the states out;
>
>  - subsequent invocation, we read from the states and then override
>    with the command line options, but we do not write the states out
>    to update, so that subsequent invocations will keep reading from
>    the very first one.

... and we also load back the saved options after processing the patch
that we resume from, so the command-line options only affect the
conflicting patch, which fits in with Peff's idea on "wiggling that
_one_ patch".

>>>> +test_expect_success '--3way, --no-3way' '
>>>> +     rm -fr .git/rebase-apply &&
>>>> +     git reset --hard &&
>>>> +     git checkout first &&
>>>> +     test_must_fail git am --3way side-first.patch side-second.patch &&
>>>> +     test -n "$(git ls-files -u)" &&
>>>> +     echo will-conflict >file &&
>>>> +     git add file &&
>>>> +     test_must_fail git am --no-3way --continue &&
>>>> +     test -z "$(git ls-files -u)"
>>>> +'
>>>> +
>>
>> ... Although if I implement the above change, I can't implement the
>> test for --3way, as I think the only way to check if --3way/--no-3way
>> successfully overrides the saved options for the current patch only is
>> to run "git am --3way", but that does not work in the test runner as
>> it expects stdin to be a TTY :-/ So I may have to remove this test.
>> This shouldn't be a problem though, as all the tests in this test
>> suite all test the same mechanism.
>
> Sorry, you lost me.  Where does the TTY come into the picture only
> for --3way (but not for other things like --quiet)?

Ah, sorry, I should have provided more context. This is due to the
following block of code:

        /*
         * Catch user error to feed us patches when there is a session
         * in progress:
         *
         * 1. mbox path(s) are provided on the command-line.
         * 2. stdin is not a tty: the user is trying to feed us a patch
         *    from standard input. This is somewhat unreliable -- stdin
         *    could be /dev/null for example and the caller did not
         *    intend to feed us a patch but wanted to continue
         *    unattended.
         */
        if (argc || (resume == RESUME_FALSE && !isatty(0)))
            die(_("previous rebase directory %s still exists but mbox given."),
                state.dir);

And it will activate when git-am is run without
--continue/--abort/--skip (e.g. "git am --3way") because the test
framework sets stdin to /dev/null.

Thanks,
Paul

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH v2 0/3] am: let command-line options override saved options
  2015-07-28 16:43       ` [PATCH] am: let command-line options override saved options Paul Tan
  2015-07-28 16:48         ` Junio C Hamano
  2015-07-28 17:09         ` Junio C Hamano
@ 2015-08-04 14:05         ` Paul Tan
  2015-08-04 21:12           ` Junio C Hamano
  2015-08-04 14:08         ` Paul Tan
  3 siblings, 1 reply; 26+ messages in thread
From: Paul Tan @ 2015-08-04 14:05 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Johannes Schindelin, Stefan Beller, Remi Lespinet,
	Jeff King, Paul Tan

Let command-line options override saved options in git-am when resuming

This is a re-roll of [v1]. Previous versions:

[v1] http://thread.gmane.org/gmane.comp.version-control.git/274789

When resuming, git-am mistakenly ignores command-line options.

For instance, when a patch fails to apply with "git am patch", subsequently
running "git am --3way" would not cause git-am to fall back on attempting a
threeway merge.  This occurs because by default the --3way option is saved as
"false", and the saved am options are loaded after the command-line options are
parsed, thus overwriting the command-line options when resuming.

[PATCH 1/3] tweaks test-terminal.perl to redirect the stdin of the child
process to a pty. This is to support the tests in [PATCH 2/3].

[PATCH 2/3] fixes builtin/am.c, enabling command-line options to override saved
options. However, even with this patch, the following command-line options have
no effect when resuming:

* --signoff overriding --no-signoff

* --no-keep overriding --keep

* --message-id overriding --no-message-id

* --scissors overriding --no-scissors

This is because they are only taken into account during the mail-parsing stage,
which is skipped over when resuming.

[PATCH 3/3] adds support for the --signoff option when resuming by recognizing
that we can (re-)append the signoff when the user explicitly specifies the
--signoff option.

Since the --keep, --message-id and --scissors options are handled by
git-mailinfo, it is tricky to implement support for them without introducing
lots of code complexity, and thus this patch series does not attempt to.

Furthermore, it is hard to imagine a use case for e.g. --scissors overriding
--no-scissors, and hence it might be preferable to wait until someone comes
with a solid use case, instead of implementing potentially undesirable behavior
and having to support it.


Paul Tan (3):
  test_terminal: redirect child process' stdin to a pty
  am: let command-line options override saved options
  am: let --signoff override --no-signoff

 builtin/am.c                       |  42 ++++++++++++---
 t/t4153-am-resume-override-opts.sh | 102 +++++++++++++++++++++++++++++++++++++
 t/test-terminal.perl               |  25 +++++++--
 3 files changed, 158 insertions(+), 11 deletions(-)
 create mode 100755 t/t4153-am-resume-override-opts.sh

-- 
2.5.0.280.gd88bd6e

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH v2 0/3] am: let command-line options override saved options
  2015-07-28 16:43       ` [PATCH] am: let command-line options override saved options Paul Tan
                           ` (2 preceding siblings ...)
  2015-08-04 14:05         ` [PATCH v2 0/3] " Paul Tan
@ 2015-08-04 14:08         ` Paul Tan
  2015-08-04 14:08           ` [PATCH v2 1/3] test_terminal: redirect child process' stdin to a pty Paul Tan
                             ` (3 more replies)
  3 siblings, 4 replies; 26+ messages in thread
From: Paul Tan @ 2015-08-04 14:08 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Johannes Schindelin, Stefan Beller, Remi Lespinet,
	Jeff King, Paul Tan

Let command-line options override saved options in git-am when resuming

This is a re-roll of [v1]. Previous versions:

[v1] http://thread.gmane.org/gmane.comp.version-control.git/274789

When resuming, git-am mistakenly ignores command-line options.

For instance, when a patch fails to apply with "git am patch", subsequently
running "git am --3way" would not cause git-am to fall back on attempting a
threeway merge.  This occurs because by default the --3way option is saved as
"false", and the saved am options are loaded after the command-line options are
parsed, thus overwriting the command-line options when resuming.

[PATCH 1/3] tweaks test-terminal.perl to redirect the stdin of the child
process to a pty. This is to support the tests in [PATCH 2/3].

[PATCH 2/3] fixes builtin/am.c, enabling command-line options to override saved
options. However, even with this patch, the following command-line options have
no effect when resuming:

* --signoff overriding --no-signoff

* --no-keep overriding --keep

* --message-id overriding --no-message-id

* --scissors overriding --no-scissors

This is because they are only taken into account during the mail-parsing stage,
which is skipped over when resuming.

[PATCH 3/3] adds support for the --signoff option when resuming by recognizing
that we can (re-)append the signoff when the user explicitly specifies the
--signoff option.

Since the --keep, --message-id and --scissors options are handled by
git-mailinfo, it is tricky to implement support for them without introducing
lots of code complexity, and thus this patch series does not attempt to.

Furthermore, it is hard to imagine a use case for e.g. --scissors overriding
--no-scissors, and hence it might be preferable to wait until someone comes
with a solid use case, instead of implementing potentially undesirable behavior
and having to support it.


Paul Tan (3):
  test_terminal: redirect child process' stdin to a pty
  am: let command-line options override saved options
  am: let --signoff override --no-signoff

 builtin/am.c                       |  42 ++++++++++++---
 t/t4153-am-resume-override-opts.sh | 102 +++++++++++++++++++++++++++++++++++++
 t/test-terminal.perl               |  25 +++++++--
 3 files changed, 158 insertions(+), 11 deletions(-)
 create mode 100755 t/t4153-am-resume-override-opts.sh

-- 
2.5.0.280.gd88bd6e

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH v2 1/3] test_terminal: redirect child process' stdin to a pty
  2015-08-04 14:08         ` Paul Tan
@ 2015-08-04 14:08           ` Paul Tan
  2015-08-06 22:15             ` Eric Sunshine
  2015-08-04 14:08           ` [PATCH v2 2/3] am: let command-line options override saved options Paul Tan
                             ` (2 subsequent siblings)
  3 siblings, 1 reply; 26+ messages in thread
From: Paul Tan @ 2015-08-04 14:08 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Johannes Schindelin, Stefan Beller, Remi Lespinet,
	Jeff King, Paul Tan, Jonathan Nieder

When resuming, git-am detects if we are trying to feed it patches or not
by checking if stdin is a TTY.

However, the test library redirects stdin to /dev/null. This makes it
difficult, for instance, to test the behavior of "git am -3" when
resuming, as git-am will think we are trying to feed it patches and
error out.

Support this use case by extending test-terminal.perl to create a
pseudo-tty for the child process' standard input as well.

Note that due to the way the code is structured, the child's stdin
pseudo-tty will be closed when we finish reading from our stdin. This
means that in the common case, where our stdin is attached to /dev/null,
the child's stdin pseudo-tty will be closed immediately. Some operations
like isatty(), which git-am uses, require the file descriptor to be
open, and hence if the success of the command depends on such functions,
test_terminal's stdin should be redirected to a source with large amount
of data to ensure that the child's stdin is not closed, e.g.

	test_terminal git am --3way </dev/zero

Cc: Jonathan Nieder <jrnieder@gmail.com>
Cc: Jeff King <peff@peff.net>
Signed-off-by: Paul Tan <pyokagan@gmail.com>
---
 t/test-terminal.perl | 25 ++++++++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/t/test-terminal.perl b/t/test-terminal.perl
index 1fb373f..f6fc9ae 100755
--- a/t/test-terminal.perl
+++ b/t/test-terminal.perl
@@ -5,15 +5,17 @@ use warnings;
 use IO::Pty;
 use File::Copy;
 
-# Run @$argv in the background with stdio redirected to $out and $err.
+# Run @$argv in the background with stdio redirected to $in, $out and $err.
 sub start_child {
-	my ($argv, $out, $err) = @_;
+	my ($argv, $in, $out, $err) = @_;
 	my $pid = fork;
 	if (not defined $pid) {
 		die "fork failed: $!"
 	} elsif ($pid == 0) {
+		open STDIN, "<&", $in;
 		open STDOUT, ">&", $out;
 		open STDERR, ">&", $err;
+		close $in;
 		close $out;
 		exec(@$argv) or die "cannot exec '$argv->[0]': $!"
 	}
@@ -50,14 +52,23 @@ sub xsendfile {
 }
 
 sub copy_stdio {
-	my ($out, $err) = @_;
+	my ($in, $out, $err) = @_;
 	my $pid = fork;
+	if (!$pid) {
+		close($out);
+		close($err);
+		xsendfile($in, \*STDIN);
+		exit 0;
+	}
+	$pid = fork;
 	defined $pid or die "fork failed: $!";
 	if (!$pid) {
+		close($in);
 		close($out);
 		xsendfile(\*STDERR, $err);
 		exit 0;
 	}
+	close($in);
 	close($err);
 	xsendfile(\*STDOUT, $out);
 	finish_child($pid) == 0
@@ -67,14 +78,18 @@ sub copy_stdio {
 if ($#ARGV < 1) {
 	die "usage: test-terminal program args";
 }
+my $master_in = new IO::Pty;
 my $master_out = new IO::Pty;
 my $master_err = new IO::Pty;
+$master_in->set_raw();
 $master_out->set_raw();
 $master_err->set_raw();
+$master_in->slave->set_raw();
 $master_out->slave->set_raw();
 $master_err->slave->set_raw();
-my $pid = start_child(\@ARGV, $master_out->slave, $master_err->slave);
+my $pid = start_child(\@ARGV, $master_in->slave, $master_out->slave, $master_err->slave);
+close $master_in->slave;
 close $master_out->slave;
 close $master_err->slave;
-copy_stdio($master_out, $master_err);
+copy_stdio($master_in, $master_out, $master_err);
 exit(finish_child($pid));
-- 
2.5.0.280.gd88bd6e

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v2 2/3] am: let command-line options override saved options
  2015-08-04 14:08         ` Paul Tan
  2015-08-04 14:08           ` [PATCH v2 1/3] test_terminal: redirect child process' stdin to a pty Paul Tan
@ 2015-08-04 14:08           ` Paul Tan
  2015-08-04 14:08           ` [PATCH v2 3/3] am: let --signoff override --no-signoff Paul Tan
  2015-08-05 15:41           ` [PATCH v2 0/3] am: let command-line options override saved options Junio C Hamano
  3 siblings, 0 replies; 26+ messages in thread
From: Paul Tan @ 2015-08-04 14:08 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Johannes Schindelin, Stefan Beller, Remi Lespinet,
	Jeff King, Paul Tan

When resuming, git-am mistakenly ignores command-line options.

For instance, when a patch fails to apply with "git am patch",
subsequently running "git am --3way" would not cause git-am to fall
back on attempting a threeway merge.  This occurs because by default
the --3way option is saved as "false", and the saved am options are
loaded after the command-line options are parsed, thus overwriting
the command-line options when resuming.

Fix this by moving the am_load() function call before parse_options(),
so that command-line options will override the saved am options.

The purpose of supporting this use case is to enable users to "wiggle"
that one conflicting patch. As such, it is expected that the
command-line options do not affect subsequent applied patches. Implement
this by calling am_load() once we apply the conflicting patch
successfully.

Noticed-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Jeff King <peff@peff.net>
Signed-off-by: Paul Tan <pyokagan@gmail.com>
---
 builtin/am.c                       | 16 ++++++--
 t/t4153-am-resume-override-opts.sh | 82 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 94 insertions(+), 4 deletions(-)
 create mode 100755 t/t4153-am-resume-override-opts.sh

diff --git a/builtin/am.c b/builtin/am.c
index 84d57d4..0961304 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -1777,7 +1777,6 @@ static void am_run(struct am_state *state, int resume)
 
 		if (resume) {
 			validate_resume_state(state);
-			resume = 0;
 		} else {
 			int skip;
 
@@ -1839,6 +1838,10 @@ static void am_run(struct am_state *state, int resume)
 
 next:
 		am_next(state);
+
+		if (resume)
+			am_load(state);
+		resume = 0;
 	}
 
 	if (!is_empty_file(am_path(state, "rewritten"))) {
@@ -1893,6 +1896,7 @@ static void am_resolve(struct am_state *state)
 
 next:
 	am_next(state);
+	am_load(state);
 	am_run(state, 0);
 }
 
@@ -2020,6 +2024,7 @@ static void am_skip(struct am_state *state)
 		die(_("failed to clean index"));
 
 	am_next(state);
+	am_load(state);
 	am_run(state, 0);
 }
 
@@ -2130,6 +2135,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
 	int keep_cr = -1;
 	int patch_format = PATCH_FORMAT_UNKNOWN;
 	enum resume_mode resume = RESUME_FALSE;
+	int in_progress;
 
 	const char * const usage[] = {
 		N_("git am [options] [(<mbox>|<Maildir>)...]"),
@@ -2225,6 +2231,10 @@ int cmd_am(int argc, const char **argv, const char *prefix)
 
 	am_state_init(&state, git_path("rebase-apply"));
 
+	in_progress = am_in_progress(&state);
+	if (in_progress)
+		am_load(&state);
+
 	argc = parse_options(argc, argv, prefix, options, usage, 0);
 
 	if (binary >= 0)
@@ -2237,7 +2247,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
 	if (read_index_preload(&the_index, NULL) < 0)
 		die(_("failed to read the index"));
 
-	if (am_in_progress(&state)) {
+	if (in_progress) {
 		/*
 		 * Catch user error to feed us patches when there is a session
 		 * in progress:
@@ -2255,8 +2265,6 @@ int cmd_am(int argc, const char **argv, const char *prefix)
 
 		if (resume == RESUME_FALSE)
 			resume = RESUME_APPLY;
-
-		am_load(&state);
 	} else {
 		struct argv_array paths = ARGV_ARRAY_INIT;
 		int i;
diff --git a/t/t4153-am-resume-override-opts.sh b/t/t4153-am-resume-override-opts.sh
new file mode 100755
index 0000000..39fac79
--- /dev/null
+++ b/t/t4153-am-resume-override-opts.sh
@@ -0,0 +1,82 @@
+#!/bin/sh
+
+test_description='git-am command-line options override saved options'
+
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-terminal.sh
+
+format_patch () {
+	git format-patch --stdout -1 "$1" >"$1".eml
+}
+
+test_expect_success 'setup' '
+	test_commit initial file &&
+	test_commit first file &&
+
+	git checkout initial &&
+	git mv file file2 &&
+	test_tick &&
+	git commit -m renamed-file &&
+	git tag renamed-file &&
+
+	git checkout -b side initial &&
+	test_commit side1 file &&
+	test_commit side2 file &&
+
+	format_patch side1 &&
+	format_patch side2
+'
+
+test_expect_success TTY '--3way overrides --no-3way' '
+	rm -fr .git/rebase-apply &&
+	git reset --hard &&
+	git checkout renamed-file &&
+
+	# Applying side1 will fail as the file has been renamed.
+	test_must_fail git am --no-3way side[12].eml &&
+	test_path_is_dir .git/rebase-apply &&
+	test_cmp_rev renamed-file HEAD &&
+	test -z "$(git ls-files -u)" &&
+
+	# Applying side1 with am --3way will succeed due to the threeway-merge.
+	# Applying side2 will fail as --3way does not apply to it.
+	test_must_fail test_terminal git am --3way </dev/zero &&
+	test_path_is_dir .git/rebase-apply &&
+	test side1 = "$(cat file2)"
+'
+
+test_expect_success '--no-quiet overrides --quiet' '
+	rm -fr .git/rebase-apply &&
+	git reset --hard &&
+	git checkout first &&
+
+	# Applying side1 will be quiet.
+	test_must_fail git am --quiet side[123].eml >out &&
+	test_path_is_dir .git/rebase-apply &&
+	! test_i18ngrep "^Applying: " out &&
+	echo side1 >file &&
+	git add file &&
+
+	# Applying side1 will not be quiet.
+	# Applying side2 will be quiet.
+	git am --no-quiet --continue >out &&
+	echo "Applying: side1" >expected &&
+	test_i18ncmp expected out
+'
+
+test_expect_success TTY '--reject overrides --no-reject' '
+	rm -fr .git/rebase-apply &&
+	git reset --hard &&
+	git checkout first &&
+	rm -f file.rej &&
+
+	test_must_fail git am --no-reject side1.eml &&
+	test_path_is_dir .git/rebase-apply &&
+	test_path_is_missing file.rej &&
+
+	test_must_fail test_terminal git am --reject </dev/zero &&
+	test_path_is_dir .git/rebase-apply &&
+	test_path_is_file file.rej
+'
+
+test_done
-- 
2.5.0.280.gd88bd6e

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v2 3/3] am: let --signoff override --no-signoff
  2015-08-04 14:08         ` Paul Tan
  2015-08-04 14:08           ` [PATCH v2 1/3] test_terminal: redirect child process' stdin to a pty Paul Tan
  2015-08-04 14:08           ` [PATCH v2 2/3] am: let command-line options override saved options Paul Tan
@ 2015-08-04 14:08           ` Paul Tan
  2015-08-07  9:29             ` Johannes Schindelin
  2015-08-05 15:41           ` [PATCH v2 0/3] am: let command-line options override saved options Junio C Hamano
  3 siblings, 1 reply; 26+ messages in thread
From: Paul Tan @ 2015-08-04 14:08 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Johannes Schindelin, Stefan Beller, Remi Lespinet,
	Jeff King, Paul Tan

After resolving a conflicting patch, a user may wish to sign off the
patch to declare that the patch has been modified. As such, the user
will expect that running "git am --signoff --continue" will append the
signoff to the commit message.

However, the --signoff option is only taken into account during the
mail-parsing stage. If the --signoff option is set, then the signoff
will be appended to the commit message. Since the mail-parsing stage
comes before the patch application stage, the --signoff option, if
provided on the command-line when resuming, will have no effect at all.

We cannot move the append_signoff() call to the patch application stage
as the applypatch-msg hook and interactive mode, which run before patch
application, may expect the signoff to be there.

Fix this by taking note if the user explictly set the --signoff option
on the command-line, and append the signoff to the commit message when
resuming if so.

Signed-off-by: Paul Tan <pyokagan@gmail.com>
---
 builtin/am.c                       | 28 +++++++++++++++++++++++++---
 t/t4153-am-resume-override-opts.sh | 20 ++++++++++++++++++++
 2 files changed, 45 insertions(+), 3 deletions(-)

diff --git a/builtin/am.c b/builtin/am.c
index 0961304..8c95aec 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -98,6 +98,12 @@ enum scissors_type {
 	SCISSORS_TRUE        /* pass --scissors to git-mailinfo */
 };
 
+enum signoff_type {
+	SIGNOFF_FALSE = 0,
+	SIGNOFF_TRUE = 1,
+	SIGNOFF_EXPLICIT /* --signoff was set on the command-line */
+};
+
 struct am_state {
 	/* state directory path */
 	char *dir;
@@ -123,7 +129,7 @@ struct am_state {
 	int interactive;
 	int threeway;
 	int quiet;
-	int signoff;
+	int signoff; /* enum signoff_type */
 	int utf8;
 	int keep; /* enum keep_type */
 	int message_id;
@@ -1184,6 +1190,18 @@ static void NORETURN die_user_resolve(const struct am_state *state)
 }
 
 /**
+ * Appends signoff to the "msg" field of the am_state.
+ */
+static void am_append_signoff(struct am_state *state)
+{
+	struct strbuf sb = STRBUF_INIT;
+
+	strbuf_attach(&sb, state->msg, state->msg_len, state->msg_len);
+	append_signoff(&sb, 0, 0);
+	state->msg = strbuf_detach(&sb, &state->msg_len);
+}
+
+/**
  * Parses `mail` using git-mailinfo, extracting its patch and authorship info.
  * state->msg will be set to the patch message. state->author_name,
  * state->author_email and state->author_date will be set to the patch author's
@@ -2151,8 +2169,9 @@ int cmd_am(int argc, const char **argv, const char *prefix)
 		OPT_BOOL('3', "3way", &state.threeway,
 			N_("allow fall back on 3way merging if needed")),
 		OPT__QUIET(&state.quiet, N_("be quiet")),
-		OPT_BOOL('s', "signoff", &state.signoff,
-			N_("add a Signed-off-by line to the commit message")),
+		OPT_SET_INT('s', "signoff", &state.signoff,
+			N_("add a Signed-off-by line to the commit message"),
+			SIGNOFF_EXPLICIT),
 		OPT_BOOL('u', "utf8", &state.utf8,
 			N_("recode into utf8 (default)")),
 		OPT_SET_INT('k', "keep", &state.keep,
@@ -2265,6 +2284,9 @@ int cmd_am(int argc, const char **argv, const char *prefix)
 
 		if (resume == RESUME_FALSE)
 			resume = RESUME_APPLY;
+
+		if (state.signoff == SIGNOFF_EXPLICIT)
+			am_append_signoff(&state);
 	} else {
 		struct argv_array paths = ARGV_ARRAY_INIT;
 		int i;
diff --git a/t/t4153-am-resume-override-opts.sh b/t/t4153-am-resume-override-opts.sh
index 39fac79..7c013d8 100755
--- a/t/t4153-am-resume-override-opts.sh
+++ b/t/t4153-am-resume-override-opts.sh
@@ -64,6 +64,26 @@ test_expect_success '--no-quiet overrides --quiet' '
 	test_i18ncmp expected out
 '
 
+test_expect_success '--signoff overrides --no-signoff' '
+	rm -fr .git/rebase-apply &&
+	git reset --hard &&
+	git checkout first &&
+
+	test_must_fail git am --no-signoff side[12].eml &&
+	test_path_is_dir .git/rebase-apply &&
+	echo side1 >file &&
+	git add file &&
+	git am --signoff --continue &&
+
+	# Applied side1 will be signed off
+	echo "Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" >expected &&
+	git cat-file commit HEAD^ | grep "Signed-off-by:" >actual &&
+	test_cmp expected actual &&
+
+	# Applied side2 will not be signed off
+	test $(git cat-file commit HEAD | grep -c "Signed-off-by:") -eq 0
+'
+
 test_expect_success TTY '--reject overrides --no-reject' '
 	rm -fr .git/rebase-apply &&
 	git reset --hard &&
-- 
2.5.0.280.gd88bd6e

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [PATCH v2 0/3] am: let command-line options override saved options
  2015-08-04 14:05         ` [PATCH v2 0/3] " Paul Tan
@ 2015-08-04 21:12           ` Junio C Hamano
  0 siblings, 0 replies; 26+ messages in thread
From: Junio C Hamano @ 2015-08-04 21:12 UTC (permalink / raw)
  To: Paul Tan
  Cc: git, Johannes Schindelin, Stefan Beller, Remi Lespinet, Jeff King

Paul Tan <pyokagan@gmail.com> writes:

> Let command-line options override saved options in git-am when resuming
>
> This is a re-roll of [v1]. Previous versions:
>
> [v1] http://thread.gmane.org/gmane.comp.version-control.git/274789
>
> When resuming, git-am mistakenly ignores command-line options.
>
> For instance, when a patch fails to apply with "git am patch", subsequently
> running "git am --3way" would not cause git-am to fall back on attempting a
> threeway merge.  This occurs because by default the --3way option is saved as
> "false", and the saved am options are loaded after the command-line options are
> parsed, thus overwriting the command-line options when resuming.
>
> [PATCH 1/3] tweaks test-terminal.perl to redirect the stdin of the child
> process to a pty. This is to support the tests in [PATCH 2/3].
>
> [PATCH 2/3] fixes builtin/am.c, enabling command-line options to override saved
> options. However, even with this patch, the following command-line options have
> no effect when resuming:
>
> * --signoff overriding --no-signoff
>
> * --no-keep overriding --keep
>
> * --message-id overriding --no-message-id
>
> * --scissors overriding --no-scissors
>
> This is because they are only taken into account during the mail-parsing stage,
> which is skipped over when resuming.

It is more like "which has already happened", so I would tend to
think that these are the right things to ignore.  Otherwise, a
pretty common sequence would not work well ...

    $ git am mbox
    ... conflicted ...
    $ edit .git/rebase-apply/patch
    $ git am

... if the "resuming" invocation re-split the message by running
mailinfo again, the edit by the user will be lost.

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v2 0/3] am: let command-line options override saved options
  2015-08-04 14:08         ` Paul Tan
                             ` (2 preceding siblings ...)
  2015-08-04 14:08           ` [PATCH v2 3/3] am: let --signoff override --no-signoff Paul Tan
@ 2015-08-05 15:41           ` Junio C Hamano
  2015-08-05 17:51             ` Paul Tan
  3 siblings, 1 reply; 26+ messages in thread
From: Junio C Hamano @ 2015-08-05 15:41 UTC (permalink / raw)
  To: Paul Tan
  Cc: git, Johannes Schindelin, Stefan Beller, Remi Lespinet, Jeff King

Interesting.  This seems to break test under prove.

    cd t && make T=t4153-am-resume-override-opts.sh prove

does not seem to return.

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v2 0/3] am: let command-line options override saved options
  2015-08-05 15:41           ` [PATCH v2 0/3] am: let command-line options override saved options Junio C Hamano
@ 2015-08-05 17:51             ` Paul Tan
  0 siblings, 0 replies; 26+ messages in thread
From: Paul Tan @ 2015-08-05 17:51 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: git, Johannes Schindelin, Stefan Beller, Remi Lespinet, Jeff King

On Wed, Aug 05, 2015 at 08:41:44AM -0700, Junio C Hamano wrote:
> Interesting.  This seems to break test under prove.
> 
>     cd t && make T=t4153-am-resume-override-opts.sh prove
> 
> does not seem to return.

The new test-terminal.perl code is the culprit. It seems that if our
wrapped process terminates before our stdin-writing fork does, our
stdin-writing process will stall. I think this occurs with prove because
prove waits until all of its child processes terminate before returning.

So, the solution may be to send a SIGTERM to our stdin-writing fork
should our wrapped process terminate before it does, in order to ensure
that it immediately exits.

The following squash fixes it for me.

Thanks,
Paul

-- >8 --
Subject: [PATCH] squash! test_terminal: redirect child process' stdin to a pty

When the child process terminates before the copy_stdio() finishes
writing all of its data to the child's stdin slave pty, it will stall.

As such, we first move the stdin-pty-writing logic out of copy_stdio()
into its own subroutine copy_stdin() so that we can manage the forked
process ourselves, and then we send SIGTERM to the forked process should
the command we are wrapping terminate before copy_stdin() finishes
writing all of its data to un-stall it.

Signed-off-by: Paul Tan <pyokagan@gmail.com>
---
 t/test-terminal.perl | 27 ++++++++++++++++++---------
 1 file changed, 18 insertions(+), 9 deletions(-)

diff --git a/t/test-terminal.perl b/t/test-terminal.perl
index f6fc9ae..96b6a03 100755
--- a/t/test-terminal.perl
+++ b/t/test-terminal.perl
@@ -51,24 +51,26 @@ sub xsendfile {
 	copy($in, $out, 4096) or $!{EIO} or die "cannot copy from child: $!";
 }
 
-sub copy_stdio {
-	my ($in, $out, $err) = @_;
+sub copy_stdin {
+	my ($in) = @_;
 	my $pid = fork;
 	if (!$pid) {
-		close($out);
-		close($err);
 		xsendfile($in, \*STDIN);
 		exit 0;
 	}
-	$pid = fork;
+	close($in);
+	return $pid;
+}
+
+sub copy_stdio {
+	my ($out, $err) = @_;
+	my $pid = fork;
 	defined $pid or die "fork failed: $!";
 	if (!$pid) {
-		close($in);
 		close($out);
 		xsendfile(\*STDERR, $err);
 		exit 0;
 	}
-	close($in);
 	close($err);
 	xsendfile(\*STDOUT, $out);
 	finish_child($pid) == 0
@@ -91,5 +93,12 @@ my $pid = start_child(\@ARGV, $master_in->slave, $master_out->slave, $master_err
 close $master_in->slave;
 close $master_out->slave;
 close $master_err->slave;
-copy_stdio($master_in, $master_out, $master_err);
-exit(finish_child($pid));
+my $in_pid = copy_stdin($master_in);
+copy_stdio($master_out, $master_err);
+my $ret = finish_child($pid);
+# If the child process terminates before our copy_stdin() process is able to
+# write all of its data to $master_in, the copy_stdin() process could stall.
+# Send SIGTERM to it to ensure it terminates.
+kill 'TERM', $in_pid;
+finish_child($in_pid);
+exit($ret);
-- 
2.5.0.282.gdd6b4b0

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [PATCH v2 1/3] test_terminal: redirect child process' stdin to a pty
  2015-08-04 14:08           ` [PATCH v2 1/3] test_terminal: redirect child process' stdin to a pty Paul Tan
@ 2015-08-06 22:15             ` Eric Sunshine
  2015-08-12  4:16               ` Paul Tan
  0 siblings, 1 reply; 26+ messages in thread
From: Eric Sunshine @ 2015-08-06 22:15 UTC (permalink / raw)
  To: Paul Tan
  Cc: Git List, Junio C Hamano, Johannes Schindelin, Stefan Beller,
	Remi Lespinet, Jeff King, Jonathan Nieder

On Tue, Aug 4, 2015 at 10:08 AM, Paul Tan <pyokagan@gmail.com> wrote:
> When resuming, git-am detects if we are trying to feed it patches or not
> by checking if stdin is a TTY.
>
> However, the test library redirects stdin to /dev/null. This makes it
> difficult, for instance, to test the behavior of "git am -3" when
> resuming, as git-am will think we are trying to feed it patches and
> error out.
>
> Support this use case by extending test-terminal.perl to create a
> pseudo-tty for the child process' standard input as well.

An alternative would be to have git-am detect that it is being tested
and pretend that isatty() returns true. There is some precedent for
having core functionality recognize that it is being tested. See, for
instance, environment variable TEST_DATE_NOW, and rev-list
--test-bitmap. Doing so would allow the tests work on non-Unix
platforms, as well.

> Note that due to the way the code is structured, the child's stdin
> pseudo-tty will be closed when we finish reading from our stdin. This
> means that in the common case, where our stdin is attached to /dev/null,
> the child's stdin pseudo-tty will be closed immediately. Some operations
> like isatty(), which git-am uses, require the file descriptor to be
> open, and hence if the success of the command depends on such functions,
> test_terminal's stdin should be redirected to a source with large amount
> of data to ensure that the child's stdin is not closed, e.g.
>
>         test_terminal git am --3way </dev/zero
>
> Signed-off-by: Paul Tan <pyokagan@gmail.com>

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v2 3/3] am: let --signoff override --no-signoff
  2015-08-04 14:08           ` [PATCH v2 3/3] am: let --signoff override --no-signoff Paul Tan
@ 2015-08-07  9:29             ` Johannes Schindelin
  2015-08-12  3:06               ` Paul Tan
  0 siblings, 1 reply; 26+ messages in thread
From: Johannes Schindelin @ 2015-08-07  9:29 UTC (permalink / raw)
  To: Paul Tan; +Cc: git, Junio C Hamano, Stefan Beller, Remi Lespinet, Jeff King

Hi Paul,

On 2015-08-04 16:08, Paul Tan wrote:

> diff --git a/builtin/am.c b/builtin/am.c
> index 0961304..8c95aec 100644
> --- a/builtin/am.c
> +++ b/builtin/am.c
> @@ -2151,8 +2169,9 @@ int cmd_am(int argc, const char **argv, const
> [...]
> char *prefix)
>  		OPT_BOOL('3', "3way", &state.threeway,
>  			N_("allow fall back on 3way merging if needed")),
>  		OPT__QUIET(&state.quiet, N_("be quiet")),
> -		OPT_BOOL('s', "signoff", &state.signoff,
> -			N_("add a Signed-off-by line to the commit message")),
> +		OPT_SET_INT('s', "signoff", &state.signoff,
> +			N_("add a Signed-off-by line to the commit message"),
> +			SIGNOFF_EXPLICIT),
>  		OPT_BOOL('u', "utf8", &state.utf8,
>  			N_("recode into utf8 (default)")),
>  		OPT_SET_INT('k', "keep", &state.keep,
> @@ -2265,6 +2284,9 @@ int cmd_am(int argc, const char **argv, const
> char *prefix)
>  
>  		if (resume == RESUME_FALSE)
>  			resume = RESUME_APPLY;
> +
> +		if (state.signoff == SIGNOFF_EXPLICIT)
> +			am_append_signoff(&state);
>  	} else {

This is clever, but I suspect there is now a chance for a double-signoff if we passed `--signoff` to the initial `git am` call and it went through without having to resume.

Or am I missing something?

Ciao,
Dscho

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v2 3/3] am: let --signoff override --no-signoff
  2015-08-07  9:29             ` Johannes Schindelin
@ 2015-08-12  3:06               ` Paul Tan
  2015-08-12  3:07                 ` Paul Tan
  0 siblings, 1 reply; 26+ messages in thread
From: Paul Tan @ 2015-08-12  3:06 UTC (permalink / raw)
  To: Johannes Schindelin
  Cc: Git List, Junio C Hamano, Stefan Beller, Remi Lespinet, Jeff King

On Fri, Aug 7, 2015 at 5:29 PM, Johannes Schindelin
<johannes.schindelin@gmx.de> wrote:
>> diff --git a/builtin/am.c b/builtin/am.c
>> index 0961304..8c95aec 100644
>> --- a/builtin/am.c
>> +++ b/builtin/am.c
>> @@ -2265,6 +2284,9 @@ int cmd_am(int argc, const char **argv, const
>> char *prefix)
>>
>>               if (resume == RESUME_FALSE)
>>                       resume = RESUME_APPLY;
>> +
>> +             if (state.signoff == SIGNOFF_EXPLICIT)
>> +                     am_append_signoff(&state);
>>       } else {
>
> This is clever, but I suspect there is now a chance for a double-signoff if we passed `--signoff` to the initial `git am` call and it went through without having to resume.

It's not present in this diff context, but this hunk modifies the code
path where in_progress is true. In other words, we only check for
SIGNOFF_EXPLICIT if

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v2 3/3] am: let --signoff override --no-signoff
  2015-08-12  3:06               ` Paul Tan
@ 2015-08-12  3:07                 ` Paul Tan
  0 siblings, 0 replies; 26+ messages in thread
From: Paul Tan @ 2015-08-12  3:07 UTC (permalink / raw)
  To: Johannes Schindelin
  Cc: Git List, Junio C Hamano, Stefan Beller, Remi Lespinet, Jeff King

On Wed, Aug 12, 2015 at 11:06 AM, Paul Tan <pyokagan@gmail.com> wrote:
> It's not present in this diff context, but this hunk modifies the code
> path where in_progress is true. In other words, we only check for
> SIGNOFF_EXPLICIT if

..we are resuming.

(Ugh, butter fingers)

Thanks,
Paul

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v2 1/3] test_terminal: redirect child process' stdin to a pty
  2015-08-06 22:15             ` Eric Sunshine
@ 2015-08-12  4:16               ` Paul Tan
  0 siblings, 0 replies; 26+ messages in thread
From: Paul Tan @ 2015-08-12  4:16 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: Git List, Junio C Hamano, Johannes Schindelin, Stefan Beller,
	Remi Lespinet, Jeff King, Jonathan Nieder

On Fri, Aug 7, 2015 at 6:15 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:
> An alternative would be to have git-am detect that it is being tested
> and pretend that isatty() returns true.

I would vastly prefer a solution that would work for everything, for
all the C code and scripts, instead of implementing a workaround in
git-am :(

In this case, I implemented a generic solution in test-terminal.perl
that works for POSIX systems, so if there are no problems with its
implementation, I do think it's better. Other than the fact that it
does not work on non-Unix platforms, of course.

The other approach I would consider is to implement a xisatty()
function that returns true for xisatty(0) if TEST_TTY=0 or something.

However, I do wonder if this would lead us to have to hack around
other functions of terminals as well (e.g. if xisatty(0),
tcgetattr()), which would be a big can of worms I think...

> There is some precedent for
> having core functionality recognize that it is being tested. See, for
> instance, environment variable TEST_DATE_NOW,

(Hmm, I took a look, and it seems that TEST_DATE_NOW is only checked
in test-date.c...)

> and rev-list --test-bitmap.
> Doing so would allow the tests work on non-Unix
> platforms, as well.

Ehh, if the non-Unix platforms do not implement terminals, it means
that the git-am logic to detect if we are attempting to feed it a
patch by checking if stdin is a TTY is invalid anyway, so implementing
a "yeah-it-is-a-tty" workaround for the sake of tests would be hiding
the problem, I think.

Thanks,
Paul

^ permalink raw reply	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2015-08-12  4:16 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-07-24 17:48 "git am" and then "git am -3" regression? Junio C Hamano
2015-07-24 18:09 ` Jeff King
2015-07-26  5:03   ` Paul Tan
2015-07-26  5:21     ` Jeff King
2015-07-27  8:09       ` Matthieu Moy
2015-07-27  8:32         ` Jeff King
2015-07-27 14:21     ` Junio C Hamano
2015-07-28 16:43       ` [PATCH] am: let command-line options override saved options Paul Tan
2015-07-28 16:48         ` Junio C Hamano
2015-07-28 17:09         ` Junio C Hamano
2015-07-31 10:58           ` Paul Tan
2015-07-31 16:04             ` Junio C Hamano
2015-08-01  0:59               ` Paul Tan
2015-08-04 14:05         ` [PATCH v2 0/3] " Paul Tan
2015-08-04 21:12           ` Junio C Hamano
2015-08-04 14:08         ` Paul Tan
2015-08-04 14:08           ` [PATCH v2 1/3] test_terminal: redirect child process' stdin to a pty Paul Tan
2015-08-06 22:15             ` Eric Sunshine
2015-08-12  4:16               ` Paul Tan
2015-08-04 14:08           ` [PATCH v2 2/3] am: let command-line options override saved options Paul Tan
2015-08-04 14:08           ` [PATCH v2 3/3] am: let --signoff override --no-signoff Paul Tan
2015-08-07  9:29             ` Johannes Schindelin
2015-08-12  3:06               ` Paul Tan
2015-08-12  3:07                 ` Paul Tan
2015-08-05 15:41           ` [PATCH v2 0/3] am: let command-line options override saved options Junio C Hamano
2015-08-05 17:51             ` Paul Tan

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

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 read-only IMAP folder(s) and NNTP newsgroup(s).