How to PROPERLY discard changes in GIT? [6 Methods]


GIT

Author: Steve Alila
Reviewer: Deepak Prasad

Understand various states in GIT

In the world of version control with Git, the phrase "git discard changes" is a lifeline for developers. It denotes the ability to undo, revert, or simply discard changes that haven't been finalized, ensuring that mistakes or unwanted modifications don't become a permanent part of the project history. To understand the depth of "git discard changes", it's essential to grasp Git's core operational states: the working directory, staging area, and commit history.

  • Working Directory: This is your playground. Here, you actively modify files, but Git hasn't recorded these changes yet. Think of it as your current workspace, reflecting the live, often unsaved, state of your project.
  • Staging Area: Consider this the waiting room. After making changes in the working directory, you can choose which ones you're ready to commit by moving them to the staging area. It's your way of telling Git, "I'm considering these changes for my next commit."
  • Commit History: This is the ledger of your project. Every time you finalize changes, they get saved as a commit in this history. It's a timeline that captures every saved change, letting you travel back in time to any version of your project.

After creating or modifying files in the working directory, git temporarily takes a snapshot of the index changes before storing them in the git database when each commit becomes part of the history. The history tells more about the commit, such as the author, date created, and most importantly, a unique hash called the commit hash.

The last commit hash is often referred to as the HEAD. Changes that have not passed the index (a.k.a staging area) are called uncommitted, while those with a history are called committed changes.

Passed the local workflow, you can send the changes to a remote server on a website like GitHub, GitLab, or Bitbucket. Then the changes are pushed. Otherwise, they are unpushed.

That is the basic explanation of the commit HEAD, uncommitted, and committed changes. Let's see their role in discarding git changes.

 

 

Commands to be used at different git state for discarding changes

1. Discarding Local Changes in the Working Directory:

  • At times, you might find yourself with local modifications that you no longer want, either because they were experimental, mistakes, or superseded by newer ideas.
  • This is the state where you've made local modifications to files but haven't added them to the staging area yet. These changes are "unstaged."
  • Running git status will show these files under "Changes not staged for commit."
  • Commands relevant to this state for discarding changes:  git checkout, git clean, git stash

2. Unstaging Changes:

  • After adding changes to the staging area, you might reconsider which modifications should be part of the next commit.
  • After making local changes and adding them to Git's "staging area" with git add, they're ready for commit. However, they aren't committed yet. This is the "staged" state.
  • Running git status will show these files under "Changes to be committed."
  • Commands relevant to this state for discarding changes: git reset, git stash, git restore

3. Reverting Commits:

  • Sometimes, even after finalizing and committing changes, you realize they might be erroneous or unnecessary. Rather than deleting or hiding these commits, Git allows for a safer method: creating a new commit that undoes the changes of a previous one. This ensures the history remains intact while effectively "reverting" the unwanted modifications.
  • Once changes are committed, they become part of the repository's history. If you need to undo a commit, you're looking to revert a change that's already been finalized.
  • Running git log lets you see the list of past commits. Any commit in this log can be considered for reverting.
  • Commands relevant to this state for discarding changes: git revert, git reset

 

Discarding Changes in the Working Directory

1. Using git checkout:

This command can discard changes in specific files or the entire working directory.

Specific File: To discard changes in a single file (example.txt for instance):

git checkout -- example.txt

Entire Directory: To discard changes in all files in the directory:

git checkout -- .

 

2. Using git clean:

This command is used to remove untracked files from the working directory. Note that it won't affect tracked files (files that are already part of the Git repository).

Remove Untracked Files: To delete all untracked files:

git clean -f

Remove Untracked Directories: To remove untracked directories in addition to untracked files:

git clean -fd
IMPORTANT NOTE:
git clean is a destructive command. Once you remove untracked files/directories with it, they're gone for good. Always double-check what you're about to delete (using git clean -n to do a dry run can help).

 

3. Using git stash:

This command temporarily shelves (or "stashes") changes you've made to your working directory. It can be used to store both staged and unstaged changes.

Stash Changes: To stash all changes in the working directory and staging area:

