1

I know that, when moving a file, you need to git add the "new" file and git rm the "old" file so git can see it as renamed rather than removed... but how can you fix a (pushed) commit that didn't do this properly?

I made a commit directly in Visual Studio and I wasn't paying enough attention - it renamed multiple files, and they now show as if the old files were removed and new ones were added, rather than the old files being renamed. I only realised this after having pushed multiple commits on top. Is there a way to fix it?

(And bonus question - why didn't Visual Studio handle this properly and how could I make it work next time, without having to use separate terminal commands?)

Vipul Gulhane
  • 761
  • 11
  • 16
SakoDaemon
  • 973
  • 1
  • 6
  • 21
  • Basically for renaming a file you need to use # git mv . git rm is not valid. – Yogesh Nov 03 '18 at 11:43
  • It's what the accepted answer [here](https://stackoverflow.com/questions/433111/how-to-make-git-mark-a-deleted-and-a-new-file-as-a-file-move) says, I personally found that just using `git add .` usually makes renames get recognized properly. – SakoDaemon Nov 03 '18 at 11:46
  • I literally mentioned that exact post above, and said that I know how to do that. My problem is I want to FIX a commit after NOT doing that. – SakoDaemon Nov 03 '18 at 13:40
  • Did you just renamed the files, or did you change their contents as well? – evolutionxbox Nov 03 '18 at 13:54
  • Renamed and changed the `#include` tags to match the new names. – SakoDaemon Nov 03 '18 at 13:55
  • I'm marking this as a dup, since overall that question has answers that do a good job in answering why git is not showing you renames (it uses a heuristic, you did nothing wrong) and how you could change your history to show you renames if you really wanted to. – Edward Thomson Nov 03 '18 at 14:41

2 Answers2

1

(copy the library before you do this as you might break something)

Check out the current code in a new branch(NB). Reset to the commit before the rename. Rename everything again with git mv. Commit this. Then you start cherrypicking / replaying commits ontop of your current branch from NB.

If you do this.. You will have to forcepush code to the server since you rewrote the history. Which means that anyone that pulled your code will get errors and have to repull/will get conflicts.

Jonas
  • 185
  • 12
0

I know that, when moving a file, you need to git add the "new" file and git rm the "old"

You can achieve this with a single command git mv

I only realized this after having pushed multiple commits on top. Is there a way to fix it?

Yes.

Now let's explain in details what and how.


How to rename git files

How does git store files?

First of all, let's understand how git stores the file names and why there is a "problem" as novice users see it.

  • git doesn't care what is file name when storing content.
  • The file name is stored separately from the content.
  • Every time you execute git add git calculate the SHA-1 of the content and store it inside the .git/objects folder
  • The first 2 HEX digits of the SHA-1 are the folder name and the remaining 38 are the file name inside this folder
  • A file content is a blob in git.
  • The content of the .git/object/<SHA-1> is the following:

    blob<single white space><Content length><null><content>

enter image description here

Where is the file name?

  • Git store full path and not a plural file names.
  • The "folder" structure is stored inside "tree" objects.
  • The file name is stored elsewhere and it will be too long to explain here. in short git store the list of files and their SHA-1 in an object named tree

  • Git generates the file list (called snapshots) before your commit.

  • To view the SHA-1 of your files : git ls-tree -l <commit id>

enter image description here

  • Once you commit your changes git will write the data to the tree object

enter image description here

enter image description here


And now that we have explained in short how git store files we can explain what went wrong.

Since git doesn't care about your file name and they are only used for writing the content to your local file system they are stored elsewhere.

When you "move" a file git see it as a new file and the consequence is a deletion of your "old" file and "finding" a new file

enter image description here

In order to rename your files, you have to use the git mv command which updates the internal git storage and move the file to the new location enter image description here

CodeWizard
  • 128,036
  • 21
  • 144
  • 167
  • No, `git mv a b` is just a shorthand for `git rm a` and `git add b`. git does not store rename information, it uses a heuristic to measure similarity between old paths and new paths, and based on that similarity decides whether to show you that `a` was renamed to `b` or whether `a` was deleted and `b` was added. It makes no difference whether you use `git add` or `git mv`, the results will be identical. – Edward Thomson Nov 03 '18 at 14:37