Skip to content

Git Notes

Versión en español de esta publicación.
Git is a very robust and flexible source code control system that allows code versioning in a simple and fast way, it was created by Linus Torvalds with the idea of replacing the sotware that was used maintain the code versioning of the Linux kernel which converted from open source to closed source.

Git uses a distributed repositories paradigm which means that every client has a complete copy of the whole code repository which makes working with the code be possible even without a network connection, this is the main difference between the centralized systems like subversion which requires a network connection in order to checkout files for editing and/or deleting.

This guide does not pretend to be a complete reference of git commands and descriptions, that guide already exists, instead, this guide pretends to help people that wants to start learning how to use git as a source code control in a fast manner and want to start to be productive using this tool as soon as possible.

Configuration

Basically, the first thing to do after installing git is to configure its global options in order to use git effectively. First we need to increment the post buffer size to be able to post large files into our repository. We do that in the following way

# increment git post buffer to 500MB
git config --global http.postBuffer 524288000

Next, we need to establish a credential helper cache of 10 hours to not have git to be asking for credentials every pull and/or push we make to our repository

# cache credentials for 10 hours
git config --global credential.helper cache
git config --global credential.helper "cache --timeout=36000"

After that we setup some console output color just to make the shell more attractive 🙂

# and give some love to the git output
git config --global color.ui auto
git config --global color.branch auto
git config --global color.diff auto
git config --global color.status auto

After that, we need to set some identity information like the user name and email, this data is going to appear in each commit we do to our repositories

# add commit global information
git config --global user.name "Yohan Jasdid"
git config --global user.email yohan.jasdid@gmail.com
git config --global push.default simple

Then, we have the mergetool configuration, the merge tool is the tool used to resolve any issue at the moment of making any merge between branches, this tool usually shows the differences between local and remote files and allow us to resolve any conflicts in a visual and easy way, in this case I use kdiff but of course there are many good merge tools that you can use

# configure merge tool global setting
git config --global --add merge.tool kdiff3
git config --global --add mergetool.kdiff3.path "/usr/bin/kdiff3"
git config --global --add mergetool.kdiff3.trustExitCode false

After the mergetool we setup the diff tool, this is the tool that will be used when showing differences between revisions, here again I’m using kdiff

# configure diff tool global setting
git config --global --add diff.guitool kdiff3
git config --global --add difftool.kdiff3.path "/usr/bin/kdiff3"
git config --global --add difftool.kdiff3.trustExitCode false

Lastly, I added a setting to disable the SSL certificate. This was just because I’m using a self signed certificate in my source control server and git is unable to verify the authenticity of the certificate, I should get rid of this setting once I use a letsencrypt certificate

# disable ssl checking (not recommended for global)
git config --global http.sslVerify false

Cloning Repos

Cloning a repository in git means that we will obtain a full copy of the remote repository in the local machine, to do this we use the following command

# clone a repository
git clone https://my_repo.git

Branching

Git is based on the concept of branching, all branches basically have a parent which they’re based on, a branch can be seen as a snapshot of the current repository at the moment of creating the branch. The new created branch is intended to contain a set of code that can be integrated on the main branch or any other branch.

# create branch
git branch <branch_name>
 
# create and move to branch
git checkout -d <branch_name>

There are 2 types of branches, local and remote branches. Once a local branch has been created it need to be pushed in order to create the remote branch mapped to the local branch. To push the local branch we use the following command

# send local branch to origin in case the branch is just local and start tracking remote branch with local branch
git push origin <branch_name>

And to push the local branch and map it to a remote branch we use

# send local branch to origin and map with remote branch
git push --set-upstream origin <branch_name>

Once we have created branches in our repository, we may need to delete some of this branches, to do that we can use the following commands, to delete a branch safely or forcedly

# delete local branch (safely)
git branch -d <branch_name>
 
# delete local branch (forced)
git branch -D <branch_name>
 
# delete remote branch
git push origin --delete <branch_name>

If we want to see a list of local or remote branches we can do this by executing the following commands

# show local branches
git branch
 
# show all branches (local and remote)
git branch -a

After using or deleting branches is necessary to do a clean up and update the references to the current branches. We can do this by using the following commands

# Update references to remote branches, if remote branch is deleted then with this command the branch list gets updated
git remote prune origin

Once we have work with branches, we probably have the need to make changes in branches that are available remotely and that are not owned by us. To do that we first need to retrieve the branch locally so we can make the desired changes. There are some known ways to do that , the two most used ways are to retrieve a remote branch and map it to a local branch that has a different name and to retrieve a remote branch and map it to a local branch with the same name respectively, to do that we use the following commands

# Checkout a remote branch and track it locally (it is possible to use different names for local and remote branches)
git checkout -b <local_branch> origin/<remote_branch>       # Will create <local_branch> and track origin/<remote_branch>
 
# Checkout a remote branch and track it locally (it is NOT possible to use different names for local and remote branches)
git checkout --track origin/<remote_branch>                # Will only create '<remote_branch>', not a branch with a different name

There are times when something goes wrong in a local branch and we just want to simply regenerate the local branch based on the remote branch, to do that we use the reset command in the following way

# Force replace local branch with remote branch
git reset --hard origin/<remote_branch>

Also, there are times when is useful to simply delete the local branch and create it again using the remote branch, to do that we use this commands

# Recreate branch locally
git checkout master
git branch -D <local_branch>
git checkout --track origin/<remote_branch>

Add

Once we have understand and mastered branches and is time to do a code change or simply develop a new feature in the system, we proceed to make our changes, git is smart, at the moment we do our changes in a branch git automatically recognizes them and it display them when we type the following command

# show status of modified files detected by git
git status

