6

I want to commit a Python module’s __init__.py file, which, on my disk, already contains code. However, for the current commit, I wanted to add it empty, as this part of the code is yet to be tested. Thus, I used

$ git add -N __init__.py

The file is there in the output of git status, but if I issue git commit, all other files gets into the commit except __init__.py, which, in turn, remains in the index according to git status.

The man page of git-add says for -N that

Record only the fact that the path will be added later. An entry for the path is placed in the index with no content.

Is there a way to circumvent this will be added later part, i.e. add the file empty without temporarily deleting its content?

Edit: This happens with current (2.2.0) Git. With 1.7.1 and a small test repo, I get an error:

$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       new file:   b
#
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   b
#
$ git commit -m 'test'
b: not added yet
error: Error building trees
GergelyPolonkai
  • 6,230
  • 6
  • 35
  • 69
  • I believe you need to run git commit with ````-a```` when you use the ````-N```` flag on add. From the help: *This is useful for, among other things, showing the unstaged content of such files with git diff and committing them with git commit -a.* – Sander Toonen Jan 21 '15 at 11:44
  • That’s a no-go, because it will commit all other modified files, regardless if I added them with `git add` or not. Untracked files, however, will still remain untracked this way. – GergelyPolonkai Jan 21 '15 at 11:51
  • That's hilarious. When only using `git add -N` and then commiting you can create a completly empty commit. Just wanted to share that little gem. – Sascha Wolf Jan 21 '15 at 11:53
  • You can use `git add -p` after `git add -N` and simply decline adding the single diff hunk you are asked about. See [this answer](http://stackoverflow.com/a/4232334/279627) for more information. – Sven Marnach Jan 21 '15 at 11:56
  • @SvenMarnach I've actually tried that and at least in git 1.9.4 that won't solve the issue. – Sascha Wolf Jan 21 '15 at 11:58
  • @Zeeker: Fair enough -- it worked for me at the time I wrote the linked answer, which also provides alternative approaches of achieving the same thing. – Sven Marnach Jan 21 '15 at 12:01
  • @SvenMarnach thank you, my search-fu failed me to find that post, which makes my question somewhat a duplicate of that one. – GergelyPolonkai Jan 21 '15 at 12:29
  • possible duplicate of [Can git commit "empty versions" of new files?](http://stackoverflow.com/questions/4232171/can-git-commit-empty-versions-of-new-files) – GergelyPolonkai Jan 21 '15 at 12:30

1 Answers1

6

This should be fixed with Git 2.5 (Q2 2015), meaning git commit won't try to include the new file "intended to be added later".
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

In other words:

  • 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.

Update Q4 2016:

commit: fix empty commit creation when there's no changes but ita entries

(ita or i-t-a is "intent to add")

See commit 2c49f7f, commit 018ec3c, commit b42b451, commit 425a28e (24 Oct 2016) by Nguyễn Thái Ngọc Duy (pclouds).
(Merged by Junio C Hamano -- gitster -- in commit 6503602, 27 Oct 2016)

When new paths were added by "git add -N" to the index, it was enough to circumvent the check by "git commit" to refrain from making an empty commit without "--allow-empty".
The same logic prevented "git status" to show such a path as "new file" in the "Changes not staged for commit" section.

git diff man page now includes:

--ita-invisible-in-index:

By default entries added by "git add -N" appear as an existing empty file in "git diff" and a new file in "git diff --cached".
This option makes the entry appear as a new file in "git diff" and non-existent in "git diff --cached".

This option could be reverted with --ita-visible-in-index.

Both options are experimental and could be removed in future.


Update Q1 2018 (Git 2.16.x/2.17), git status improves again.
"git status", after moving a path in the working tree (hence making it appear "removed"), and then adding with the -N option (hence making that appear "added") detected it as a rename, but did not report the old and new pathnames correctly.

See commit 176ea74, commit 5134ccd, commit ea56f97, commit 98bc94e, commit 06dba2b, commit 6de5aaf (27 Dec 2017) by Nguyễn Thái Ngọc Duy (pclouds).
Helped-by: Igor Djordjevic (boogisha).
(Merged by Junio C Hamano -- gitster -- in commit bc3dca0, 23 Jan 2018)

Note: i-t-a or ita is "intended to add".

wt-status.c: handle worktree renames

Before 425a28e (diff-lib: allow ita entries treated as "not yet exist in index" - 2016-10-24, Git 2.11.0-rc0) there are never "new files" in the index, which essentially disables rename detection because we only detect renames when a new file appears in a diff pair.

After that commit, an i-t-a entry can appear as a new file in "git diff-files".
But the diff callback function in wt-status.c does not handle this case and produces incorrect status output.


Update Q4 2018 with Git 2.20, git status avoid displaying multiple renames on the same target.

See commit 3e73cc6 (27 Sep 2018) by Elijah Newren (newren).
(Merged by Junio C Hamano -- gitster -- in commit 98f3f00, 16 Oct 2018)

commit: fix erroneous BUG, 'multiple renames on the same target? how?'

builtin/commit.c:prepare_to_commit() can call run_status() twice if using the editor, including status, and the user attempts to record a non-merge empty commit without explicit --allow-empty.
If there is also a rename involved as well (due to using 'git add -N'), then a BUG in wt-status.c is triggered:

BUG: wt-status.c:476: multiple renames on the same target? how?

The reason we hit this bug is that both run_status() calls use the same struct wt_status * (named s), and s->change is not freed between runs. Changes are inserted into s with string_list_insert, which usually means that the second run just recomputes all the same results and overwrites what was computed the first time.

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