How to stage only part of a new file with git?

Git

Git Problem Overview


I love git add --interactive. It is now part of my daily workflow.

The problem seems that it does not work with untracked files. What I want to do is track a new file, but only add part of it, i.e. some parts of this new file are not yet ready to be staged.

For example, with git add -i, I can chose the patch option and even edit individual hunks in order to stage parts of the new code, leaving debug code comments unstaged. I love working this way because it makes it obvious which places of the mega patch I am currently working on still need work.

Unfortunately, I don't seem to be able to do the same with an untracked file. Either I stage the whole file, or nothing. The workaround I have been using is staging or even committing a new file when it is empty, and then staging individual changes in the usual way. But this solution feels like a dirty hack and when I forget, or change my mind, it creates more troubles than there should be.

So the question is: How to stage only part of a new file, so that this new file gets tracked but leaving the whole or parts of its content unstaged?

Git Solutions


Solution 1 - Git

Whoa, all that update-index and hash-object business seems overly complicated. How about this instead:

git add -N new_file
git add -i  # or 'git add -p' if you prefer

From git help add:

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

Solution 2 - Git

git update-index --add --cacheinfo 100644 $(git hash-object -w /dev/null) newfile
git add --interactive newfile

Simple demo:

mkdir /tmp/demo
cd /tmp/demo
git init .

echo hello > newfile
git update-index --add --cacheinfo 100644 $(git hash-object -w /dev/null) newfile
  • Hint If you're sure the 'empty' blob already exists in your git object database, you could hardcode the hash e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 instead. I don't recommend doing that_
  • Hint If you're on Windows, you probably can just use NUL: instead of /dev/null. Otherwise, use something like echo -n '' | git hash-object --stdin -w

Now the index will contain newfile as the empty blob, and the empty blob has been entered into the object database if it didn't exist yet:

$ find .git/objects/ -type f 
.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391

$ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#	new file:   newfile
#
# 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:   newfile
#

$ git diff
diff --git a/newfile b/newfile
index e69de29..ce01362 100644
--- a/newfile
+++ b/newfile
@@ -0,0 +1 @@
+hello

This should be precisely what you want. May I also recommend the vim fugitive plugin for very intelligent index management (see https://stackoverflow.com/questions/5851461/better-git-add-p/5851626#5851626)

Solution 3 - Git

The easiest way to do this (and imho interactive staging in general) is git gui. It comes bundled with git and should work on almost all platforms that are supported by git.

Simply run git gui and a gui will open that allows staging and unstaging hunks and even single lines of tracked and untracked files.

Git Gui screenshot

Solution 4 - Git

Edit: this doesn't seem to be working now. I'm sure it was before (on git 1.7.1). In case it doesn't work, I suggest staging /dev/null as sehe suggests above:

git update-index --add --cacheinfo 100644 $(git hash-object -w /dev/null) newfile

If you're on Windows (without /dev/null) then you can replace it with the path to an empty file.

Original answer

You want

git add -p # (or --patch)

This adds untracked files for me. From the man page:

> Interactively choose hunks of patch > between the index and the work tree > and add them to the index. This gives > the user a chance to review the > difference before adding modified > contents to the index. > > This effectively runs add > --interactive, but bypasses the initial command menu and directly > jumps to the patch subcommand. See > “Interactive mode” for details.

Solution 5 - Git

Just for the record of another possibility: I use

git add -N file
git add -p file

And then you can stage hunks, or edit them in place.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionaugustinView Question on Stackoverflow
Solution 1 - GitRichard HansenView Answer on Stackoverflow
Solution 2 - GitseheView Answer on Stackoverflow
Solution 3 - GitChronialView Answer on Stackoverflow
Solution 4 - Gitdave1010View Answer on Stackoverflow
Solution 5 - GitPedro Adame VergaraView Answer on Stackoverflow