Git, a quick and simple guide.

This guide will give you a solid base to start working with git, or a reference for the experienced developers.

Angel Ruiz
8 min readAug 15, 2020
Photo by Yancy Min on Unsplash

Git created by Linus Torvalds in 2005 is one of the most popular distributed version-control systems used nowadays. Git helps us to create and maintain repositories, get track of versions and enable comparison between them, and help to manage changes made to the different files in the repositories; which maintains accountability and promotes collaboration among developers.

Setting a repository

It’s recommended that first of all you assign a username and email.

$ git config --global user.name <name>
$ git config --global user.email <email>

There a three different ways to start a new repository:

  • From scratch
  • From an existing project in your local machine
$ git init

To add a remote server for these new repositories use:

$ git remote add <remote>
  • From an existing project in a remote repository (i.e. GitHub)
$ git clone <remote>

When creating a git repository, a .git directory is created where all the committed artifacts and metadata is stored.

Basic commands

It’s important to know that git provisions 3 different areas that are the core of the repository. The first one is the working directory which is the root of your Git project, here the files go through any change that the user performs. The staging area, also known as index, is where changes are built up, in this area all files are converted to tracked files by git. And the last one called as the commit area safely stores all files already committed. As seen in the image below, there’s another area called Remote Repository, that represents the remote location of the origin repository.

Git areas and principal commands.

To move files between the working directory to the staging area:

// to add only one specific file 
$ git add <file_name>
// to add all files in working directory
$ git add .
// if you want to unstage a file
$ git restore --staged <file_name>

Once the desired files are in the staging area, commit them using:

$ git commit -m <commit_message>

If there any files that are already tracked by git (indexed), a express commit can be perform, that will directly move the changes from working directory to the commit area:

$ git commit -am <commit_message>

To view the status of the files in working directory and staging area, a simple command is used:

$ git status 
$ git status -s

The log git command, helps to keep track of the different commits made to the repository:

$ git log// to view a compact version of the commit history
$ git log --oneline
$ git log --graph

There are scenarios where we accidentally commit a change that wasn’t intended to be present in that commit, or we simply introduce a bug to the source code that is impacting the correct behaviour of all the code. For this the revert command comes in handy:

// revert the last commit
$ git revert HEAD
// revert to and specific commit id
$ git revert <commit_id>

If it is desired to remove files in the staging area or revert all changes made in working directory and staging area:

// only for staging
$git reset
// both, working directory and staging
$ git reset --hard

Fetch command retrieves all updated files from the remote repository (origin) into the commit area but it does not merge them with your current branch, this is used to keep to repository up to date.

$ git fetch origin master

Pull command retrieves all the updated files from the remote repository into your working directory. Pull is the combination of two commands: fetch and merge.

$ git pull origin master

Push command sends the committed changes to the remote server.

$ git push origin master

Diff

When working on projects, specifically with other team members involved, a lot of changes are made through the different files in the repository. In order to display modifications in detail between versions of these files, a diff is needed.

// diff working dir - staging
$ git diff
// diff working dir - commit area
$ git diff HEAD
// diff staging - commit area
$ git diff --staged HEAD
// diff specific commit - commit area
$ git diff <commit_id> HEAD
// diff commit area - remote
$ git diff master origin/master
// diff branch - commit area
$ git diff <branch_name> master

Branches

When reviewing the commit history in our repository, a HEAD label is shown in the list of commits, this reference points out to the last commit in the branch that is currently being used. It serves as a starting point from where the next commit is going to take place.

Commit history.

If there’s the need to check how the repository was before certain commits, we can use the checkout command to navigate to the state of our repository in a specific commit. When doing this a new reference is created known as the “detached HEAD”, changes can be made,committed and discarded without impacting the actual repository.

$ git checkout <commit_id>
Detached HEAD

If we committed changes in detached HEAD that we want to retain, the creation of a branch is needed. A branch is used as another independent line of development, that is different from the master branch, it’s commonly used for bug fixes, addition of new features, etc. As seen in the image below, each branch has its own HEAD reference.

Representation of a master branch and feature branch
// list all branches
$ git branch -a
// create a branch
$ git branch <branch_name>
// rename branch
$ git branch -m <branch_name> <new_branch_name>
// delete branch
$ git branch -d <branch_name>
// to move between branches
$ git checkout <branch_name>

