Git – Simplified (Chapter 4)

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.

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:

The “first commit” line was done on the first commit, and the second line “second commit” was done on the 2nd 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:

Pay attention that the last commit is removed, and the a.txt file is remained the same but moved back to the staging area

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:

Pay attention that the hard reset removed the second commit and the a.txt file changes were also removed.

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:

In this example, we remove the last commit and then undo it using reset –hard ORIG_HEAD

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:

  1. create a new branch called “tmp”
  2. add a new file called “important.txt” and commit the changes.
  3. 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:

We can see that db3c0bf3 is the correct commit which is common between the two branches

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.

Leave a Reply

Your email address will not be published. Required fields are marked *