Skip to main content

Git: Discard All Local Changes and Get a Fresh Copy from GitHub

· 5 min read
Serhii Hrekov
software engineer, creator, artist, programmer, projects founder

A common and reliable way to get a fresh copy from a GitHub repository, while preserving specific local files like .gitignore, is to use a combination of git reset and git clean. This approach ensures your local branch exactly mirrors the remote branch, without leaving behind any untracked or unwanted files.

The Right Approach

Your goal is to achieve a state where your local repository is an exact clone of the remote, except for your .gitignore file. Here's the sequence of commands that achieves this:

  1. Stash your .gitignore file: This temporarily saves your .gitignore file so it won't be deleted.
  2. Forcefully reset your local branch: This discards all commits and changes on your local branch, making it an exact copy of the remote.
  3. Clean your working directory: This removes all untracked files, which includes things you might have created but not yet committed.
  4. Restore your .gitignore file: This brings your stashed .gitignore file back into the repository.

Step-by-Step Commands

Let's assume you're on the main branch and want to pull the latest from the origin remote.

Step 2.1: Stash the .gitignore File

First, you need to save your .gitignore file so it doesn't get deleted by the cleanup commands.

git stash push -- .gitignore

This command adds .gitignore to your stash, a temporary storage area for changes.

Step 2.2: Fetch the Latest from Remote

Before resetting, fetch the latest state of the repository from GitHub. This ensures you're resetting to the most current version.

git fetch origin main

This command downloads the latest changes from the main branch on the origin remote without merging them into your local branch.

Step 2.3: Reset to the Remote Branch

Now, you can forcefully reset your local main branch to the exact commit origin/main is pointing to.

git reset --hard origin/main

The --hard flag is crucial as it discards all local commits and uncommitted changes, making your local branch identical to the remote.

Step 2.4: Clean Untracked Files

Next, you need to remove all untracked files from your working directory, except those specified in .gitignore.

git clean -d -f

The -d flag removes untracked directories, and the -f flag forces the operation. git clean respects the .gitignore file, so it won't delete files that are ignored by your repository (1).

Step 2.5: Restore the .gitignore File

Finally, you can restore your .gitignore file from the stash you created in the first step.

git stash pop

This command applies the stashed changes to your working directory and then removes them from the stash.

Alternative for Simple Cases

If your goal is simply to pull the latest changes and a few files are untracked and in the way, you can use the git clean command alone.

# Forcefully remove all untracked files and directories
git clean -f -d

After this, you should be able to run git pull without issues.

Why This is the Best Approach

Using git reset --hard combined with git clean is the most explicit and reliable way to get a clean, up-to-date copy from the remote. It avoids the complexities of merges and ensures no unwanted local files or commits are left behind.

Sources

  1. Git Documentation: git clean