Git is arguably the most popular version control system used. It is difficult to imagine an IT project without some sort of version control system to help the software teams manage changes to the source code over time. It is a really powerful tool capable of tracking and comparing all the changes and keeping multiple teams of engineers in sync.
Git works directly on your source code and hence, it can also cause a lot of headache when not used properly. No matter how well you manage the code, things can inevitably go wrong either due to your own mistake or your colleague’s. In such case, it becomes really handy to know some of the advanced git commands that can help you clean up the mess.
1. Temporarily store uncommitted changes with git stash
Stash is useful when you want to temporarily store your uncommitted changes or you are halfway through the code change but you want to work on something else without having to commit the incomplete change.
Also, you will need to use -u flag to include untracked files in the stash.
git stash will store your current uncommitted changes for later use and revert those changes in your current branch. Now you can freely switch branches, pull in changes or perform any other git operations and re-apply the stashed commits later on top of it using git stash pop.
Pretty handy, isn’t it?
You can also maintain multiple stashes and choose to apply a specific stash with the command git stash apply [stash index] or git stash pop [stash index]. If you use git stash apply command instead of pop, the stash will still remain in the stash list which you can clear by using git stash clear.
If you ever get merge conflicts while applying your stash, fix your merge conflicts and then do git reset.
2. Undo recent local commits
Sometimes, you might accidentally add wrong files to your commit or want to undo your commit for some reason. If you haven’t yet pushed it to the server, you can simply undo the commit with the git reset command.
Here, ‘HEAD~1’ tells Git to move the HEAD pointer back one commit. If you want your HEAD pointer to go back to specific commit, you can check the commit log using git log and then use the commit hash to go back to. All the changes will still be preserved.
If you want to undo the commit as well as remove all the changes as well, you need to pass the --hard flag. This will also remove all other changes that have not yet been committed as well. Pass the --keep file to preserve the uncommitted changes.
There is also --soft flag that you can use which will undo the commits but will keep them staged.
Undoing public commits
In order to undo commit that has already been pushed, you can use the git revert command.
If you want to revert range of commits,
What this basically does is it creates a new commit that will undo the specific commit. The commits made and the revert commit will be visible in your git history.
If you want to permanently remove the commit along with its trace from the git history instead,
[Warning: This should only be done if you are the only one working on the branch and no one has pulled in the changes yet.]
This will undo and remove the commit. Use HEAD~1 to undo only the last commit. Then push the changes using the -f flag which will force push the change.
To modify the changes before push, remove the –hard flag. This will re-checkout all the updates locally. You can then make your changes and commit them and push with -f flag.
3. Undo uncommitted changes
To remove your uncommitted changes, you have couple of different ways.
If you have multiple stashes maintained
Using reset and checkout
4. Move your local committed changes to different branch
For new branch
For existing branch
5. Merge multiple commits into single one
If you want to merge all the last local commits,
If you want to merge n number of previous commits
This only works for merging last N commits. If you want to merge commits in the middle, you will need to use git rebase.
Let’s say you want to merge the 2nd last and the 3rd last commit into single one.
You will get something like below listing all the commits and the word ‘pick’ at the beginning. Notice how the commits are in reverse order i.e. oldest first.
Replace ‘pick’ with ‘squash’ or ‘s’ for the 2nd line. This will merge the 2nd last commit to the 3rd last commit. (2nd line below will be merged to the 1st line)
Now save the editor with :wq. You will be prompted to select a commit message. By default, the commit messages will be concatenated into a single commit message but you can choose a different commit message altogether as well.
In case of public commits (which I have already mentioned above that it is not recommended if others have pulled in your changes), you can push the changes with -f flag.
If you are just looking to merge public commits from one branch to another branch, there is a simpler way to do it.
Note: Make sure you have no uncommitted changes
6. Rename local commit message
If you want to rename your last local commit message, you can pass --amend flag to git commit.
The --amend flag is also useful when you want to add new changes to your last local commit without modifying the commit message.
This will simply add your new changes to your last commit.
If you want to rename nth last local commit message, you can use git rebase that we used earlier for merging commit.
You will get the list of all the commits and you can rename the commit message leaving rest the same.
7. Copy a commit from one branch to another
Unlike merge or rebase which can apply multiple commits into your branch, there is a cherry-pick command that will apply a specific commit to your branch. To be specific, “cherry-pick commit applies the changes introduced by the named commit on the current branch”.
In case you are cherry-picking from public branch, you might consider using -x flag that appends a line that says “(cherry picked from commit …)” to the original commit message in order to indicate which commit this change was cherry-picked from.
8. Adding committed files to .gitignore
If a file or files has been added to the repository and you want to ignore it in the future commits, simply adding it in .gitignore won’t work. Since it is still present in the index, it’ll still continue to be tracked by git. You’ll first need to untrack the files.
If you are dealing with multiple files, you can remove them all using
This will also work if your gitignore file is acting weird for some reason.
9. Advanced logging with git log
We already know that git log lists the commits made in the repository in reverse chronological order. You can also pass in various flags to customize the log display.
The --stat flag will display the changes stats like list of modified files, number of lines changed, files added/removed, etc with the log.
If you want to see the changes in the files as well, you can use git log --patch -1 command. `-1` will show the changes in the last commit.
With --pretty flag, you can change the log output to formats other than the default. You can provide few prebuilt options like --pretty=oneline which prints out one line commit messages and the hash. You can achieve the same with git log --oneline well.
If you pass in --graph flag, it will add a nice little ASCII graph showing the branch and merge history as well.
Git log shows the commit logs traversing back through the repo’s ancestry. Apart from this, there is also git reflog which is slightly different.
One of the things Git does in the background while you’re working away is keep a reflog - a log of where your HEAD and branch references have been for the last few months.
This becomes particularly important when you accidentally delete your commit or made mistakes while rebasing or resetting and you want to recover them. Even though the git log command won’t display them, you can find it in your reflog. You can use the commit hash to checkout and recover the state of your project.
It becomes hard and cumbersome sometimes to remember all the long commands or flag options that goes in with the git commands specially the log flags or amend flags. In that case, keeping a list of alias can be really useful and can save you lots of time.
I hope you found this article useful. There might be other ways too to achieve these same things. This is just a list of commands that I’ve compiled based on my experience and which I like to use frequently. If you liked this blog, do checkout other articles from Botsplash as well.