Managing Files in Git

Rename, move and delete files the Git way, stop tracking files without deleting them, clear out untracked clutter with git clean, and handle line endings with .gitattributes.

Lesson 4 of 30Beginner17 min read

Projects change shape all the time. You rename style.css to main.css, move images into an assets folder, delete an old logo, and realise a file of personal notes should never have been committed. Each of these is a change that Git needs to record, so the rest of your team gets the same tidy structure when they pull.

Git's own commands, git mv and git rm, make these changes and stage them in one step. git rm --cached stops tracking a file while keeping it on your computer, and git clean clears out clutter that was never tracked.

In this lesson you'll use all of them, learn to preview before deleting anything, and fix the "LF will be replaced by CRLF" warning that puzzles many Windows users.

Renaming and moving: git mv

Terminal
git mv style.css css/main.css

git mv renames or moves a file and stages the change, so git status shows it as renamed:

Text
R  style.css -> css/main.css

Git doesn't actually store renames. It notices that a file disappeared and a very similar file appeared, and reports a rename. That's why renaming in your editor and then running git add -A works just as well. Avoid renaming and heavily editing a file in the same commit: if the content changes too much, Git shows a delete and an add instead of a rename, which makes history harder to follow.

Deleting: git rm

git rm old-logo.png deletes the file from your folder and stages the deletion. The next commit removes it from the project.

  • If you've already deleted a file by hand, git add old-logo.png or git add -A stages the deletion too.
  • git rm -r folder/ removes a folder and everything in it.
  • Deleted files aren't lost: they're still in history, and git restore --source=HEAD~1 old-logo.png brings one back from an earlier commit.

Because history keeps everything, deleting a file containing a password doesn't make it safe. The secret must be changed, as the history lesson explains.

Untracking without deleting: git rm --cached

Sometimes a file was committed by mistake: an .env file, an editor's settings folder, or a large export. You want Git to forget it but keep it on your computer:

Terminal
git rm --cached notes.txt
echo "notes.txt" >> .gitignore
git add .gitignore
git commit -m "Stop tracking notes.txt"

--cached removes the file from the staging area only; your copy stays where it is. Adding it to .gitignore stops it being added again. Note that .gitignore only affects untracked files, which is why the --cached step is needed for a file Git already knows about. git ls-files lists every file Git is tracking.

Clearing clutter: git clean

git clean deletes untracked files: things Git has never been told about, like build output, logs and temporary files. Because they were never committed, they can't be recovered afterwards, so always preview first:

CommandDoes
git clean -nDry run: lists untracked files that would be deleted
git clean -ndDry run including untracked folders
git clean -fdDeletes untracked files and folders
git clean -fdxAlso deletes ignored files, such as node_modules

Git refuses to clean without -f (force) unless you've changed its settings, as a safety net.

Git Files Syntax

File commands

git mv old-name new-name
git rm file.txt
git rm -r folder/
git rm --cached secret.env
git ls-files
git clean -n          # preview
git clean -fd         # delete untracked files and folders
git restore --source=HEAD~1 file.txt

Git Files Summary

  • git mv old new renames or moves a file and stages the change.
  • git rm file deletes a file and stages the deletion; history still has it.
  • git rm --cached file stops tracking a file but keeps it on disk; add it to .gitignore too.
  • git clean -n previews and git clean -fd deletes untracked files and folders permanently.
  • .gitattributes with * text=auto eol=lf keeps line endings consistent across systems.

Git Files Examples

Each example shows the code, the output it produces and what each part does.

Example 1

Renaming and deleting

Terminal
git mv style.css css/main.css
git rm old-logo.png
git status --short
git commit -m "Move stylesheet into css folder, remove old logo"
Output
rm 'old-logo.png'
R  style.css -> css/main.css
D  old-logo.png
[main 8c41d2e] Move stylesheet into css folder, remove old logo
 2 files changed, 1 deletion(-)
 rename style.css => css/main.css (100%)
 delete mode 100644 old-logo.png
Line-by-line explanation
  1. Line 1The file is moved and the rename is already staged.
  2. Line 2The file is deleted and the deletion is staged.
  3. Line 3--short gives a compact status: R for renamed, D for deleted.
  4. Line 4The commit shows the rename was 100% similar, so Git kept the file's history connected.
Example 2

Stop tracking a file you committed by mistake

