Last modified: September 13, 2025
This article is written in: 🇺🇸
The three core actions you’ll perform most often in Git are staging, committing, and undoing changes.
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.
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.
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.
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.
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.
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.
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.
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.
N
commitsThe command you’ll use is git reset
.
Here’s the general form:
git reset HEAD~N
HEAD
means “the commit you’re currently on.”~N
means “go back N commits.” For example, HEAD~2
means “go back two commits.”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.
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).
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.
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.
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.
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.
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.
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.