Once the work is finished in the features or fixes branches, this new code needs to be part of the existing code in the master branch. This is accomplished by the merge command. There are 3 different ways in how git merges the branches. The first one is called fast forward merge, this is possible when there exists a linear path from the feature branch to the master branch’s HEAD. This merge will only move the HEAD reference of the master branch to the former feature branch’s HEAD and doesn't create a merge commit.

// in master branch
$ git merge <branch_name>
Fast forward merge

The second type of merge is known as no fast forward merge, this is identical to fast forward, it needs a linear path from the feature branch to the master’s HEAD reference; but the the main difference is that this option literally merges the specific branch to the master’s, keeping the branch topology, hence creating a merge commit as shown below.

// in master branch
$ git merge --no-ff <branch_name>
No fast forward merge

The 3-way merge is performed when there exist new commits in the master branch that the feature branch is not aware of, this means that the linear path from the branch to the master branch’s HEAD is lost. This unifies the work done in two branches.

3-way merge

When merging branches using the 3-way merge is very common that conflicts are presented. A conflict is when a merge is executed on 2 branches, and in both of them, there are changes in the same parts of the files. If a conflict exists, the merge is stopped before creating the merge commit, and the conflict needs to be resolved manually. After resolving the conflicts , it’s necessary to commit the changes by yourself to generate the merge commit.

Amend and rebase

The amend command lets us combine changes in the staging area with the last commit, without generating a new entirely commit. This is very helpful when dealing with premature commits where we can easily forget to staged one or various files. Although, this command aggregates the stage changes to the last commit, a new commit is created with its own new reference (commit id), and the previous commit reference is lost. Also amend command is used to change the most recent commit message.

// amend staged changes changing commit message
$ git commit --amend -m <message>
// amend staged changes without changing commit message
$ git commit --amend --no-edit

Rebase is the action of moving the entire feature branch to the HEAD reference of the master branch; this is not a merge, since the project commit history is rewritten by creating new commits for each commit previously unknown by the feature branch. The rebase is commonly executed in the feature branch, and this will keep a linear history of commits. After this a merge to the master branch could be executed.

// in feature branch
$ git rebase master
// if conflict exits
$ git rebase --abort
// when conflicts are solved
$ git rebase --continue
Rebase

Tagging and stash

When a project reaches a milestone in its development, a good practice is to mark this specific point in the repository history, these markers are called tags. Tags are usually used to identify stable releases and to keep track of the project’s versions. There are two types of tags: lightweight and annotated. Lightweights are just like pointers to specific commits in the history, while annotateds are objects containing tagger’s name, email and date.

// lightweight tag
$ git tag <tag_name> <commit_id>
// annotated tag
$ git tag -a <tag_name> -m <tag_message> <commit_id>
// to compare tags
$ git diff <tag1> <tag2>
//to update tag
$ git tag -a <tag_name> --force <commit_id>
// to delete tag
$ git tag <tag_name> --delete
// to push tags to remote
$ git push origin --tags
// to push only annotated tags to remote
$ git push origin --follow-tags
//to delete tag in remote
$ git push origin :<tag_name>

Stash is the action to save snapshots of the changes you have made in your working directory, so you can start working on something else, without losing your previous work and then come back later and retake the work you left unfinished.

// to stash
$ git stash
$ git stash save <message>
// to list all stashes
$ git stash list
// to see files stashed (stashes are listed as "stash@{1}")
$ git stash show <stash>
// to retrieve stashed files
$ git stash apply <stash>
// to delete stash
$ git stash drop <stash>
// to retrieve and delete stash
$ git stash pop <stash>
// to delete stashes
$ git stash clear
// to create branch from stash
$ git stash branch <name branch> <stash>

Conclusion

The commands and their basics options presented in this article are at least the basics you should know when working with Git. Git is a powerful and great tool used and known for almost all developers. So I recommend you to go ahead and explore deeper about the different commands and the advanced options they present.

--

--

Angel Ruiz

I write about software development, AI, ML and other stuff that I find interesting. || Software Developer and AI-ML enthusiast