4

Suppose I have altered a file which was versioned and renamed it using something other then GIT, but I only want to include some diffs from that file? How would I do that?

The problem is that GIT can only add complete new files.

The scenario is probably better understood by example:

$ mkdir temp
$ cd temp
$ git init
$ nano 1.txt
$ cat 1.txt
I am file 1.txt
2
3
4
5

$ git add 1.txt
$ git commit -m "1st commit"
$ #edit some stuff and rename using something else than git
$ cat 2.txt #note, 1.txt is renamed to 2.txt
1 I am file 1.txt
2 I am now file 2.txt
3
4
5
6

$ #note the line with '6 'is added

What are my options now, to commit only the rename and the line change of "2" to "2 I am now file 2.txt" but not the addition of the line with '6'.

Externally renaming back and using git mv is not really a solution in my case, because of the many renames possible by the refactoring in an IDE.

basically, I want to get in the situation you'd normally get by having done git mv 1.txt 2.txt, in that case you could interactively select which lines in 2.txt you'd want to stage.

hbogert
  • 4,198
  • 5
  • 24
  • 38
  • What is the final name that you would want to have for the file ? – Math Jun 11 '14 at 12:41
  • As the (contrived) example shows, 2.txt, but it does not really matter for the problem itself. – hbogert Jun 11 '14 at 12:55
  • In fact, doing `mv 2.txt 1.txt` (not `git mv`, just `mv`) would solve the problem since git tracks the name of the file. – Math Jun 11 '14 at 13:02
  • doing `rm 1.txt` alone can also have the effect you expect as git will detect `2.txt` as being `1.txt` if they are similar enough : http://stackoverflow.com/questions/433111/how-to-make-git-mark-a-deleted-and-a-new-file-as-a-file-move/433142#433142 – Math Jun 11 '14 at 15:16
  • I would think you could achieve this with `git mv --cached oldfile newfile`. Unfortunately, `--cached` doesn't work with `git mv` (only `git rm`). – Ajedi32 Jun 11 '14 at 21:23

2 Answers2

3

The git add command has the nifty -N flag:

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

Needless to say, this flag also works with git add -p.


There is no need to use git mv. As correctly pointed out by @Ajedi32 below, git mv does not do anything special. A index entry rename (rename_index_entry_at at read-cache.c) boils down to:

remove_index_entry_at(istate, nr);
add_index_entry(istate, new, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);

edit. (based on @Math's comment above). Since git tracks filenames, it's just two commands:

mv 2.txt 1.txt                # Rename it back to the first name
git mv 1.txt git 2.txt        # Tell git you've moved it

git add -p -- 2.txt           # You can now stage the hunks

MBlanc
  • 1,773
  • 15
  • 31
  • although this works, I already thought of that, that's why I added the "Externally renaming back and using git mv is not really a solution in my case, because of the many renames possible by the refactoring in an IDE." line in the question. If there is no better way without resorting to renaming back, I will accept it. Also should the second mention of 'git' be there in 2nd line of your snippet? – hbogert Jun 11 '14 at 13:27
  • 1
    As I understand it, `git mv` doesn't tell git anything special about whether you've moved a file, it just helps you with updating the index: http://stackoverflow.com/questions/1094269/whats-the-purpose-of-git-mv So does this actually work? And if so, why? – Ajedi32 Jun 11 '14 at 13:43
  • @Ajedi32 yes, that strategy does work. I used it as a possible solution getting my daily work committed today – hbogert Jun 11 '14 at 20:33
  • talking about read-cache.c, rename_index_entry_at also does: copy_cache_entry(new, old);` Could this explain why adding chunks is possible if one would've used git mv? – hbogert Jun 11 '14 at 20:55
1

If I'm understanding correctly, your problem stems from the fact that you can't interactively add chunks (with -p) to new files, only modified files.

You can tell git that you intend to add the file with the -N flag, and then git add -p should work:

$ mv 1.txt 2.txt    # not `git mv`
$ git add -N 2.txt  # Stages an empty file; you can now see the contents with `git diff`
...
$ git add -p        # Will include changes to `2.txt`
nickgrim
  • 5,387
  • 1
  • 22
  • 28
  • Doesn't this just result in the diff displayed in `git add -p` being "all content in `2.txt` was added"? Or does git detect the rename and somehow give you more fine-grained options for staging part of the file? – Ajedi32 Jun 11 '14 at 18:55
  • @Ajedi32 , indeed this does not allow one to stage chunks, merely the whole file. – hbogert Jun 11 '14 at 20:29