Home > OS >  Git reset loses track of moving files
Git reset loses track of moving files

Time:08-03

I've got a git repo that looks like this

          v master
A <- B <- C <- D
               ^ foo

where master and foo are two branches. I want to merge foo into master, but I want to refactor commit D first. The differences between C and D are the following:

  • A couple of files have minor changes.
  • Several files were moved from their old location to a new one in a new directory. I'd like to split D up into two commits, one with the edits and one with the file moves. Normally I'd do this by checking out D, doing git reset C, and then committing stuff as I see fit.

However, when I do git reset C, git seems to completely forget that some of the files were moved renamed. Instead, it thinks that I deleted some files and created some other ones.

How do I help git understand what's going on, so that I can split the edits and file moves?

Here's a complete shell session illustrating the issue:

~/src/junk$ git init
Initialized empty Git repository in <snip>
~/src/junk$ touch a.txt b.txt c.txt
~/src/junk$ git add a.txt b.txt c.txt 
~/src/junk$ git commit -m "Initial commit."
[main (root-commit) c76830b] Initial commit.
 3 files changed, 0 insertions( ), 0 deletions(-)
 create mode 100644 a.txt
 create mode 100644 b.txt
 create mode 100644 c.txt
~/src/junk$ mkdir Subdir
~/src/junk$ git mv b.txt c.txt Subdir/
~/src/junk$ echo "This is text." > a.txt
~/src/junk$ git add a.txt 
~/src/junk$ git commit -m "Moved b.txt and c.txt, edited a.txt."
[main 9efc354] Moved b.txt and c.txt, edited a.txt.
 3 files changed, 1 insertion( )
 rename b.txt => Subdir/b.txt (100%)
 rename c.txt => Subdir/c.txt (100%)
~/src/junk$ git reset HEAD~1
Unstaged changes after reset:
M   a.txt
D   b.txt
D   c.txt
~/src/junk$ git status
On branch main
Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
    modified:   a.txt
    deleted:    b.txt
    deleted:    c.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)
    Subdir/

no changes added to commit (use "git add" and/or "git commit -a")

CodePudding user response:

The default mode of operation of git reset is --mixed which means that (from git help reset):

Resets the index but not the working tree (i.e., the changed files are preserved but not marked for commit) and reports what has not been updated.

So, if index is getting adjusted to what it was in the first revision (only the original files are there), then when comparing with working tree, b.txt and c.txt are deleted, a couple of new files are untracked in Subdir and a.txt was modified, just what you see in the status report.

What you are probably expecting to see is what git reset --soft does. --mixed updates where HEAD points to and also the index.... --soft only moves the pointer but the index is kept as is. I think that is what you want, right?

You can stop reading at this point. What follows is some additional stuff I had posted previously in the answer but that is not really relevant because the question is all about the reset operation:

As a general rule: do not care if git notices that files moved or not. Actually, git doesn't care about. That's information that is not tracked at all. A movement is inferred by git by checking files that are added and deleted between revisions (being one after the other or in ranges, like when merging). If the files' contents look close enough (and this level can be set at will, if I recall correctly) then git will consider that the file was moved..... you might have a situation like this:

A <- B <- C ............. <- L <- M ........ <- X

And suppose that on B you renamed a file (no content change, to make the example clearer). Then you check with git diff A L and see the file as being renamed.... but if the file changes enough between L and X, if you did git diff L X, file would be a simple diff with a lot of changes on the same file, but then you try git diff A X, you could get not a rename but a deletion/creation of the file. It all depends on how different the content is between the original file in A and the final file in X.

  •  Tags:  
  • git
  • Related