19

Can git commit empty versions of some files? The case in point is that I need new (untracked), non-empty files to first be added and committed as empty files, so as to mark their contents as being new and to be reviewed (the full, untracked file should not be added to the index; git diff should show the newly added contents by comparing the file to its committed empty version).

There is git add -N file…, which puts file with an empty content in the index, but this only says that file will be added, and git commit complains that the file has not been added. The thing is that the current, non-empty version is not what has to be added, but only an empty version of the new file.

Is there a way to do this?

PS: This question is asked in the context of a program that automatically adds files to a git repository (my program follows what code students write). Uncommitted code is code that I have yet to approve. Thus, the state in which a program created by a student starts should be the empty state, even though my program just found a new, non-empty program in their home directory; this is handled by automatically committing a new, empty version of any new student program file in a git repository. Thus, new code lines that they write appear as being newly added contents, compared to the last committed git revision.

Eric O. Lebigot
  • 91,433
  • 48
  • 218
  • 260
  • 1
    I honestly don't understand your problem. `touch empty-file && git add empty-file && git commit` works for me. – joschi Nov 20 '10 at 10:09
  • `git diff` works perfectly fine for a newly created file. If you diff a state when the file didn't exist with a diff when it has content, you will see all lines added, the exact same diff as diffing against an empty file. (Only the modelines are different.) – Cascabel Nov 20 '10 at 15:38
  • 1
    @joschi: The problem is that I have many new, *non-empty* files. Using Sven's approach #1 is more cumbersome that using his neat git-plumbing approach. – Eric O. Lebigot Nov 21 '10 at 08:00
  • @Jefromi: The point is that there should not be any "state"/version where the file "has content" (only a version where the file is empty). New, non-empty files should thus *not* be committed, because this is a way for me, as a teacher, to mark student code as not having yet been approved. – Eric O. Lebigot Nov 21 '10 at 08:03
  • @EOL: But then, until approval, the code is untracked! Scary! You could use committing to mark submission of the code, then mark approval by amending with a signed-off-by-line, or commit it to a "submitted" branch, then cherry-pick or merge it to an "approved" branch... – Cascabel Nov 21 '10 at 13:31
  • @Jefromi: Untracked code is not a problem at all, when I follow what students in my class do. I have no use for the history of their progress--I don't see anything scary with that. I only need to quickly scan what each student has been adding on top of what I have approved of their code. Using `git add -p`, I can easily mark what lines do not require my attention anymore. I don't see how cherry-picking commits could help, since approved code can only be added through `git add -p` and granular commits. Maybe I'm missing your point completely? :) – Eric O. Lebigot Nov 21 '10 at 20:36
  • Hm, I'm just frightened by the idea of anything potentially important being outside of version control. But if it really doesn't matter, then I guess it's all good! – Cascabel Nov 21 '10 at 23:52
  • @Jefromi: I'd be afraid to. :) Students are still free to use version control for their own code if they want to. Version control software is versatile enough to do other things than version control, and that's why I use it for marking what parts of the student code I should discuss with them. – Eric O. Lebigot Nov 22 '10 at 13:43
  • Note: with Git 2.5 (Q2 2015), git commit will no longer complain about a new file "to be added later": see http://stackoverflow.com/a/30341632/6309 – VonC May 20 '15 at 06:30
  • I find this useful for when you need to stage a new file line-by-line – minexew Apr 11 '20 at 12:37

2 Answers2

37

To be honest, I do not really understand what this is useful for. I would try to fix the review process instead of messing up the history. But if you really want to do this, here are several ways how:

  1. The pragmatic approach:

    mv file out-of-way
    touch file
    git add file
    mv out-of-way file
    
  2. The porcelain approach:

    git add -N file
    git add -p file
    

    ... and just answer "no" when asked whether the single hunk should be added. (Apparently this does not work anymore in 2019.)

  3. The plumbing approach:

    First, make sure an empty object exists in the object database:

    git hash-object -w --stdin < /dev/null
    

    This will return the SHA1 of an empty blob (which is e69de29bb2d1d6434b8b29ae775ad8c2e48c5391). You have to create this object only once. Now you can create empty files in the index by

    git update-index --add --cacheinfo 0644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 file
    
