Last modified: September 13, 2025

This article is written in: 🇺🇸

Staging, Committing, and Undoing Actions

The three core actions you’ll perform most often in Git are staging, committing, and undoing changes.

Staging Files

To prepare changes for a commit, we "stage" them. Staging involves selecting which changes in your working directory you want to include in your next commit. The staging area, also known as the index, acts as an intermediary between your working directory and your repository (commit history).

Staging allows you to organize your changes logically before recording them. By carefully selecting which changes to stage, you can create more meaningful and manageable commit histories, making it easier to track and understand project evolution.

+--------------+    +--------------+     +-------------------+
|              |    |              |     |                   |
| Working      |    | Staging      |     | Repository        |
| Directory    |    | Area (Index) |     | (Commit History)  |
|              |    |              |     |                   |
|  (Changes)   | -> | (Changes to  | ->  | (Commits)         |
|              |    | be committed)|     |                   |
+--------------+    +--------------+     +-------------------+

Here's how to stage files:

I. Stage a Specific File:

To stage a specific file, use the git add command followed by the file name. This tells Git to include the changes made to this file in the next commit.

git add filename

Example: If you modified a file named index.html, you would stage it with:

git add index.html

Staging individual files is useful when you want to commit changes selectively, ensuring that unrelated modifications are kept separate for clarity.

II. Stage All Changed Files:

If you want to stage all the changes you made across multiple files, you can use the git add . command. The period . is a wildcard that tells Git to stage changes from the current directory and all its subdirectories.

git add .

Example: If you modified several files and you want to stage all of them at once, simply run:

git add .

Staging all changes at once is efficient when you're confident that all modifications are related and should be committed together.

Unstaging Files

If you've staged changes but haven't committed them, you can unstage them. This can be useful if you change your mind about what should be included in the next commit.

Unstaging allows you to refine your staged changes, ensuring that only the appropriate modifications are recorded. It provides flexibility to adjust your commits before finalizing them.

I. Unstage a Specific File (but Keep Changes):

To unstage a specific file but keep the changes in the working directory, use the git reset command followed by the file name. This removes the file from the staging area.

git reset filename

Example: If you previously staged index.html but now want to unstage it, run:

git reset index.html

This is helpful when you realize that a particular file shouldn't be part of the current commit and needs further modifications.

II. Revert Everything to the State of the Last Commit:

If you want to discard all changes and revert everything in the working directory and staging area to match the last commit, use the git reset --hard command. This will remove all uncommitted changes, so use it with caution.

git reset --hard

Example: To discard all changes and revert to the last commit, run:

git reset --hard

This command is useful when you need to completely abandon your current work and return to a known good state.

Committing Files

Commits in Git are akin to saving the state of your project at a particular point in time. A commit captures the current state of your project and associates it with a message that describes the changes made since the last commit. Each commit is uniquely identified by a SHA-1 hash, and you can use the git checkout command to revert to a previous state of your project.

Commits form the backbone of your project's history, allowing you to track progress, understand changes, and collaborate effectively with others.

+----------+
|  commit  |
|   hash   | A unique identifier (SHA-1 hash) for the commit.
+----------+
|  author  | The person who authored the commit.
|  date    | The date and time the commit was made.
+----------+
| message  | A brief description of the changes made in the commit.
+----------+
| changes  | The actual changes made to the files.
+----------+

Here's how to commit files:

I. Commit All Staged Files with a Message:

To commit the changes you have staged, use the git commit command with the -m option followed by a descriptive message. This message should succinctly describe what changes have been made.

git commit -m "Your descriptive commit message"

Example: If you added a new feature, you might write:

git commit -m "Added new feature to enhance user interface"

A clear commit message is essential for maintaining a readable and understandable project history, especially when collaborating with others.

II. Push Your Commits to a Remote Repository (like GitHub):

After committing your changes locally, you often need to push them to a remote repository to share them with others or back them up. Use the git push command to accomplish this.

git push

Example: To push changes to the main branch of your remote repository:

git push origin main

Pushing commits ensures that your work is stored remotely, enabling collaboration and safeguarding against data loss.

III. Go Back to a Previous State Captured in a Specific Commit:

If you need to revert your project to a previous state, use the git checkout command followed by the commit ID. This command allows you to explore the project as it was at that specific commit.

git checkout commit_id

Example: If the commit ID is a1b2c3d4, you would use:

git checkout a1b2c3d4

This is useful for reviewing past versions or recovering specific states of your project.

Undoing Commits

Mistakes happen, and Git provides several ways to undo commits:

Being able to undo commits is vital for maintaining a clean and accurate project history. Whether you need to correct errors or remove unintended changes, Git's undo capabilities offer the necessary tools to manage your commits effectively.

I. Undo the Last Commit but Keep All Files Staged:

If you want to undo your last commit but keep the changes staged, use the git reset --soft HEAD~ command. This is useful if you realize you need to modify your commit message or make additional changes before committing again.

git reset --soft HEAD~

This approach allows you to adjust your last commit without losing any work, providing a chance to refine your changes.

II. Undo the Last Commit and Unstage the Changes:

To undo the last commit and unstage the changes (but keep them in the working directory), use the git reset HEAD~ command. This will make the changes appear as if they were never staged or committed.

git reset HEAD~

This is helpful when you need to reorganize your commits or exclude certain changes from the previous commit.

III. Erase All Changes Made in the Last Commit:

If you want to completely undo the last commit and discard all changes made, use the git reset --hard HEAD~ command. This is a more destructive action, so use it with caution.

git reset --hard HEAD~

Use this command only when you are certain that you want to remove the last commit and its changes permanently.

