Table of Contents
Introduction to Git
In professional development environments, the code is written in teams of developers. From your colleague sitting around the corner to a remote developer living across the globe, anyone could be writing code with you and contributing to the same codebase. The best and most popular way to contribute code to a single codebase is Version Control Systems.
Version Control Systems
Version control systems are systems that allow us to contribute to and manage different releases and stages of a software product without actually having to keep multiple files or folders. They also make development within a team more manageable and less of a pain as developers don’t have to be trading folders, but rather communicate with a single source where all the changes are happening and everything is saved.
There are two types of Version Control Systems: Centralized and Distributed.
Centralized Version Control Systems
Centralized means that the codebase or the project resides in one central place also known as a repository. In order to make changes, people need to have access to that repository and write their code in it.
Distributed Version Control Systems
In distributed systems like Git and Mercurial, things are much more flexible, since they are distributed systems. Which means that everyone has his working copy of the repository that keeps track of his changes and the different releases made by him or by his colleagues.
What is git?
Git is a free and open source distributed version control system designed to handle everything from small to very large projects with speed and efficiency.
How Git works
Most version control systems work by calculating the differences in each file, and then by summing up these differences they can reach whichever version saved, but that’s not the way Git works.
Git functions as a series of snapshots for your file system. Every time you change something in your files committing it, or just saving the state of your project, Git takes a picture of the whole system and saves a reference to it. If there’s a file that hasn’t been changed, then it stores a reference to the previous snapshot. We’ll get to how this is one of the most powerful and enabling features in Git when we dive deeper into the features Git provides.
There are three states for your files to be in when you’re working with Git. These three states are: modified, staged and committed.
When you make changes to a file in your working directory, it is then modified, but these modifications are not stored in the codebase. When you stage the file, these changes are marked to be saved in the next commit. When you commit the file, these changes are finally stored in your codebase.
There’s a fundamental thing to understand about Git, which is the fact that you can run two types of the repository. Usually, you have a local repository on your machine, that is your desktop or laptop, which is defined in your working directory, and a remote repository that is stored on the cloud.
The difference is, you can use the local repository and Git with all its features on your local machine, until and unless you want to share your code with others. It is only then that you need to make a remote repository of your code on GitHub/Gitlab etc and upload your code to that repository.
Once you do that, anyone with the access to your repository can download the code to his/her local machine and contribute to it.
Configuring Git: Getting Started
To get started, visit https://git-scm.com/ and download the appropriate version for your operating system. After running the installation, open Git bash or Git CMD. and CD ( change directory command) into an empty directory of your choice and run these commands. Replace the “John Doe” with your git username and “firstname.lastname@example.org” with your git account’s email id.
$ git config --global user.name "John Doe" $ git config --global user.email email@example.com
Here, git config is a command that asks your computer to make changes in config the file in the .git folder of the root of your system.
--global is a flag you pass to tell git that this is going to be your global git account and you are going to use this account to create git projects all over the computer. You can also use a git account specific for a directory. You can find details more about the initial setup and the necessary commands here.
Basic Git Commands
Now that you’re all set up and ready let’s run a
git status command first.
You’ll get an error that looks something like this. And of course, it’s natural, as we have not initialized a git repository inside that folder which represents our working directory.
In order to initialize Git, we will run the command
Now, if we run
git status again we should see that we’re on branch master (we’ll talk more about branches in a minute) and that this is the initial commit, and there’s nothing there to commit, as the project is empty for now.
Let’s create a text file and start creating some changes to simulate a real-world project. I’m going to do so inside of visual studio code, you can pick any IDE/editor of your choice, they all have similar features, but VS code is my favorite. Let’s add some text to the file:
Now, when we run the git status command we’ll notice that we get an untracked file.
This means we have some content inside of the project in the modified state and that we haven’t added yet to the staging area.
To add the files created and edited in the previous step to the staging area we will run the command:
git add hello.txt
If you have more than one file that you want to add the staging area, you can also run
git add . which adds all files in the modifying area. Run git status again and you’ll find that the text file is now labeled as changes to be committed.
Now for the last step, let’s run the commit command to commit these changes. One thing about the commit command though, it has to be accompanied with a message, the reason behind that is that Git tries to enforce best practices, and it wouldn’t be hectic inside of a single project if changes were being made without a word of description said. So this is how we will run the git commit command:
git commit -m “added hello.txt”
In the command line, it says that one file was changed with 3 insertions, which are the three lines we’ve written so far.
Since all the collaborators will be reading your commit messages, it’s important you learn how to write them succinctly: Git Commit Messages
So everything works fine, but now if we want to share the project with a colleague and bring them on board we need to place our project somewhere on the cloud where other teammates can access it. We’re not making it centralized, as everyone is going to have his working copy, but there needs to be a focal point to pipeline the project changes. So let’s go and create a repository on Github.
Give it a description and a name, I’ll call it Hello Git.
When the new repository’s page opens up, you’ll find an option to push an existing repository which is exactly what we want to do.
So we’ll follow the commands and write:
git remote add origin [repository’s link]
git push origin master
The first command links the remote repository we created to our local one under the name of origin, and in fact, you can name this anything you like as long as it’s clear enough. The second command pushes the files we have on the master branch to the origin repository. So by running these two commands, our repository would end up with the text file we created on the repository.
Now that your code is pushed to a remote repository, anyone with access/permissions to your repo can download the code and start editing it.
There are two ways to bring a remote repository to a directory on your local machine. You can either download a zip of the entire project or you can clone(duplicate) the repository to anywhere on your system.
To download the repository with the full history of the project and nearly every change that was ever made, we use the command
git clone "url of the repository"
Just navigate to the place where you want to clone the repository and run
git clone "link of the remote repository"
Usually, you don’t need to write this entire command on your own. Just find the repository you want to clone (for ex. On Github), click the green “Clone or download” button and you can see the option to download the zip or copy the Url and replace it in the command “
git clone "link of the remote repository"
Now let’s dive into a very critical part of Git. Let’s say you’re working with a colleague on the same project and he makes some changes to the repository on the same file you’re working on.
(To mimic this behavior, I am going to clone the project I pushed in the last step, to another directory of my system using the git clone.
This way we can mimic two people collaborating on the same project.)
I’ll open another instance of VS code and will head to the directory where I cloned the project, there I’m going to change the word ‘first’ to ‘changed’ and then go through the steps we went through earlier to push the project, that is: add, commit, then push directly.
Note: We will not need to run the git remote add command since we cloned the repository and it’s already remotely added.
git merge and git fetch
There are two ways that we can bring this change into our main project and we’ll go through both. The first is through the
git merge command, which is going bring the changes and merge them into our files.
The other way is to fetch the changes first and then merge them into the files we have. So it’s basically running two commands. But what if we only want to fetch the changes then selectively merge them when we want to?
(Before trying this out we need to have some changes in our local files as well as in our remote repository files. To mimic this we are going to perform some additional steps.)
Git allows us to visit the state of our files at the time of a previous commit. If you want to head to a previous commit without making a change you can run the <code>git checkout “commit hash” </code>command and pass the appropriate commit hash. You can view all previous commits with hashes using
git log command.
You can also find these by pressing on the commits tab on your repository on GitHub. And It will look something like this.
You can copy the hash of your previous commit from here and paste in the command prompt. It will look like this.
Now we will run the following command.
git reset --hard "commit hash"
This forces our remote repository projects files to be the state they were in, when we made that particular commit, regardless of what we have now.
When we do so, we’ll receive the message that we are one commit behind. Meaning git counted this action as another commit and now you have some changes in your remote repository.
Let’s now fetch these changes without merging them into the directory and selectively doing the merge by ourselves. To do so, we’ll run the git fetch command as follows:
git fetch --all
This will fetch all the commits that we don’t currently have, but without merging them or affecting our workflow. So let’s actually add a few words in our text file, I’ll add the words ‘we made’ after the word ‘project’ on the third line.
I’ll then add and commit these changes. Now our local repo has a commit that our remote doesn’t have, and our remote has a commit that our local doesn’t have. What to do then?
Well, let’s try to use the
git merge command and see what happens. We get the message that we have a “Conflict”, the automatic merge didn’t work and we need to fix these conflicts by ourselves.
On my VS code, I can clearly see these conflicts and the actions I can take to resolve them. If you’re not using VS code, do not worry, most editors support conflict management.
I have 4 options, ‘Accept Current Change’, ‘Accept Incoming Changes’, ‘Accept Both Changes’ and ‘Compare Changes’.
I will choose to accept both changes to showcase the different options, but of course, in this situation, you should choose the most appropriate. Now, this is how the text file looks like:
At this stage, what you ideally do is click on either “Accept Current Change” or “Accept Incoming Change”, depending on what changes you want to keep and what you want to discard.
Once done, we’ll finalize the merge by committing our changes.
We’ve mentioned branches a lot so far, and it’s about time we explain what branches are. Branches are one of the most powerful features in Git.
There are many use cases for branches, for example, if you’re working on a software with different releases, development of the different versions shouldn’t be going on the same pipeline. Branching is basically diverging the flow of changes in a certain direction.
Another more general example is a production, testing, and development branches, production would only contain stable releases, certain development commits would have to diverge to testing before they’re merged with production and so forth. It’s a much-needed practice in the software world.
The reason why Git is so good at branching is that it’s using snapshots and calculating differences, the process of creating a branch then becomes much simpler and faster than it is in other systems like SVN where such operation is a headache.
So let’s start a new branch on our project, we can simply do so by using the git branch <branch name> command which will go ahead and create a new branch with the name we choose.
We can then enter that branch by using the following command:
git checkout "branch name"
I’ll go ahead and edit branch ‘testing’ with a change in the text file as follows, and I’ll commit this change. You can run
git commit -a to commit all the unstaged files and commit them with the same command.
Here you can find some best practices for branching: Git Branching Model
Pull requests are used to discuss some piece of code with the other collaborators before finally merging the code. They can be useful if you are contributing to an open source project or have some people working remotely. You can specify which branch you’d like to merge your changes into when you create your pull request.
To create a pull request, first, you need to create a new branch from the branch you wish to merge into. Next, you need to commit some changes and push this branch to Github.
You will find the “New pull request” button on the repository page. On clicking it, Github will show you the following prompt:
Here, you can select the branches and leave a comment (optional). After a pull request has been created, Github gives you (the project owner) the option to merge or close the pull request.
If an automatic merge cannot be performed online, you will need to take a pull and merge them locally. Github has a “command line instructions” button to help you out.
Version control is a requirement of most software engineering and a daily practice for developers. It’s a tool that you’ll definitely need and the only way to get good with it is using it.
The official Pro Git book is free and it’s resourceful so check it out. There’s also a Cheat-Sheet found on the official GIT website that lists most of the git commands that you’ll be using, so it’s a good reference especially when your beginning your journey with Git.
Ready for in-depth Git tutorial? Here are the programming community best Git tutorials and courses: https://hackr.io/tutorials/learn-git?ref=blog