Sven Marnach
  • 574,206
  • 118
  • 941
  • 841
  • 1
    @Sven: Thank you so much! The plumbing approach is perfect for me: its is easily automatized, and to the point (the second guessing of why I would need this is not so relevant, though :) ). This is useful for following what new code my students add to their home directory by using `git diff` on my local copies of their programs. Code that I have not yet approved should not be committed, but keep appearing as newly added lines (compared to an empty file) as long as it is not committed (i.e. approved). – Eric O. Lebigot Nov 21 '10 at 07:57
  • @EOL: You could also easily automate touch, add, *then* copy. – Cascabel Nov 21 '10 at 14:07
  • @EOL: Sorry for sounding unkind -- just wanted to point out that I do not recommend to actually do what I explained in this answer. I think the approaches Jefromi suggests in the comments to your question provide more flexible (and more reliable) workflows. – Sven Marnach Nov 21 '10 at 17:51
  • @Sven: Thank you for your nice, soothing words. :) Jefromi's approach is in principle good, but I would have to use your version (i.e. your approach #1). I use rsync to locally copy the (remote) student files. Thus, new files appear as untracked files, and their contents is already copied in the local directory structure. Your approach #3 is perfect for my situation, and I used it in my "surveillance" program. – Eric O. Lebigot Nov 21 '10 at 20:41
  • 1
    @EOL: I was referring to the workflows Jefromi described in the comments to your *question*, e.g. have separate branches `commited` and `accepted`. This would be one way to "fix the review process" instead of "messing up the history". – Sven Marnach Nov 21 '10 at 22:19
  • @Sven: I see. I really have no need for the "committed" branch. :) If *they* want to use version control, it's up to them. I don't need version control per se, but only need to mark parts of their code as being correct. Thus, I only need the "accepted" branch,… which means that a single master branch is enough! :) – Eric O. Lebigot Nov 22 '10 at 14:12
  • 2
    The porcelain approach doesn't seem to work here: `git commit` says `file: not added yet error: Error building trees`, and a similar error from `git stash`. The plumbing approach does work. – p00ya Jun 22 '11 at 21:32
  • Re "why is this useful?", I'm rewriting a branch to make it easy to review, and I'd like to start with a "boilerplate" commit which adds new, empty files and includes them in the build process. Further commits add code to these files for new features. – Patrick Sanan Mar 06 '19 at 09:47
  • I'm also having problems with the porcelain way. When I add the file with `git add -N`, it shows up as a new file when I do `git status`. However, doing `git add -p` and selecting `no` seems to have no effect, and an empty file is not added to the index. – HelloGoodbye Oct 17 '19 at 12:50
  • @HelloGoodbye Apparently, git's behaviour in this corner case has changed in the nine years since I posted this answer, so I will remove the second approach – Sven Marnach Oct 17 '19 at 13:38
  • Ah. Seems like the porcelain broke. ;) – HelloGoodbye Oct 17 '19 at 21:38
-2

Automatically add all empty files and folders


Force add all files

$ git add -Af

You can automatically add a .gitignore file in every empty folder.

$ find $PATH_TO_REPOSITORY -type d ! -path "*.git*" -empty -exec cp .gitignore '{}'/ \;

You can automatically add a .gitkeep file in every empty folder.

$ find $PATH_TO_REPOSITORY -type d ! -path "*.git*" -empty -exec touch '{}'/.gitkeep \;
Nathan Weiler
  • 407
  • 4
  • 4
  • 1
    Hi Nathan. The question specifically asks about "non-empty" files. Are you sure this is not just a generic copy-paste answer? – minexew Apr 22 '20 at 12:22