Terminal
git rm --cached .env
echo ".env" >> .gitignore
git add .gitignore
git commit -m "Stop tracking .env"
git status --short
ls -a
Output
rm '.env'
[main 3b7e9f1] Stop tracking .env
 2 files changed, 1 insertion(+), 1 deletion(-)
 delete mode 100644 .env
 create mode 100644 .gitignore
.  ..  .env  .git  .gitignore  css  index.html
Line-by-line explanation
  1. Line 1Remove .env from Git's tracking, but not from your folder.
  2. Lines 2 to 3Ignore it from now on, and commit the .gitignore change.
  3. Line 5The status is clean: .env is now ignored, not untracked.
  4. Line 6The file is still on disk. If it contained real secrets, change them: they're still in older commits.
Example 3

Previewing and cleaning untracked files

Terminal
git status --short
git clean -nd
git clean -fd
git status --short
Output
?? build/
?? debug.log
Would remove build/
Would remove debug.log
Removing build/
Removing debug.log
Line-by-line explanation
  1. Line 1Two untracked items: a build folder and a log file.
  2. Line 2-n means dry run, and -d includes folders. Nothing is deleted yet.
  3. Line 3-f actually deletes them. This can't be undone, because Git never had copies.
  4. Line 4The final status is empty: the working tree is clean.

Common Git Files Mistakes

Expecting .gitignore to untrack a committed file

Don't
echo "config.local.php" >> .gitignore
git commit -am "Ignore local config"     # file is still tracked
Do
git rm --cached config.local.php
echo "config.local.php" >> .gitignore
git add .gitignore
git commit -m "Stop tracking local config"

git rm when you meant --cached

Don't
git rm .env              # deletes your only copy of the file
Do
git rm --cached .env     # keeps the file on disk

Cleaning without a preview

Don't
git clean -fdx           # also deletes ignored files like .env and node_modules
Do
git clean -nd            # look first
git clean -fd            # then delete only untracked files and folders

Git Files in Real Projects

Managing files in practice

Teams reorganise folders with git mv so pull requests show clean renames, newcomers run git rm --cached after committing editor folders like .vscode, and build scripts use git clean -fdx to start completely fresh.

Git Files FAQ

Does Git track file renames?

Git doesn't store renames as such. It stores snapshots and works out renames afterwards by comparing content: a file deleted in one place and a very similar file added elsewhere is shown as a rename. That's why renaming with your file manager and then running git add -A gives the same result as git mv.

How do I keep an empty folder in Git?

Git tracks files, not folders, so an empty folder never appears in a commit. The usual workaround is to put a placeholder file inside, often named .gitkeep, and commit that. The name is only a convention; Git gives it no special meaning.

How do I change only the capitalisation of a file name?

On Windows and macOS the file system usually treats readme.md and README.md as the same name, so a plain rename may not be noticed. The reliable way is two steps: git mv readme.md temp.md and then git mv temp.md README.md, followed by a commit.

How do I get back a file I deleted with git rm?

If you haven't committed yet, run git restore --staged notes.txt and then git restore notes.txt to bring it back. If the deletion is already committed, restore the version from the commit before it: git restore --source=HEAD~1 notes.txt, then git add and commit it again.

What is the difference between git clean -x and git clean -X?

Lower-case -x removes untracked files including ignored ones, such as build output and node_modules. Upper-case -X removes only ignored files and leaves your other untracked files alone. Either can delete a lot, so preview with -n first.

Git Files Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Fill in the blankseasy

Complete the command that renames a file and stages the change.

git  about.htm about.html
Multiple choiceeasy

What does git rm --cached secrets.txt do?

Multiple choicemedium

Which command shows what git clean would delete, without deleting anything?

Predict the outputmedium

What does git status --short show after git mv a.txt b.txt?

Multiple choicehard

Why can't files removed by git clean -f be recovered with Git?

Git Files Quiz

5 questions to check what you learned.

  1. Which command lists every file Git is tracking?

    • git status
    • git log --files
    • git ls-files
    • git show files
  2. After deleting a file in your file explorer, how do you stage the deletion?

    • You can't
    • git add with the file name, or git add -A
    • git restore
    • git clean
  3. What does .gitattributes with * text=auto eol=lf help with?

    • Ignoring files
    • Making files read-only
    • Keeping line endings consistent between Windows, macOS and Linux
    • Compressing files
  4. Does deleting a committed file with git rm remove it from history?

    • No, earlier commits still contain it
    • Yes
    • Only after pushing
    • Only for large files
  5. What extra does git clean -fdx delete compared with git clean -fd?

    • Tracked files
    • The .git folder
    • Remote branches
    • Ignored files, such as node_modules and .env