threads / discuss / 44013

git commit -p with file arguments

Subject: git commit -p with file arguments

## tl;dr

16 messages between Sep 5, 2016 and Oct 5, 2016.

replies: 15people: 5as markdown or json

Christian Neukirchen· Sep 5, 2016, 21:08 UTC · lore
Hi,
I noticed the following suprising behavior:

% git --version git version 2.10.0

% git add bar
% git status -s 
A  bar
 M foo

% git commit -p foo [stage a hunk] ... # Explicit paths specified without -i or -o; assuming --only paths... # On branch master # Changes to be committed: # new file: bar # modified: foo #

So why does it want to commit bar too, when I explicitly wanted to commit foo only?

This is not how "git commit files..." works, and the man page says
            3.by listing files as arguments to the commit command, in which
           case the commit will ignore changes staged in the index, and
           instead record the current content of the listed files (which must
           already be known to Git);

I'd expect "git commit -p files..." to work like "git add -p files... && git commit files...".

Thanks,
-- 
Christian Neukirchen  <chneukirchen@gmail.com>  http://chneukirchen.org
Duy Nguyen· Sep 9, 2016, 10:54 UTC · re: Christian Neukirchen · lore

Re: git commit -p with file arguments

On Tue, Sep 6, 2016 at 4:08 AM, Christian Neukirchen <chneukirchen@gmail.com> wrote:

Show 34 quoted lines
> Hi,
>
> I noticed the following suprising behavior:
>
> % git --version
> git version 2.10.0
>
> % git add bar
> % git status -s
> A  bar
>  M foo
>
> % git commit -p foo
> [stage a hunk]
> ...
> # Explicit paths specified without -i or -o; assuming --only paths...
> # On branch master
> # Changes to be committed:
> #       new file:   bar
> #       modified:   foo
> #
>
> So why does it want to commit bar too, when I explicitly wanted to
> commit foo only?
>
> This is not how "git commit files..." works, and the man page says
>
>             3.by listing files as arguments to the commit command, in which
>            case the commit will ignore changes staged in the index, and
>            instead record the current content of the listed files (which must
>            already be known to Git);
>
> I'd expect "git commit -p files..." to work like
> "git add -p files... && git commit files...".

The paths after '-p' could mean two things, either as a filter (e.g. like in "git add -p") to help save your time going through all changed files, or as "git commit files...". I think the paths were meant to be filter when '-p' was added. There's a separate bullet point git-commit man page, number 5, in about --patch, so that paragraph you quoted is probably _not_ about --patch. Either way changing its behavior now might surprise users used to it.

At the least I think we should clarify this in the document. Maybe we could add --patch-only as well, which commits just what you select in --patch mode, ignoring anything in existing index.

-- 
Duy
Duy Nguyen· Oct 5, 2016, 10:26 UTC · re: Duy Nguyen · lore

Re: git commit -p with file arguments

On Fri, Sep 09, 2016 at 05:54:30PM +0700, Duy Nguyen wrote:
Show 40 quoted lines
> On Tue, Sep 6, 2016 at 4:08 AM, Christian Neukirchen
> <chneukirchen@gmail.com> wrote:
> > Hi,
> >
> > I noticed the following suprising behavior:
> >
> > % git --version
> > git version 2.10.0
> >
> > % git add bar
> > % git status -s
> > A  bar
> >  M foo
> >
> > % git commit -p foo
> > [stage a hunk]
> > ...
> > # Explicit paths specified without -i or -o; assuming --only paths...
> > # On branch master
> > # Changes to be committed:
> > #       new file:   bar
> > #       modified:   foo
> > #
> >
> > So why does it want to commit bar too, when I explicitly wanted to
> > commit foo only?
> >
> > This is not how "git commit files..." works, and the man page says
> >
> >             3.by listing files as arguments to the commit command, in which
> >            case the commit will ignore changes staged in the index, and
> >            instead record the current content of the listed files (which must
> >            already be known to Git);
> >
> > I'd expect "git commit -p files..." to work like
> > "git add -p files... && git commit files...".
> 
> ...
> 
> At the least I think we should clarify this in the document.
How about something like this? Would it help?
-- 8< --
Subject: [PATCH] git-commit.txt: clarify --patch mode with pathspec

