5 Git Commands to Save the Day
Git is an extremely useful tool that has become almost ubiquitous with programming itself. Unfortunately, learning it can be a bit overwhelming with the seeming endless git documentation. Eventually everyone masters manipulating and merging branches on small projects but as repositories grow in size as well as contributors things can get complicated. Fortunately git is excels on large projects and has many advanced commands which allow you fix almost any mistake you make, the key is knowing which commands to use in which situation. That being said, let's go through the git commands I find myself using all the time to fix my mistakes.
Undo
Most people make mistakes and due to this most programs include and undo button. Git’s undo button is known as reset. There are two style of reset, a soft and hard reset. A soft reset will remove the specific commit and place those changes back into the staged area where as a hard reset will delete the specified commit. In Figure 1 the commit is specified relative to the head of the branch instead of by its commit ID.
git reset --soft HEAD~1Figure 1: Soft undo of the last commit
Amend
Often there is the case where you have made a commit and then found a typo or style change that is related to the previous commit. Making another commit with these kind of changes does not add value the git log, instead it would add clutter. Instead, using the commit amend option keeps the log clean by well, amending the current staged changes to the previous commit. Adding the --no-edit
option keeps the same commit message, this can be removed if you want to change the message.
git commit --amend --no-editFigure 2: Amend staged changes to previous commit
Stash
Sometimes your working on a code change and you want to switch gears to work on something else or maybe reference some code on a different branch. You could commit your half completed work but the better move would be to stash it. Stashing allows you to store staged changes locally so you can switch branches, work on some other aspect of the change, or even move your stashed code to another branch without git complaining.
In Figure 3 the current changes are first saved to a stash via git stash save
with an optional message. At this point git will let you switch branches as your changes no longer exist on the current branch. To re-apply the changes from a stash you can first, list all the available stashes with git stash list
. From this point you can apply the latest stash to the current branch and delete that stash with git stash pop
. You can specify a specific stash from the current stashes by passing its location on the stash list For example, in Figure 3 the 4th stash in the list is being pop. Alternatively, if you would like to apply a stash without removing it from the stash list you can use git stash apply
.
git stash save "optional message for reference"
git stash list
git stash pop stash@{3}Figure 3: Stash and pop changes
Cherry Pick
Imagine you have been working on a piece of code when you suddenly realize you are working on the main branch instead of a feature branch like you intended. You do not want to delete all the work you have done but you also want your changes to be reviewed prior to merging into main, this is a perfect case for cherry pick. Cherry pick allows you to pull a commit from one branch to another by specifying its commit ID.
First use git log -1
to list the last commit in order to get that commits ID. Next create and checkout a new branch with git checkout -b new-branch-name
and then cherry pick that commit to this branch via git cherry-pick commit-ID
. The change has now been added to the desired branch but the main branch still be cleaned up so switch back to that branch and then delete the last commit with git reset — hard HEAD~1
.
git log -1
git checkout -b new-branch-name
git cherry-pick commit-ID
git checkout main
git reset --hard HEAD~1Figure 4: Cherry picking a commit to a different branch
Rebase
When working in a continuous integration environment developers are constantly pushing code which is great but it quickly makes the branch your working on out of date. You want to ensure your changes do not break something that has already that has already been merged and it is desirable to keep your changes at the top of the log; this is where rebasing is extremely useful. Basically, rebase pulls your feature branch to the head of the master branch as if you just created that a branch.
git rebase origin/main -i
git push --force-with-leaseFigure 5: Rebasing and force pushing a feature branch
In Figure 5, git rebase
first specifies the branch to rebase against, in this case origin/main
and then includes the -i
flag. This lets you interactively rebase via your IDE such as VS Code; assuming it is configured via git config --global core.editor
. Figure 6 shows a sample interactive rebase using GitLens where you can squash commits into another, edit the commit message, drop commits, or even reorder your commits. These are all helpful to clean up this features git log to add clarity.
The final line of Figure 5 pushes the recently rebased feature branch to its remote repository with the --force-with-lease
flag. At a minimum the --force
flag is required to push to Github since the rebase rewrote the git log so it appears to be a different branch. Forcing will basically overwrite your remote branch which is desirable in this case. The --force-with-lease
flag will not push your local branch to the remote branch if it notices that the remote branch is ahead of what you are trying to push. This is helpful if your working on that branch with multiple developers.