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
- Git – Home: https://git-scm.com/
- Git – Reference: https://git-scm.com/docs
- Git – The Simple Guide: http://rogerdudler.github.io/git-guide/
- Git – Documentation: https://git.wiki.kernel.org/index.php/GitDocumentation
- Git – Understanding Git Conceptually: https://www.sbf5.com/~cduan/technical/git/
Cheers!
-Yohan