58

To use git effectively (and as intended) I make small atomic commits, while I do have longer sessions where I do change not only one thing. Thus, I make heavy use of git add -p. This doesn't work for completely new files, though, because I tend to forget them later on.

What I want to do is, tell git that there is a new file, I want it to track, but not stage it:

Example: Running git status produces:

# On branch my-current-branch
# Your branch is ahead of 'origin/my-current-branch' by 2 commits.
#
# Changes to be committed:
#
<<STAGED SECTION>> // A
#
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
<<UNSTAGED-YET-KNOWN SECTION>> // B
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
<<UNKNOWN SECTION>> // C

If I have a file foo in the C section, and I say git add foo it will go to the A section. If I say git add -N foo it will go to both A and B. However, that would mean it would be included in the next commit, at least as the fact that there is a new file.

I want it to go in section B exclusively, such that I can later add it to A with git add -p or git add foo (or whatever).

Edit

Regarding the add -N solution, this doesn't work because if I try to commit after having said add -N and not having added it properly, git complains because it doesn't know how to handle empty files:

foo: not added yet
error: Error building trees
Community
  • 1
  • 1
bitmask
  • 32,434
  • 14
  • 99
  • 159
  • :8 I suggested you use -N, but you already mentioned that it doesn't work for you in the post! My suggestion, then, is to keep your untracked files section empty by staying on top of your gitignores, so anything new in it is immediately obvious. – Robert Jun 18 '12 at 16:42
  • @Robert: Yes, I actually have a bunch of gitignores, but I don't manage to keep the section entirely clean, there is always *some* garbage, and my eyes appear to have grown accustomed to simply not seeing that section. – bitmask Jun 18 '12 at 16:44
  • I don't think git has an option to do exactly what you're looking for... the -N option seems closest, but if you don't want to stage the creation (which should be harmless) I don't see another option than using the untracked files for this purpose. IMHO it's good practice to keep that section clean anyway - everything is either a source file or a build product – Robert Jun 18 '12 at 16:57
  • 1
    I wanted to suggest `git add foo` + `git reset HEAD foo`, but it turned out that `reset` moves a new file back to section C instead of section B as in the case of old files. Grrr... – Andras Nemeth May 09 '13 at 11:00
  • Note: Git 2.5 (Q2 2015) makes a `git add -N` a viable solution now: see [my answer below](http://stackoverflow.com/a/30341980/6309) – VonC May 20 '15 at 06:35

3 Answers3

45

With Git 2.5, git add -N/--intent-to-add is actually the right solution.
The new file won't be part of the next commit.

See commit d95d728 by Nguyễn Thái Ngọc Duy (pclouds) (merged in d0c692263):

diff-lib.c: adjust position of i-t-a entries in diff

Problem:

Entries added by "git add -N" are reminder for the user so that they don't forget to add them before committing. These entries appear in the index even though they are not real. Their presence in the index leads to a confusing "git status" like this:

On branch master
Changes to be committed:
        new file:   foo

Changes not staged for commit:
        modified:   foo

If you do a "git commit", "foo" will not be included even though "status" reports it as "to be committed".

Solution:

This patch changes the output to become

On branch master
Changes not staged for commit:
        new file:   foo

no changes added to commit

That means:

Treat such paths as "yet to be added to the index but Git already know about them"; "git diff HEAD" and "git diff --cached HEAD" should not talk about them, and "git diff" should show them as new. + files yet to be added to the index.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
3

Maybe you could try writing some pre-commit hook that alerts you if you have untracked files. This will require you to always keep your git directory clean to work, though (and obviously you'll need to keep a up-to-date .gitignore).

Also try git add -i which is similar to git add -p but also has an interface for adding new files.

asmeurer
  • 86,894
  • 26
  • 169
  • 240
  • `git add -p` implies `git add -i` but skips straight to option `5: patch`. `git add -i` will get you all the way there as long as you examine option `4: add untracked` every time you do `5: patch`. – Christopher Jun 18 '12 at 21:40
1

You could commit an empty file with that path before making your changes. If you've already written things there, move the file away, make a blank file, commit that, then add -p as normal and git commit --amend so you don't have an "Add blank file" commit.

Daenyth
  • 35,856
  • 13
  • 85
  • 124
  • 3
    I think if I use `add -N` it will already be committed as empty. However, the `--amend` solution means I will have to remember doing that. It's not as bad as forgetting a file altogether, but it means messing with previous commits, which I would like to avoid. At least this is a hack, not a clean solution. – bitmask Jun 18 '12 at 16:40
  • 1
    I don't see it as a hack. There's nothing wrong with using amend/rebase to clean *unpublished* history. – Daenyth Jun 18 '12 at 18:06
  • 1
    You could also alias some of this stuff to something like "git add-empty" or whatever so that there is a repeatable process but you don't have to remember it. – msouth Feb 20 '15 at 19:20