How pathspec is used, with and without --interactive/--patch, is different. But this is not clear from the document. These changes hint the user to keep reading (to option #5) instead of stopping at #2 and assuming --patch/--interactive behaves the same way.

And since all the options listed here always mention how the index is involved (or not) in the final commit, add that bit for #5 as well. This "on top of the index" is implied when you head over git-add(1), but if you just go straight to the "Interactive mode" and not read what git-add is for, you may miss it.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/git-commit.txt | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt
index b0a294d..f2ab0ee 100644
--- a/Documentation/git-commit.txt
+++ b/Documentation/git-commit.txt
@@ -29,7 +29,8 @@ The content to be added can be specified in several ways:
 2. by using 'git rm' to remove files from the working tree
    and the index, again before using the 'commit' command;
 
-3. by listing files as arguments to the 'commit' command, in which
+3. by listing files as arguments to the 'commit' command
+   (without --interactive or --patch switch), in which
    case the commit will ignore changes staged in the index, and instead
    record the current content of the listed files (which must already
    be known to Git);
@@ -41,7 +42,8 @@ The content to be added can be specified in several ways:
    actual commit;
 
 5. by using the --interactive or --patch switches with the 'commit' command
-   to decide one by one which files or hunks should be part of the commit,
+   to decide one by one which files or hunks should be part of the commit
+   in addition to contents in the index,
    before finalizing the operation. See the ``Interactive Mode'' section of
    linkgit:git-add[1] to learn how to operate these modes.
 
-- 
2.8.2.524.g6ff3d78

-- 8< --
Duy
Christian Neukirchen· Oct 5, 2016, 11:38 UTC · re: Duy Nguyen · lore

Re: git commit -p with file arguments

Duy Nguyen <pclouds@gmail.com> writes:
>> At the least I think we should clarify this in the document.
>
> How about something like this? Would it help?
I think it captures the current behavior well.
-- 
Christian Neukirchen  <chneukirchen@gmail.com>  http://chneukirchen.org
Junio C Hamano· Oct 5, 2016, 17:16 UTC · re: Duy Nguyen · lore

Re: git commit -p with file arguments

Duy Nguyen <pclouds@gmail.com> writes:
Show 20 quoted lines
>> At the least I think we should clarify this in the document.
>
> How about something like this? Would it help?
>
> -- 8< --
> Subject: [PATCH] git-commit.txt: clarify --patch mode with pathspec
>
> How pathspec is used, with and without --interactive/--patch, is
> different. But this is not clear from the document. These changes hint
> the user to keep reading (to option #5) instead of stopping at #2 and
> assuming --patch/--interactive behaves the same way.
>
> And since all the options listed here always mention how the index is
> involved (or not) in the final commit, add that bit for #5 as well. This
> "on top of the index" is implied when you head over git-add(1), but if
> you just go straight to the "Interactive mode" and not read what git-add
> is for, you may miss it.
>
> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
> ---
Excellent.  
Show 26 quoted lines
>  Documentation/git-commit.txt | 6 ++++--
>  1 file changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt
> index b0a294d..f2ab0ee 100644
> --- a/Documentation/git-commit.txt
> +++ b/Documentation/git-commit.txt
> @@ -29,7 +29,8 @@ The content to be added can be specified in several ways:
>  2. by using 'git rm' to remove files from the working tree
>     and the index, again before using the 'commit' command;
>  
> -3. by listing files as arguments to the 'commit' command, in which
> +3. by listing files as arguments to the 'commit' command
> +   (without --interactive or --patch switch), in which
>     case the commit will ignore changes staged in the index, and instead
>     record the current content of the listed files (which must already
>     be known to Git);
> @@ -41,7 +42,8 @@ The content to be added can be specified in several ways:
>     actual commit;
>  
>  5. by using the --interactive or --patch switches with the 'commit' command
> -   to decide one by one which files or hunks should be part of the commit,
> +   to decide one by one which files or hunks should be part of the commit
> +   in addition to contents in the index,
>     before finalizing the operation. See the ``Interactive Mode'' section of
>     linkgit:git-add[1] to learn how to operate these modes.

When re-reading these 5 bullet points, I feel there may be some unrelated updates needed to clarify (e.g. it is unclear when reading the description pretending to be a newbie, if it is the "changes" that is recorded in the index, or if it is the "state"; the answer is the latter but if the reader's world model is still the former, the description can mislead to expect a different behaviour).

But regardless of such remaining potential issues, this is a clearly good change. Thanks.

Jacob Keller· Sep 9, 2016, 16:57 UTC · re: Christian Neukirchen · lore

Re: git commit -p with file arguments

On Mon, Sep 5, 2016 at 2:08 PM, Christian Neukirchen <chneukirchen@gmail.com> wrote:

Show 24 quoted lines
> Hi,
>
> I noticed the following suprising behavior:
>
> % git --version
> git version 2.10.0
>
> % git add bar
> % git status -s
> A  bar
>  M foo
>
> % git commit -p foo
> [stage a hunk]
> ...
> # Explicit paths specified without -i or -o; assuming --only paths...
> # On branch master
> # Changes to be committed:
> #       new file:   bar
> #       modified:   foo
> #
>
> So why does it want to commit bar too, when I explicitly wanted to
> commit foo only?
It wants to commit bar too because you already added bar before. It works like:
"git add bar && git add -p foo && git commit" does it not?

I fail to see why "git commit -p <path>" would unstage the bar you already added? Or am I missing some assumption here?

Thanks, Jake

Show 11 quoted lines
>
> This is not how "git commit files..." works, and the man page says
>
>             3.by listing files as arguments to the commit command, in which
>            case the commit will ignore changes staged in the index, and
>            instead record the current content of the listed files (which must
>            already be known to Git);
>
> I'd expect "git commit -p files..." to work like
> "git add -p files... && git commit files...".
>

I guess the part about "git commit files" is different from "git commit -p files", which is confusing.

> Thanks,
> --
> Christian Neukirchen  <chneukirchen@gmail.com>  http://chneukirchen.org
>
Christian Neukirchen· Sep 9, 2016, 17:05 UTC · re: Jacob Keller · lore

Re: git commit -p with file arguments

Jacob Keller <jacob.keller@gmail.com> writes:
Show 6 quoted lines
> It wants to commit bar too because you already added bar before. It works like:
>
> "git add bar && git add -p foo && git commit" does it not?
>
> I fail to see why "git commit -p <path>" would unstage the bar you
> already added? Or am I missing some assumption here?

Yet the commit message comment says: # Explicit paths specified without -i or -o; assuming --only paths...

But files are committed which were not given on the command line.

My confusion is that I use "git commit" with explicit files, yet other files are committed. AFAICS, this only happens with -p.

-- 
Christian Neukirchen  <chneukirchen@gmail.com>  http://chneukirchen.org
Junio C Hamano· Sep 9, 2016, 18:03 UTC · re: Jacob Keller · lore

Re: git commit -p with file arguments

Jacob Keller <jacob.keller@gmail.com> writes:
Show 6 quoted lines
> It wants to commit bar too because you already added bar before. It works like:
>
> "git add bar && git add -p foo && git commit" does it not?
>
> I fail to see why "git commit -p <path>" would unstage the bar you
> already added? Or am I missing some assumption here?
Yes.

"git commit -p <pathspec>" were added originally for lazy people who do not want to type "git add -p <pathspec> && git commit", which matches your expectation. If you already added "bar" that is outside of the <pathspec> given to "add -p", the final "git commit" step would record the latest contents of "bar" in it.

For obvious reasons, "git commit -p <pathspec>" cannot be a short-hand to "git add -p <pathspec> && git commit <pathspec>", so the current behaviour was the best they could do for those who aded "commit -p", I guess.

Jakub Narębski· Sep 9, 2016, 20:39 UTC · re: Junio C Hamano · lore

Re: git commit -p with file arguments

W dniu 09.09.2016 o 20:03, Junio C Hamano pisze:
Show 21 quoted lines
> Jacob Keller <jacob.keller@gmail.com> writes:
> 
>> It wants to commit bar too because you already added bar before. It works like:
>>
>> "git add bar && git add -p foo && git commit" does it not?
>>
>> I fail to see why "git commit -p <path>" would unstage the bar you
>> already added? Or am I missing some assumption here?
> 
> Yes.
> 
> "git commit -p <pathspec>" were added originally for lazy people who
> do not want to type "git add -p <pathspec> && git commit", which
> matches your expectation.  If you already added "bar" that is
> outside of the <pathspec> given to "add -p", the final "git commit"
> step would record the latest contents of "bar" in it.
> 
> For obvious reasons, "git commit -p <pathspec>" cannot be a
> short-hand to "git add -p <pathspec> && git commit <pathspec>", so
> the current behaviour was the best they could do for those who aded
> "commit -p", I guess.
The 'obvious reasons' are that 
  $ git add -p <pathspec> && git commit <pathspec>

would not work as intended, that is it wouldn't create commit out of HEAD and changes to <pathspec> created interactively in the index. "git commit <pathspec>" is a shortcut to "git commit --only <pathspec>"; the git-commit(1) manpage explains (emphasis mine):

 -o
 --only
    Make a commit by taking the updated *working tree contents* of
    the paths specified on the command line, disregarding any contents
    that have been staged for other paths. [...]

Which means that with "git add -p <pathspec> && git commit <pathspec>", the "git add -p <pathspec>" would carefully craft the <pathspec> state in the index... and "git commit <pathspec>" would take worktree version of <pathspec> for commit, ignoring what was in the index :-(

Currently there is no way to create commit out of subset of the index, e.g. with "git commit :0:<path>"

Best,
-- 
Jakub Narębski
Christian Neukirchen· Sep 9, 2016, 20:52 UTC · re: Jakub Narębski · lore

Re: git commit -p with file arguments

Jakub Narębski <jnareb@gmail.com> writes:
Show 7 quoted lines
> Which means that with "git add -p <pathspec> && git commit <pathspec>",
> the "git add -p <pathspec>" would carefully craft the <pathspec> state
> in the index... and "git commit <pathspec>" would take worktree version
> of <pathspec> for commit, ignoring what was in the index :-(
>
> Currently there is no way to create commit out of subset of the index,
> e.g. with "git commit :0:<path>"

I played around with creating a new index just for "add -p" and then committing that one. Seems to have worked...

Perhaps I'll just wrap git-commit myself then.
cu,
-- 
Christian Neukirchen  <chneukirchen@gmail.com>  http://chneukirchen.org
Jakub Narębski· Sep 10, 2016, 09:52 UTC · re: Christian Neukirchen · lore

Re: git commit -p with file arguments

W dniu 09.09.2016 o 22:52, Christian Neukirchen napisał:
Show 14 quoted lines
> Jakub Narębski <jnareb@gmail.com> writes:
> 
>> Which means that with "git add -p <pathspec> && git commit <pathspec>",
>> the "git add -p <pathspec>" would carefully craft the <pathspec> state
>> in the index... and "git commit <pathspec>" would take worktree version
>> of <pathspec> for commit, ignoring what was in the index :-(
>>
>> Currently there is no way to create commit out of subset of the index,
>> e.g. with "git commit :0:<path>"
> 
> I played around with creating a new index just for "add -p" and then
> committing that one.  Seems to have worked...
> 
> Perhaps I'll just wrap git-commit myself then.

What I wanted to say is that there is no built-in way to create commit out of subset of the index. You can of course do what "git commit <file>" does, that is use temporary index file (GIT_INDEX_FILE etc.; see contrib/examples/git-commit.sh).

I wonder, if git-commit is to acquire such feature, what would be the best interface. "git commit :0:./<path>"? "git commit -o -p <path>" (that is, "git commit --only --patch <pathspec>")?

-- 
Jakub Narębski
Junio C Hamano· Sep 11, 2016, 21:50 UTC · re: Jakub Narębski · lore

Re: git commit -p with file arguments

Jakub Narębski <jnareb@gmail.com> writes:
> I wonder, if git-commit is to acquire such feature, what would be the
> best interface.  "git commit :0:./<path>"?  "git commit -o -p <path>"
> (that is, "git commit --only --patch <pathspec>")?

Just do "git reset && git commit -p <pathspec>", I would say. Anything more elaborate would just confuse the end users.

Jacob Keller· Sep 11, 2016, 22:05 UTC · re: Junio C Hamano · lore

Re: git commit -p with file arguments

On Sun, Sep 11, 2016 at 2:50 PM, Junio C Hamano <gitster@pobox.com> wrote:
Show 9 quoted lines
> Jakub Narębski <jnareb@gmail.com> writes:
>
>> I wonder, if git-commit is to acquire such feature, what would be the
>> best interface.  "git commit :0:./<path>"?  "git commit -o -p <path>"
>> (that is, "git commit --only --patch <pathspec>")?
>
> Just do "git reset && git commit -p <pathspec>", I would say.
> Anything more elaborate would just confuse the end users.
>

Yes, I'm actually confused by "git commit <files>" *not* usinng what's in the index already, so I think that isn't intuitive as is.

Thanks, Jake

Junio C Hamano· Sep 12, 2016, 01:57 UTC · re: Jacob Keller · lore

Re: git commit -p with file arguments

Jacob Keller <jacob.keller@gmail.com> writes:
> Yes, I'm actually confused by "git commit <files>" *not* usinng what's
> in the index already, so I think that isn't intuitive as is.
You are excused ;-)

In ancient days, "git commit <pathspec>" was to add the contents from working tree files that match <pathspec> to what is already in the index and create a commit from that state. This ran against the intuition of many users who knew older systems (e.g. cvs) and we had to migrate it to the current behaviour by breaking backward compatibility.

Jacob Keller· Sep 12, 2016, 04:56 UTC · re: Junio C Hamano · lore

Re: git commit -p with file arguments

On Sun, Sep 11, 2016 at 6:57 PM, Junio C Hamano <gitster@pobox.com> wrote:
Show 9 quoted lines
>
> You are excused ;-)
>
> In ancient days, "git commit <pathspec>" was to add the contents
> from working tree files that match <pathspec> to what is already in
> the index and create a commit from that state.  This ran against the
> intuition of many users who knew older systems (e.g. cvs) and we had
> to migrate it to the current behaviour by breaking backward
> compatibility.
I see.

Thanks, Jake

Jakub Narębski· Sep 12, 2016, 21:14 UTC · re: Junio C Hamano · lore

Re: git commit -p with file arguments

W dniu 12.09.2016 o 03:57, Junio C Hamano pisze:
Show 10 quoted lines
> Jacob Keller <jacob.keller@gmail.com> writes:
> 
>> Yes, I'm actually confused by "git commit <files>" *not* usinng what's
>> in the index already, so I think that isn't intuitive as is.
> 
> You are excused ;-)
> 
> In ancient days, "git commit <pathspec>" was to add the contents
> from working tree files that match <pathspec> to what is already in
> the index and create a commit from that state.

That is, "git commit <pathspec>" meant --include, being equivalent to "git commit --include <pathspec>".

>                                               This ran against the
> intuition of many users who knew older systems (e.g. cvs) and we had
> to migrate it to the current behaviour by breaking backward
> compatibility.

That is, "git commit <pathspec>" means --only, being equivalent to "git commit --only <pathspec>".

But it was always about working tree version of <pathspec>.
And of course older version control systems didn't have the index...
-- 
Jakub Narębski

← back to recent threads