'git add --patch' to include new files?
Asked Answered
I

6

148

When I run git add -p, is there a way for git to select newly made files as hunks to select??

So if I make a new file called foo.java, then run git add -p, git will not let me choose that file's content to be added into the index.

Information answered 24/1, 2013 at 0:9 Comment(0)
S
125

To include every new files, you can run:

git add -N .
git add -p

If you want to use it frequently, you can create an alias in your ~/.bashrc:

alias gapan='git add --intent-to-add . && git add --patch'

N.B: If you use this with an empty new file, git will not be able to patch it and skip to the next one.

Shaftesbury answered 11/8, 2017 at 17:44 Comment(3)
For anyone who is wondering what git add -N does, it just adds the specified untracked files to the index, but without content.Achaean
-N, --intent-to-add: Record only the fact that the path will be added later. An entry for the path is placed in the index with no content. This is useful for, among other things, showing the unstaged content of such files with git diff and committing them with git commit -a.Wolfenbarger
Thank you! Another alternative is to add this as a git alias in ~/.gitconfigap = ! git add -N . && git add -p . You can then simply do git ap. This uses this trick to create an alias that calls multiple git commands.Shandra
S
144

When I tried git add -p someNewFile.txt on a new file (an untracked file), git would simply output No changes. and stop. I had to tell git that I intended to track the new file first.

git add -N someNewFile.txt
git add -p

However, since the file was untracked, it would show up as one giant hunk that couldn't be split (because it is all new!). So, then I needed to edit the hunk into smaller bits. If you're not familiar with that, checkout this reference to get started.

Update - Hunk editing info I wanted to update this in case the above reference goes away. Because the new file is untracked, git add -p will show every line in the file as a new line in one hunk. It will then ask you what you want to do with that hunk, giving you the following prompt:

Stage this hunk [y,n,q,a,d,/,e,?]?

Assuming that you do not want to commit the whole hunk (and thus, the whole file; because I am not sure why you would want to use git add -p in that case?), you will want to specify option e to tell git that you want to edit the hunk.

Once you tell git that you want to edit the hunk, it should drop you into your editor of choice so you can make your changes. All lines should be prefixed with a + and git has some explanatory comments (prefixed with a #) at the end of the file. Simply delete any lines that you do not want in your initial commit of the file. Then save and quit the editor.

Git's explanation of git's hunk options:

y - stage this hunk
n - do not stage this hunk
q - quit; do not stage this hunk or any of the remaining ones
a - stage this hunk and all later hunks in the file
d - do not stage this hunk or any of the later hunks in the file
g - select a hunk to go to
/ - search for a hunk matching the given regex
j - leave this hunk undecided, see next undecided hunk
J - leave this hunk undecided, see next hunk
k - leave this hunk undecided, see previous undecided hunk
K - leave this hunk undecided, see previous hunk
s - split the current hunk into smaller hunks
e - manually edit the current hunk
? - print help
Shellfish answered 31/7, 2013 at 20:38 Comment(6)
Please someone answer this in summary.Hospitaler
In summary, git add -N someNewFile.txt followed by git add -pShellfish
It seems like in new git version, the behaviour changed. It has no option to manually edit the current hunk.Drum
This doesn't seem to be working for me, when I accept all changes in git add -p filename (by typing y) it exits with nothing staged. When I try to edit with e I get "Sorry, cannot edit this hunk"Lavena
if i do git push after it says "Everything is up to date"Josefajosefina
This doesn't work for me. Note, i don't want to apply any filechanges, the commit should just contain a new empty file.Bayer
S
125

To include every new files, you can run:

git add -N .
git add -p

If you want to use it frequently, you can create an alias in your ~/.bashrc:

alias gapan='git add --intent-to-add . && git add --patch'

N.B: If you use this with an empty new file, git will not be able to patch it and skip to the next one.

Shaftesbury answered 11/8, 2017 at 17:44 Comment(3)
For anyone who is wondering what git add -N does, it just adds the specified untracked files to the index, but without content.Achaean
-N, --intent-to-add: Record only the fact that the path will be added later. An entry for the path is placed in the index with no content. This is useful for, among other things, showing the unstaged content of such files with git diff and committing them with git commit -a.Wolfenbarger
Thank you! Another alternative is to add this as a git alias in ~/.gitconfigap = ! git add -N . && git add -p . You can then simply do git ap. This uses this trick to create an alias that calls multiple git commands.Shandra
A
8

There's also a very similar approach making use of the --cached flag...

1) Turn your unstaged changes into staged, just like your added file.

git add edited-file.txt
git add new-file.txt
git add directory-of-changes/

2) Look at the diff (note: you can include both edits and new files).

git diff --cached

3) Create the patch.

git diff --cached > my_patch_file.patch
Anus answered 16/9, 2016 at 20:52 Comment(3)
Unfortunately that won't accomplish the same purpose. What I like about git add -p is that it does not add everything, but let's me pick and choose what I want to add. This solution would blindly add everything.Information
Well you can pick what you add! I'll update the answer.Anus
thank you :allthethings: this works amazingly for meNortherly
A
8

Catshoes's answer includes:

When I tried git add -p someNewFile.txt on a new file (an untracked file), git would simply output No changes. and stop.
I had to tell git that I intended to track the new file first.

git add -N someNewFile.txt
git add -p

That should change soon with Git 2.29 (Q4 2020).

Recent versions of "git diff-files"(man) shows a diff between the index and the working tree for "intent-to-add" paths as a "new file" patch;
"git apply --cached"(man) should be able to take "git diff-files" and should act as an equivalent to "git add" for the path, but the command failed to do so for such a path.