In git there are different states of the files, there is a state called untracked, that means that git detected a fie that had never been tracked by git, there is also the tracked state, that means that git already tracked changes for that file but is in a modified state at the moment. Wherever the state of the file change is, if we want to integrate the change into our local branch and then into the remote branch, we first need to add the change to staging, the staging area is the area that identifies all the file changes we want to add to the repository, to add a file change to staging we use the following command

# adds a file to staging
git add <file_name>

There are probably many changes that we want to add to staging at the same time at once, and to avoid being adding changes one by one, we can use pattern matching and add a bunch of changes to staging at once like this

# add all files with pattern match to staging
git add *
 
# add all files with pattern match to staging
git add .

And lastly, we can add only the untracked file changes to staging with the following command

# add all files that are untracked to staging
git add -u

Commits

Once we have added a change or group of changes to staging, we can proceed to make commits, a commit is basically a change or a group or changes encapsulated in a sort of bag with an ID that is a hash that git generates, to generate a commit or “bag of changes” we can use the following commands

# Standard commit with simple message
git commit -m "Message of commit"
 
# Commit with message and description - this commit is intended for when having a title and a long description
git commit -m "Title of commit" -m "Detail message of commit"

Pushing

Once we have our commit of changes or group of commits of changes in place in our local branch, what we want to do now is to send these changes to the remote branch to make them publicly available, this is what the push command does for us, is worth mentioning that the push command can push a branch with changes to the remote repository or just a sets of changes in a branch that already exists remotely, we do that by using the following commands

# Send all changes that are already in commits to remote repository that is tracked
git push
 
# Send local branch to origin in case the branch is just local and start tracking remote branch with local branch
git push origin <branch_name>

Revert

There are cases were for whatever reason we decide to undo all the local changes we already did to a file or group of files or just undo all the changes we made to all files, to this effect we use the following commands

# revert a file to a commit state
git checkout <commit_hash> path/to/file
 
# discard file changes 
git checkout path/to/file
 
# discard file changes with pattern matching
git checkout .

Stash and Clean

There are also some times when we start making changes and developing new functionality in the system and we realize that we were not doing this changes in the correct branch, what can I do then?, we use git stash!. The stash commands allow us to save a change or group of changes in some kind of temporary location which allow us to switch to another branch and restore all changes, nice!, we do this by using the following command

# when having changes in different branch and want them to move to another branch use git stash
# git stash saves changes to a temporary location and applies them with a command
# sample workflow to move changes from one branch to another
git checkout <branch_name>       # move to a branch
<make some changes>
git stash                        # stash the changes in temp location
git checkout <another_branch>    # move to a different branch
git stash pop                    # apply the last stash changes to <another_branch> and drops the stash from the stack

Git stash also allows to save one set or many set of changes, to see all sets of changes available by git stash we use the following command

# shows a list of stashes. there can be more than one stash in form of a list
git stash list

There are times that the local and remote branches diverge, in this case what we want to do is regenerate the local branch, and we can do that with the reset commands in the following way

# when remote and local branches had diverged you can use reset to reset your local branch
# and sync with the remote branch
git fetch
git reset --hard origin/<branch_name>

There are other cases that we added a bunch of new files to the branch that we realize that were not needed to be added and we want to remove them, in that case we can use the clean command like this

# delete untracked files - show untracked files to delete using the -n option:
git clean -f -n
 
# delete untracked files - beware: this will delete files
git clean -f

We can also discard all added changes with the following command

# remove all changes in current branch and checkout branch changes
git checkout .

Log and Show

Once we have branches, commits, pushed commits and a change history, we may regularly need to query our repository for the list of latest commits done. This is useful to find a specific change or just to see who made some change. To do this, we use the log command which is very useful, we can show a list of changes with descriptions like this

# show commits history with descriptions
git log

And if we want to look for all the commits done by a certain author we can do this

# show commits history with descriptions of a certain author
git log --author=bob

To show the commit history in a one line per change and/or with decoration format we can do the following

# to see a very compressed log where each commit is one line
git log --pretty=oneline
 
# to see an ASCII art tree of all the branches, decorated with the names of tags and branches
git log --graph --oneline --decorate --all

To show only the modifies files, we do

# see only which files have changed
git log --name-status

And to display the command help we use

# show help for log
git log --help

To show the differences between commits between branches we do

# show commit difference between branches
git log master..<branch_name>

And to show the details of a commit, we do

# show commit diff details
git show <commit_hash>

Diff

There is another useful command called diff that allow us to view all differences between branches or commits. We use this command in the following way

# show changes between source and target branches
git diff <source_branch> <target_branch>
 
# show changes between commit's ancestor and commit
git diff <commit_hash>~ <commit_hash>
 
# show modified files between branches
git diff --name-only <source_branch> <target_branch>
 
# show file differences between branches
git diff --name-status <branch1>..<branch2>
 
# show file content differences between branches
git diff <branch1> <branch2> -- <file_path_name>

Tags

# it's recommended to create tags for software releases. this is a known concept, create a new tag named 1.0.0 with this command
# the 1b2e1d63ff stands for the first 10 characters of the commit id you want to reference with your tag.
git tag 1.0.0 1b2e1d63ff
 
# Show tag list
git tag
 
# Create a breanch based on tag
git checkout -b <branch_name> <tag_name>

Escenarios

# Usually at home in my server I'll do the following
git checkout development   # Move to dev branch
Do some programming.
git status                              # to see what files I changed.
git diff [file]                           # to see exactly what I modified.
git add .                               # to stage all changes
git commit -m [message]     # to commit.
git push                               # push changes to branch
 
# Steps to fast forward merge from development branch into master and return to development to continue working
git checkout master && git pull && git merge development && git push && git checkout development

References

Cheers!
-Yohan

Leave a Reply

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