How to stop tracking a file in Git without deleting it?

You added a file to Git, but now you want to stop tracking it. You don't want to delete it, you just want to stop tracking it. How do you do that?

Setup

Let’s say you have a process called doit.sh that, when run, creates a log file.

alina

alina git:( main ) ./doit.sh

alina git:( main ) cat doit.log

Wed May 31 07:36:20 PDT 2023

alina git:( main )

You are satisfied with the process, so you decide to add it to Git.

alina

alina git:( main ) git add -A

alina git:( main ) git commit -m 'add doit process'

[main e423685] add doit process

 2 files changed, 4 insertions(+)

 create mode 100644 doit.log

 create mode 100755 doit.sh

alina git:( main )

Your working directory is currently clean.

alina

alina git:( main ) git status

On branch main

Your branch is ahead of 'origin/main' by 1 commit.

  (use "git push" to publish your local commits)

nothing to commit, working tree clean

alina git:( main )

You decide to run the process again.

alina

alina git:( main ) ./doit.sh

alina git:( main )

However, you realize that you do not want to track the log file.

alina

alina git:( main ) git status

On branch main

Your branch is ahead of 'origin/main' by 1 commit.

  (use "git push" to publish your local commits)

Changes not staged for commit:

  (use "git add <file>..." to update what will be committed)

  (use "git restore <file>..." to discard changes in working directory)

        modified:   doit.log

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

alina git:( main )

Your initial instinct may be to use git rm doit.log, but that would delete the file. This is not what you want if you wish to preserve the file. Instead, you simply want to stop tracking it.

Solution

The first step is to add the file to the .gitignore file.

alina

alina git:( main ) echo "doit.log" >> .gitignore

alina git:( main ) git add .gitignore

alina git:( main ) git commit -m 'ignore doit.log'

[main da7e3d5] ignore doit.log

 1 file changed, 1 insertion(+)

 create mode 100644 .gitignore

alina git:( main )

However, simply adding the file to .gitignore is not enough as it will still be tracked:

alina

alina git:( main ) git status

On branch main

Your branch is ahead of 'origin/main' by 2 commits.

  (use "git push" to publish your local commits)

Changes not staged for commit:

  (use "git add <file>..." to update what will be committed)

  (use "git restore <file>..." to discard changes in working directory)

        modified:   doit.log

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

alina git:( main )

Although the .gitignore file prevents the file from being added to the index in the future, it does not remove it from the index.

The solution is to use git rm --cached doit.log. This command will remove the file from the index, while keeping it in your working directory.

alina

alina git:( main ) git rm --cached doit.log

rm 'doit.log'

alina git:( main )

When you check the git status command now, you will see that the file has been removed from the index.

alina

alina git:( main ) git status

On branch main

Your branch is ahead of 'origin/main' by 2 commits.

  (use "git push" to publish your local commits)

Changes to be committed:

  (use "git restore --staged <file>..." to unstage)

        deleted:    doit.log

alina git:( main )

However, the file remains intact in your working directory.

alina

alina git:( main ) cat doit.log

Wed May 31 07:36:20 PDT 2023

Wed May 31 07:36:29 PDT 2023

Wed May 31 07:36:55 PDT 2023

alina git:( main )

Now it’s time to commit your changes.

alina

alina git:( main ) git commit -m 'remove doit.log from staging area'

[main 00c28d8] remove doit.log from staging area

 1 file changed, 2 deletions(-)

 delete mode 100644 doit.log

alina git:( main )

Once again, your working directory is clean.

alina

alina git:( main ) git status

On branch main

Your branch is ahead of 'origin/main' by 3 commits.

  (use "git push" to publish your local commits)

nothing to commit, working tree clean

alina git:( main )

If you were to run the process again, the log file would be updated but it would not be tracked by Git.

alina

alina git:( main ) ./doit.sh

alina git:( main ) git status

On branch main

Your branch is ahead of 'origin/main' by 3 commits.

  (use "git push" to publish your local commits)

nothing to commit, working tree clean

alina git:( main ) cat doit.log

Wed May 31 07:36:20 PDT 2023

Wed May 31 07:36:29 PDT 2023

Wed May 31 07:36:55 PDT 2023

Wed May 31 07:38:39 PDT 2023

alina git:( main )