git stash

Stash with Message: To stash with a descriptive message:

git stash save "My descriptive message"

Apply and Drop Stashed Changes: If you want to bring back the stashed changes:

git stash apply

And if you're sure you no longer need the stashed changes:

git stash drop

 

4. Using git restore

This is a newer command introduced in Git version 2.23:

Specific File: To discard changes in a specific file (example.txt):

git restore --source=HEAD --staged --worktree example.txt

Entire Directory: To discard changes in the entire directory:

git restore --source=HEAD --staged --worktree .

 

Unstaging Changes

Unstaging changes refers to the action of moving changes from the staging area (where they are prepped for commit) back to the working directory. This is particularly useful if you've decided you want to modify some of the changes or exclude them from the next commit. Here are the primary commands to achieve this:

 

1. Using git reset:

The git reset command is a traditional way to unstage changes. It operates by moving the current HEAD pointer backward (which can be risky if you're not careful), but when used without any commit reference, it only acts on the staging area.

Unstage a Specific File: If you've staged changes for a file named example.txt and you wish to unstage them:

git reset example.txt

Unstage All Changes: To remove all files from the staging area:

git reset

 

2. Using git restore:

Introduced in Git version 2.23, git restore is designed to make unstaging (and other tasks) more intuitive.

Unstage a Specific File: For unstaging changes in a file called example.txt:

git restore --source=HEAD --staged example.txt

Unstage All Changes: To unstage all changes in the staging area:

git restore --source=HEAD --staged .

Note:

  1. The --source=HEAD option in git restore indicates that you're using the latest commit as the source for the restore operation.
  2. Both git reset and git restore used in the contexts above will only affect the staging area. Your working directory changes will remain intact.

 

Reverting to a Previous Commit

1. Using git reset:

To revert to a previous commit but keep all changes in the working directory (soft reset):

git reset COMMIT_HASH

To revert to a previous commit, unstage changes, but keep them in the working directory (mixed reset, this is also the default):

git reset --mixed COMMIT_HASH

To revert everything (commit history, staging area, and working directory) to the state of a previous commit (hard reset, use with caution):

git reset --hard COMMIT_HASH

 

2. Using git revert:

git revert doesn't actually move the HEAD back in history. Instead, it creates a new commit with changes that reverse a previous commit:

git revert COMMIT_HASH

This is a safer option in shared repositories since it doesn't rewrite commit history.

Replace COMMIT_HASH with the actual hash (or another identifier, like a branch name) of the commit you're referencing. Always be cautious when reverting or resetting, especially with the --hard option, as these changes can be difficult or impossible to undo.

 

Scenario-1: Git discard uncommitted changes

Example-1: Using git clean command

The git clean command is crucial in discarding changes in untracked files. Although we can use it with several flags, its most familiar forms are -f for untracked files only, -fd for both untracked files and directories, and -i for interactive file discard.

For instance, let's stage file1.txt and f2.txt, leaving the third.txt file and dir directory untracked.

git add file1.txt f2.txt

Running the command

git clean -f

clears the third.txt file from the working directory.

How to PROPERLY discard changes in GIT? [6 Methods]

Similarly, introducing the -d flag dumps untracked files and directories.

git clean -fd

Rechecking git status

git status

The untracked dir directory got discarded!

How to PROPERLY discard changes in GIT? [6 Methods]

Lastly, we can use the -i flag by picking the clean option.

Create a file.

touch file

Delete it.

git clean -i

Git prompts us for an option. Let's pick 1: clean to git discard changes

How to PROPERLY discard changes in GIT? [6 Methods]

 

Example-2: Use either git checkout or git restore command

The checkout command has several uses in the git workflow. Apart from switching between branches and commits, you can apply it to git discard changes. All you do is be at the root of the working directory and run either

git checkout -p

or

git checkout -- .

commands.

If it fails to remove your recent changes, use the restore command

git restore <file>

which has been git's preferred way to discard changes since the introduction of git version 2.23 in 2019.

Let's modify file1.txt.

echo line1 >> file1.txt

Assume we want to delete the most recent changes on file1.txt. We can do that by running the command:

git restore file1.txt

git discard changes using the restore command

We can also modify file1.txt and f2.txt then git discard changes on them as follows

echo line1 >> file1.txt

echo l2 >> f2.txt

git restore .

All the new changes disappeared!

 

Example-3: Use git stash command to stash the changes

Assume you want to git discard changes hoping to restore them later. The command to use is git stash. Before clearing your changes from the index, it records them in the .git/refs/stash file in your working tree, only retaining changes as per the commit HEAD.

Let's modify the two files: file1.txt and f2.txt to practice git stash.

echo line1 >> file1.txt
echo line2 >> f2.txt

Stage the changes.

git add *

then check status.

git status

Discard the changes using the stash command.

git stash

Then recheck the status.

git status

Our uncommitted changes disappeared

stash files before git discard changes

We can see the stashed changes using

git stash show

and restore them using git stash apply as follows

git stash apply

How to PROPERLY discard changes in GIT? [6 Methods]

Another way to discard the changes in the index is to do a mixed reset on the changes.

 

Example-4: Reset the HEAD

Running the mixed reset command

git reset HEAD

untracks the files from the index and dumps the changes in the working directory.

How to PROPERLY discard changes in GIT? [6 Methods]

 

Scenario-2: Git discard already committed changes

Example-5: Discarding un-pushed files

The hard reset is the most straightforward command to git discard changes already committed. We can use it as follows.

Let's restage the files.

git add .

And commit them.

git commit -m "Reset the HEAD"

View the HEAD.

git log

before resetting it.

git reset --hard HEAD^

Recheck the history.

git log

The hard reset command on the HEAD^ removed the latest commit.

How to PROPERLY discard changes in GIT? [6 Methods]

Note: git reset hard discards both changes and files from the working directory. The only way to recover the changes is to inspect the reflog and checkout the target commit hash.

Better yet, avoid the hard reset command if you have pushed the changes.

 

Example-6: Discarding remote pushed files

Doing a hard reset on local files can cause a conflict error when used on files already committed. Git revert is the best alternative to discard commit changes on pushed files.

Running

git log

shows we have four commits

How to PROPERLY discard changes in GIT? [6 Methods]

Let's revert the last three commits by making the HEAD point the initial commit hash.

git revert b4ad96

Our default text editor prompts us for a new commit message. We can go with the default message then close the text editor.

How to PROPERLY discard changes in GIT? [6 Methods]

Let's push the changes.

git push

 

Summary

When working with Git, developers often find themselves needing to modify their selection of changes before finalizing a commit. The process of selecting changes for a commit is known as "staging," and once changes are staged, they are ready to be committed to the project history.

However, there might be times when a developer decides to alter what changes should be included in the next commit, or even reverse a decision altogether. This act of modifying what's staged is known as "unstaging."

There are two primary Git commands to help with unstaging:

  1. git reset: A traditional command for unstaging, which can be used in several scenarios. When used without specifying a commit, it operates on the staging area, effectively removing changes from being staged. It can target specific files or all changes.
  2. git restore: A more recent addition to Git (from version 2.23), offering a more intuitive approach to unstaging changes. By using specific flags like --source=HEAD and --staged, developers can selectively move changes out of the staging area.

Regularly using git status ensures clarity on what is currently staged and what remains in the working directory. When used effectively, Git's staging and unstaging capabilities allow developers to curate their commits for clarity and meaningful project history.

 

Steve Alila

Steve Alila

He specializes in web design, WordPress development, and data analysis, with proficiency in Python, JavaScript, and data extraction tools. Additionally, he excels in web API development, AI integration, and data presentation using Matplotlib and Plotly. You can connect with him on his LinkedIn profile.

Can't find what you're searching for? Let us assist you.

Enter your query below, and we'll provide instant results tailored to your needs.

If my articles on GoLinuxCloud has helped you, kindly consider buying me a coffee as a token of appreciation.

Buy GoLinuxCloud a Coffee

For any other feedbacks or questions you can send mail to admin@golinuxcloud.com

Thank You for your support!!

Leave a Comment