Editing Commit Messages

Sometimes, after committing changes, you realize that your commit message could be clearer or more descriptive. Fortunately, Git allows you to amend your commit messages. Here’s how to do it:

Clear and accurate commit messages enhance the readability of your project's history. Editing commit messages ensures that each commit accurately reflects the changes made, which is especially important for collaborative projects.

Edit the Message of the Most Recent Commit

To change the commit message of the most recent commit, use the git commit --amend command followed by the new message. After amending the commit message, you need to force push the changes to the remote repository.

git commit --amend -m "New, improved message"
git push --force

Example: If you want to update the most recent commit message to "Fixed bug in user authentication," you would run:

git commit --amend -m "Fixed bug in user authentication"
git push --force

Amending commit messages is straightforward but requires caution, especially when working with shared repositories.

Modify an Older Commit Message

If you need to change the message of an older commit, follow these steps:

I. Start an Interactive Rebase for the Last n Commits:

Begin by initiating an interactive rebase. Replace n with the number of commits you want to go back from the current head.

git rebase -i HEAD~n

Example: To modify the last 3 commits, you would run:

git rebase -i HEAD~3

Interactive rebasing allows you to selectively edit, reorder, or squash commits, providing granular control over your commit history.

II. Change "pick" to "reword" for Commits You'd Like to Modify:

In the interactive rebase interface, change pick to reword for the commits whose messages you want to edit.

III. Save and Close:

Save the changes and close the editor. Git will then prompt you to provide new commit messages for each commit marked with reword.

IV. Push the Changes:

After editing the commit messages, you need to force push the changes to the remote repository.

git push --force

This process ensures that your commit history remains clean and that older commits have accurate and meaningful messages.

Removing Commits in Git

Sometimes you realize you committed something by mistake — maybe the wrong file, maybe an incomplete feature. Git gives you a couple of ways to remove commits from your history.

Removing the last N commits

The command you’ll use is git reset.

Here’s the general form:

git reset HEAD~N

So if you want to remove the last two commits, you’d run:

git reset HEAD~2

At this point, Git has moved the branch pointer back in time. The commits are no longer part of your branch history. But the actual changes from those commits are still sitting in your working directory — as if you had just made them but hadn’t committed yet.

What this looks like

Let’s say your history was:

commit a1b2c3d (HEAD -> main)
commit e4f5g6h
commit i7j8k9l

After running:

git reset HEAD~2

The history now looks like:

commit i7j8k9l (HEAD -> main)

And the changes from e4f5g6h and a1b2c3d are now unstaged in your working directory, ready to be re-committed (or edited, or discarded).

Pushing to a remote

If your branch is connected to a remote (like GitHub), you’ll need to force-push to overwrite the history there:

git push origin +HEAD

The + sign tells Git you really want to replace the remote branch with your local branch, even though the histories don’t match anymore.

⚠️ Be careful with this — if anyone else has already pulled those commits, this will cause conflicts for them.

Cleaning Up Your Commit History

Every now and then, you might commit something you regret — a password, an API key, or maybe a massive file that doesn’t belong in Git. The tricky part is that even if you delete the file in a later commit, it’s still hanging around in the history. Anyone who digs into past commits (or clones the repo) can still find it.

That’s where git filter-branch comes in. This command lets you rewrite the history of your repo and strip out files completely. Think of it as a “surgical cleanup.” But use it carefully: since it rewrites history, it can mess with collaborators’ repos if they’ve already pulled from yours.

Step 1. Remove the file from history

Here’s the general command:

git filter-branch --index-filter 'git rm -r --cached --ignore-unmatch file_to_remove' HEAD

Replace file_to_remove with the actual filename.

For example, if you accidentally committed a file called secret.txt:

git filter-branch --index-filter 'git rm -r --cached --ignore-unmatch secret.txt' HEAD

When you run this, Git will go through all commits in your current branch (HEAD) and strip out that file.

Step 2. What you’ll see

The output looks something like this:

Rewrite 1a2b3c4d5e6f7g8h9i0 (1/100) (0 seconds passed, remaining 0 predicted)    
Rewrite 2b3c4d5e6f7g8h9i0j1 (2/100) (1 seconds passed, remaining 49 predicted)    
...  
Ref 'refs/heads/main' was rewritten

Git is basically replaying your commit history without the unwanted file.

Step 3. Verify the cleanup

Once it finishes, check the history to make sure the file is gone:

git log --stat

You should no longer see secret.txt listed in any commit.

If you want to be extra sure, try:

git grep "secret.txt" $(git rev-list --all)

If nothing shows up, the file is fully removed.

Step 4. Push the rewritten history

If this repo is on a remote (like GitHub), you’ll need to force-push, since you’ve rewritten history:

git push origin main --force

⚠️ Warning: this will cause problems for anyone else using the repo — they’ll have to re-clone or reset their local copy.

That’s the full cleanup process. It’s a bit heavy-handed, but it’s the standard way to remove a file from Git’s history.

Table of Contents

    Staging, Committing, and Undoing Actions
    1. Staging Files
    2. Unstaging Files
    3. Committing Files
    4. Undoing Commits
    5. Editing Commit Messages
      1. Edit the Message of the Most Recent Commit
      2. Modify an Older Commit Message
    6. Removing Commits in Git
      1. Removing the last N commits
      2. What this looks like
      3. Pushing to a remote
    7. Cleaning Up Your Commit History
      1. Step 1. Remove the file from history
      2. Step 2. What you’ll see
      3. Step 3. Verify the cleanup
      4. Step 4. Push the rewritten history