4 Useful Solutions to Common Git Problems
August 26, 2019
These days, most developers are using some form of version control, and the most popular version control system used today is git.
I’ve written a few handy git articles:
- 10 Git Tricks to Save Your Time and Sanity
- Git Bisect is Easy
- A Quick Guide to Hunky Git
- 10 More Git Tricks That You Should Know
This one will be a continuation of those articles, with more focus on pragmatism. In the previous articles, I was sharing interesting things that you could do with git. In this article, I’m going to focus on things that every developer should know how to do.
1. Add a change to the last commit
Modifying the last commit is handy for anyone who has forgotten to stage a change (which is everyone who has ever used git).
This is really simple. All you have to do is stage the file you forgot to stage and then use the
git commit --amend command.
Say I forgot to stage my changes to the README file, this is what I’d do:
git add README.md git commit --amend
I’d be prompted to modify the commit message and then: Tada! The README.md changes have been added to the last commit.
2. Split the last commit into multiple commits
Say you have a different problem. If you accidentally staged something and then made a commit when you intended to make two commits.
All you need to do is walk back by one commit using the
git reset command:
git reset HEAD~1
git add to stage your changes (I recommend using
git add --patch, I wrote an article on it, if you’re not familiar), and commit:
git add --patch git commit -m "This is the first commit"
Then repeat the process as many times as needed:
git add --patch git commit -m "This is the second commit"
One commit has become many. 💥
3. Squash some previous commits into one commit
Every developer should know how to squash commits. This is something you will probably be asked to do if you make a contribution to Open Source and you’ve made a few redundant or poorly-worded commit messages.
I’m going to share a couple of approaches, one that uses
git rebase, and one that doesn’t.
git rebase, you can easily squash the last few commits into one. First, you’ll want to use the
git reset command to move back through the commits you’d like to squash.
You can do this by passing
HEAD~x to the
git rebase command, where
x is the number of commits you’d like to squash together.
For example, if you want to squash the previous three commits into one commit, you’d run the following command:
git reset HEAD~3
If you were to check the log, you’d notice that you are now three commits behind your previous position.
git log will reveal that all of the changes from the previous three commits still exist on your machine, but are now unstaged.
To squash them together into one commit, all you need to do is stage them and commit them:
git commit -am "Some commit message"
Congratulations! 🎉 You’ve squashed three commits into one!
Alternatively, you can use
git rebase with the interactive flag. That would look something like this:
git rebase -i master
Replace master with the branch where you will eventually merge.
git rebase -i will drop you into a text editor that looks something like this:
pick 1eabc17a8 Add data-attributes to container elements pick 90c58b487 Fix react-dom warning Rebase 5f5e140ea..90c58b487 onto 5f5e140ea (2 commands) Commands: p, pick <commit> = use commit r, reword <commit> = use commit, but edit the commit message e, edit <commit> = use commit, but stop for amending s, squash <commit> = use commit, but meld into previous commit f, fixup <commit> = like "squash", but discard this commit's log message x, exec <command> = run command (the rest of the line) using shell b, break = stop here (continue rebase later with 'git rebase --continue') d, drop <commit> = remove commit l, label <label> = label current HEAD with a name t, reset <label> = reset HEAD to a label m, merge [-C <commit> | -c <commit>] <label> [# <oneline>] . create a merge commit using the original merge commit's . message (or the oneline, if no original merge commit was . specified). Use -c <commit> to reword the commit message. These lines can be re-ordered; they are executed from top to bottom. If you remove a line here THAT COMMIT WILL BE LOST. However, if you remove everything, the rebase will be aborted. Note that empty commits are commented out
Now, this can be a little intimidating if you’ve never performed a rebase before, but it’s actually very simple.
To squash these two commits, simply replace the word
pick on the second line with
pick 1eabc17a8 Add data-attributes for styling checkout squash 90c58b487 Fix react-dom warning; non-critical, but annoying
Save the file (if you’re in Vim, this is done with
:wq), and you’ll be dropped into a text editor to write a commit message. When you’re happy, save the commit and you’re done!
Woohoo! 🤠 Now you’ve seen two different ways to squash commits.
You might be wondering why you’d choose to use
rebase when the first method was so easy, that’s understandable. Using
git rebase gives you a lot more control over big changes, and I recommend getting comfortable with it for those problems.
4. Get the most recent changes from another branch
When you work with feature branches, this is something you might be doing multiple times a day!
There are two ways to do this too.
The most common method for doing this is the
git merge command. All you have to do with run the
git merge command with the name of the branch you’d like to pull in changes from. For example, if you’re getting the most recent changes from master:
git merge master
This creates a new commit, which is referred to as a merge commit. A merge commit is basically just an indication that a merge happened, and there is nothing wrong with having these commits in your git history (in my opinion).
However, some people dislike the presence of merge commits in their repository’s history. For those people, you can use
git rebase to catch up with another branch. This is typically how I like to get my feature branches caught up with master:
git rebase master
As long as nothing funky has happened, this will painlessly replay your changes on top of the master branch, catching you up without creating a merge commit.
You can also follow me on Twitter, where I make silly memes and talk about being a developer.