34

Is there any way in VS Code to change a file's name so that the file history is preserved in git, and it doesn't think the tracked file's been deleted?

I'm hoping for a GUI implementation of the command:

git mv oldName.abc newName.xyz

Thanks

Ryan Loggerythm
  • 2,877
  • 3
  • 31
  • 39

4 Answers4

33

There is no need for it. Just rename the file. Git will detect renames regardless of whether git mv was used or not.

Try it: rename it in the normal way, stage the file under both the old and the new name (or just do git add .) and then run git status in the console, it should show up as rename and not as creation and deletion, so history is always preserved.

CherryDT
  • 25,571
  • 5
  • 49
  • 74
  • 7
    when I run `git status`, I see "Changes not staged for commit:..." "deleted: {old name}" and under the untracked file, I see the newly renamed file – Ryan Loggerythm Aug 04 '20 at 23:33
  • 19
    Yes but once you stage them, it'll look differently – CherryDT Aug 04 '20 at 23:34
  • 4
    What if you move them to another folder? – Corey Alix Sep 06 '20 at 02:46
  • when i rename it this way it doesn't recognize it is the same folder. Also happens when moving a file. It's an basic feature for an IDE. – Maxwell s.c Jan 15 '21 at 19:44
  • 4
    I'm not sure what you are referring to... It works fine, just keep in mind that you have to have it staged under both the old and new name/location before it can be seen as rename action (because the index is based on filenames and until the file is also added to the index under the new name, what you get is a deletion of a file that's indexed, and an untracked new file not yet in index). – CherryDT Jan 18 '21 at 08:51
  • 21
    There is a reason to ask for an automatic git mv when moving a file through an IDE. git will detect movements in "most cases", but not all. Typical case is when you when a file AND modify it in a consequent amount in the same commit. git can clearly fail to detect the movement in these cases. Unfortunately these cases are not that rare. That's why multiple other IDEs (notably IntelliJ and Netbeans, according to my experience) explicitly perform a git mv when moving or renaming files. Then it is perfectly clear to git that the file was moved, there's no possible ambiguity. – nicolas-van Jun 01 '21 at 12:35
  • Additionally, OSX treats files as case insensitive, so a rename from `filename.js` to `Filename.js` is not picked up by git. – adamsuskin Dec 21 '21 at 23:13
  • git mv is useful to rename files with case-sensitive name, git doesn't detect changes any time. – allema_s Apr 06 '22 at 13:05
  • This is not reliably always the case. Enough changes within file, and git will see it as a delete/add rather than a mv, losing the continuity of git history for that file and also asking for merge conflict pain. There's a reason `git mv` exists. – Karlie Verkest De Young May 16 '22 at 21:25
  • @KarlieVerkestDeYoung Not really. If you do a substantial-enough change, then regardless of whether you do `git mv` or not, as soon as you add the content change too (for example by first adding the change to index and then doing `git mv`, or by doing `git add` on the new file after changing and `git mv`ing it, or by using `git add .`), the "rename" turns into delete+add. Try it: `git init; echo hello > a; git commit -m a; echo world > a; git add a; git mv a b; git status` - You will get `deleted: a` and `new file: b` instead of `renamed: a => b` even though you used `git mv`. – CherryDT May 16 '22 at 22:46
  • 1
    The best method I found so far was to perform the file rename, commit, then make content changes in a second commit. Using mv is really optional. You may see "moved" indicators before committing but they don't have any effect once commited. For the Git log/history, Git only applies the similarity method (i.e. a deleted and added file are similar enough content-wise). By splitting move and content changes, Git should reliably be able to track renamed files. This seems to work reliably for moves across subfolders, too. – Christoph Dec 05 '22 at 22:38
  • 1
    **For those who want to understand how git handles rename/move, see this complete answer: https://stackoverflow.com/a/70444785/9150270** – Sandra Rossi Jun 04 '23 at 10:17
9

Git does not store the information that files are renamed. It detects it only when it does a diff (in git diff / status / log/ etc.). (Source)