See commit 4c025c6, commit e3cc41b (08 Aug 2020), and commit 7cfde3f (06 Aug 2020) by Raymond E. Pasco (juped).
(Merged by Junio C Hamano -- gitster -- in commit ca81676, 17 Aug 2020)

apply: allow "new file" patches on i-t-a entries

Helped-by: Junio C Hamano
Signed-off-by: Raymond E. Pasco

diff-files recently changed to treat changes to paths marked "intent to add" in the index as new file diffs rather than diffs from the empty blob.

However, apply refuses to apply new file diffs on top of existing index entries, except in the case of renames.
This causes "git add -p"(man) , which uses apply, to fail when attempting to stage hunks from a file when intent to add has been recorded.

This changes the logic in check_to_create() which checks if an entry already exists in an index in two ways:

  • first, we only search for an index entry at all if ok_if_exists is false;
  • second, we check for the CE_INTENT_TO_ADD flag on any index entries we find and allow the apply to proceed if it is set.

And:

With Git 2.29 (Q4 2020), "add -p" now allows editing paths that were only added in intent.

See commit 75a009d (09 Sep 2020) by Phillip Wood (phillipwood).
(Merged by Junio C Hamano -- gitster -- in commit 458205f, 22 Sep 2020)

add -p: fix editing of intent-to-add paths

Signed-off-by: Phillip Wood
Reported-by: Thomas Sullivan
Reported-by: Yuchen Ying

A popular way of partially staging a new file is to run git add -N <path>(man) and then use the hunk editing of git add -p(man) to select the part of the file that the user wishes to stage.

Since 85953a3187 ("diff-files --raw: show correct post-image of intent-to-add files", 2020-07-01, Git v2.28.0-rc0 -- merge listed in batch #7) this has stopped working as intent-to-add paths are now show as new files rather than changes to an empty blob and git apply(man) refused to apply a creation patch for a path that was marked as intent-to-add. 7cfde3fa0f ("apply: allow "new file" patches on i-t-a entries", 2020-08-06) fixed the problem with apply but it still wasn't possible to edit the added hunk properly.

2c8bd8471a ("checkout -p: handle new files correctly", 2020-05-27, Git v2.28.0-rc0 -- merge listed in batch #2) had previously changed add -p to handle new files but it did not implement patch editing correctly.
The perl version simply forbade editing and the C version opened the editor with the full diff rather that just the hunk which meant that the user had to edit the hunk header manually to get it to work.

The root cause of the problem is that added files store the diff header with the hunk data rather than separating the two as we do for other changes. Changing added files to store the diff header separately fixes the editing problem at the expense of having to special case empty additions as they no longer have any hunks associated with them, only the diff header.

The changes move some existing code into a conditional changing the indentation, they are best viewed with --color-moved-ws=allow-indentation-change (or --ignore-space-change works well to get an overview of the changes)


A bit more clarity is added with Git 2.32 (Q2 2021):

See commit 7a14acd (27 Apr 2021) by Peter Oliver (mavit).
(Merged by Junio C Hamano -- gitster -- in commit e60e9cc, 07 May 2021)

doc: point to diff attribute in patch format docs

Signed-off-by: Peter Oliver

From the documentation for generating patch text with diff-related commands, refer to the documentation for the diff attribute.

This attribute influences the way that patches are generated, but this was previously not mentioned in e.g., the git-diff(man) manpage.

diff-generate-patch now includes in its man page:

  1. Hunk headers mention the name of the function to which the hunk applies. See "Defining a custom hunk-header" in gitattributes for details of how to tailor to this to specific languages.
Arched answered 26/8, 2020 at 21:18 Comment(3)
any update on this one? i'm using git version 2.28.0 and it doesn't work with git add -N + git add -p to manually edit hunksDrum
@Drum Not yet: 2.29 will be released in a few weeks.Arched
yeah! fixed now :)Bithia
D
7

git add -p is really about adding changes to already tracked files.

The command to interactively select files to add is git add -i. For example:

$ git add -i

*** Commands ***
  1: status   2: update   3: revert   4: add untracked
  5: patch    6: diff     7: quit     8: help
What now> a
  1: another-new.java
  2: new.java
Add untracked>> 2
  1: another-new.java
* 2: new.java
Add untracked>> 
added one path

*** Commands ***
  1: status   2: update   3: revert   4: add untracked
  5: patch    6: diff     7: quit     8: help
What now> q
Bye.
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   new.java

Untracked files:
  (use "git add <file>..." to include in what will be committed)

        another-new.java

(The real command has colors which I couldn't cut-and-paste here, so it's nicer than it seems)

Actually, the patch command of git add -i does the same as git add -p, so the second is a subset of the first (even though I admit I love add -p and hate add -i myself!).

Darryl answered 23/8, 2017 at 14:7 Comment(3)
" I admit I love add -p and hate add -i myself!" This is why git add then patch is a solution I love: It still allows you to check content of new files you are adding (since you compare them with their empty versions), and patch files you've edited!Shaftesbury
Please correct me if I'm wrong, but even here in interactive mode, the patch will still output No changes. on a new file. The OP was asking how to add hunks from a new file, not the whole file. I believe --intent-to-add is still required here.Webb
add -p alone won't work, but this answer suggests add -i, which does.Darryl
G
-4

You can do this in a single line using git add --intent-to-add -p . The behavior is the same, but avoiding repetition.

Gaea answered 2/8, 2021 at 18:20 Comment(1)
This does not work unfortunately (git version 2.32.0 (Apple Git-132))Shaftesbury

© 2022 - 2024 — McMap. All rights reserved.