This is the 4th chapter of the “Git – Simplified” course, in which we will go through Git from zero to hero. If you are just starting out with Git I highly recommend you to go to the 1st chapter in order to learn the basics of Git.
Table of Contents
Topics in this chapter
In this chapter we will go through the following topics:
- Git reset soft\hard\mixed
- Undoing our changes using ORIG_HEAD
- Moving files between branches
- Cherry-picking
- Git merge-base
🎤 Webinar recording (Hebrew)
You can find the presentation (ppt file) at this link. The recorded session of the webinar is live! you can view it here:
Git reset
The git reset
command changes our commit history by allowing us to discard commits and either remove the files, move them back to the staging area, or just leave them as-is.
When using the reset
command we can actually manipulate the history and remove commits from branches.
Let’s try it out!
Our example repository
For this example we have a repository with only 2 commits:
The two commits only modify a file called a.txt
which have two lines, that each line is associated with a commit:
Now that we understood this simple repository, let’s play with the reset
command!
Soft reset
Soft reset allows us to undo commits but move the files back to the staging area. Think of it as a way to clear your history but leave the files as-is.
A good example of doing a soft reset is as if you were to regret your last commit, but still, want your files. But first, let’s see the command:
$ git reset --soft COMMIT_HASH # Undo all of the commits until you reach this one, and move the files back to the staging area
If for example, we want to undo our last commit, we can use HEAD~
instead of the COMMIT_HASH
, the HEAD~
actually tells git ‘refer to the previous commit’. This is the same as putting the previous commit.
When you want to undo the last commit but move the files back to the staging area, use the following command:
$ git reset --soft HEAD~
Let’s take a look at this in action:
Hard reset
Hard reset allows us to undo commits, and also remove the files they are associated with entirely. This means that our history of commits will be discarded from our branch, and also our files.
Think of a hard reset us “I don’t want any of these changes, and I’m not interested in any of the files I had”. Let’s undo our last commit with the git reset --hard
command:
Undoing our changes using ORIG_HEAD
If it ever happened to you that you “fucked up” your graph, add a commit, or accidentally removed commits (even with --hard
) you can always undo them using this command:
$ git reset --hard ORIG_HEAD # Undo our last git command, and return the graph to it's previous state
The --hard
is used to tell Git “Return the state of my branch to be exactly the same, including the files”
Let’s see it in action:
Mixed reset
Mixed reset is the same as --soft
, but the difference is that files are not moved to the staging area, rather just stay as they are. They are not being touched or modified. It is what is done by default when using git reset
without any parameters (no need for --mixed
).
In our case, if we use the command:
$ git reset HEAD~
The 2nd commit will be removed, but the file a.txt
will still have the second line. It won’t appear in the staging area (won’t be ‘Staged for commit’).
Moving files between branches
Has it ever happened to you that you need a specific file that appears in a different branch? Maybe you even needed a folder?
Let’s even take it a step further: You want to remove a branch but want only a specific file. How can you do that? well this one is easy, you can use the git checkout
command to checkout files from different branches.
Let’s use the same repository we have and do the following:
- create a new branch called “tmp”
- add a new file called “important.txt” and commit the changes.
- Then, we will move back to the master branch and “take” the file from the “tmp” branch to our branch.
Let’s see it in action:
The command to checkout a specific file from another branch is the following:
$ git checkout BRANCH_NAME FILE_PATH # copy a file from a specific branch to ours
Cherry pick
What is a git cherry pick
? think of “cherry-picking” as a way of telling Git you want to take a specific commit from another branch.
A commit will only contain the “diff” of all of the files, but when we cherry-pick, we get the entire file contents of that specific commit and not only the diff.
Live example
In this specific example, we can see two branches: master
and feature/auth
.
The master branch has only one commit of the file a.txt
called: “first commit”. The feature/auth branch has two commits, one called: “second commit”, and the third one called “third commit”.
We want to take only the “second commit” from the feature/auth branch. We can do it using the following command:
$ git chery-pick ad2fa6137 # Take only the second commit (ad2fa6137 is the commit hash), we do not need the "third commit"
Here is a live example in which you can see the changelog of all of the commits and the cherry-picking actually adding the “second commit” changes to the “master” branch:
Git merge-base
The git merge-base command allows us to find the last common commit from two branches\commits. This will allow us to see from “where” our branch exited.
Let’s take a look at this graph:
This graph is a bit “complicated” and it’s hard to see which branch exited from each. First let’s start with the easy part: we can see that feature/google-auth
and feature/auth
has a common commit which it’s description is called “commit from feature/auth”. We can guess that the branch feature/google-auth
exited from feature/auth
. Let’s check it out:
$ git merge-base feature/auth feature/google-auth
db3c0bf371b14702e86e01e3754708198755b4a7
Now if we take a look at the graph we will find that this is the correct commit:
To Summarize
In this guide we learned about Git reset, moving files between branches, cherry-picking and merge-base. These tools will help you through your “journey” with Git and can be helpful in the future.