There is an option -M to control the level of this rename detection.

       -M[<n>], --find-renames[=<n>]
           Detect renames. If n is specified, it is a threshold on the similarity index (i.e. amount of addition/deletions compared to the file’s size).
           For example, -M90% means Git should consider a delete/add pair to be a rename if more than 90% of the file hasn’t changed. Without a % sign,
           the number is to be read as a fraction, with a decimal point before it. I.e., -M5 becomes 0.5, and is thus the same as -M50%. Similarly, -M05
           is the same as -M5%. To limit detection to exact renames, use -M100%. The default similarity index is 50%.

Try it with:

git status -M10%

For VS Code, you can use the GitLens extension, it provides an option to control this threshold, the setting is called similarityThreshold.

gitlens.advanced.similarityThreshold    Specifies the amount (percent) of similarity a deleted and added file pair must have to be considered a rename

Try to set it to 10 and check the history through GitLens, it should detect the file rename better.

DLight
  • 1,535
  • 16
  • 20
  • Not true. "git mv" clearly does more than the attempt and automatically detecting renamed/moved files. "git mv" will lead to a reliable file history where as automatic detection does not. – Christoph Nov 27 '22 at 22:06
  • 1
    @Christoph I don't think so, please see [the Git FAQ](https://git.wiki.kernel.org/index.php/GitFaq#Why_does_Git_not_.22track.22_renames.3F): "Git has a rename command git mv, but that is just for convenience. The effect is indistinguishable from removing the file and adding another with different name and the same content." – DLight Dec 03 '22 at 10:39
  • Hmm, unfortunately you seem to be right. My TortoiseGit client does show the moves done with "mv" in the commit dialog. That's why I thought Git was aware of them. But once committed, the history does not indicate the file move if file name AND content changed too much. Very unfortunate... – Christoph Dec 05 '22 at 22:33
7

Since git sometimes does not detect rename operations, I have installed this extension in Visual Studio Code which so far seems to work fine to rename files and doing a git mv underneath:

https://marketplace.visualstudio.com/items?itemName=ambooth.git-rename

The cool thing from the README.md is that during rename a new directory location can be specified:

Usage

Right-click on a file in the File Explorer and choose "Rename (git-mv)". Using the input text field that appears, enter the new name and press Enter. Note: Directory location can also be altered by adjusting the path.

Jeroen Wiert Pluimers
  • 23,965
  • 9
  • 74
  • 154
  • 2
    What a time saver. I tried to switch the F2 "rename" binding to this command but unfortunately that didn't work. VS Code would show an error message, something about a theme. – Christoph Nov 27 '22 at 22:11
  • 1
    This will only work in situations where a simple rename + stage would have worked anyway. Git [uses heuristics](https://stackoverflow.com/questions/70401702/how-to-perform-git-move-in-visual-studio-instead-of-git-delete-and-git-add-whe/70444785#70444785) either way to decide if something was renamed or changed - it's done using a similarity threshold that you can change whenever you diff. I was always under the same impression as you, that `git mv` would actually do something different. I just learned today, that's not the case. Apparently the author of the extension thought so to. Many do. – mindplay.dk Aug 13 '23 at 09:41
  • @mindplay.dk it indeed does. Thanks for checking that out. The only benefit then is a slightly better vscode integration than just `git mv` on the console. – Jeroen Wiert Pluimers Aug 14 '23 at 16:36
1

I believe this is the correct answer (probably a feature VSCode added since previous versions). In Source Control panel, after you rename, open File History panel. Click the three dots ..., Toggle Follow Renames should be set to On.

I also used the command line to rename, stage, and commit (instead of clicking the VSCode UI) but I am thinking that wasn't actually necessary.

Caleb
  • 11
  • 1
  • Interesting. I just tried this and magically all of the old history appeared. Will be playing with this more to see if this is what I want to do vs all of the other suggestions I see online regarding moving files and losing git history. Note, I did NOT use the command line at all for moving/staging/committing. – flyer Sep 03 '23 at 05:03