All You Need to Know About Git!

Amruta Mulay
12 min readJun 12, 2022

Version Control Systems (VCS)

Version Control System records changes in your file/project, and then you can recall any specific version of the project later. They allow us to go back in time and get previous tapes of the project. This also helps in comparing changes over time. Nowadays, there are a couple of different version control systems, but the most popular one is Git. Git even facilitates collaboration, which helps other developers work on the same project.

There are two types of version control systems:

Centralized Version control systems have a single server that contains all the different versions of projects so that developers can collaborate, but actually that type of version control has some downsides. If you do not have a network connection, then you won't be able to get access to versions. Also, if the server collapses, we may lose all our data for some reason.

In a distributed version control system, we save versions of our project locally on different computers and also on servers, and each copy of the project is a full backup of all your data. Thus, even if anything happens to the server, we still have a full backup of the data locally. Also, it is not necessary to have a network connection to save various versions of your projects.

GIT BASICS

pwd : Shows the current directory

cd filename : Takes us to the current directory

mkdir foldername : Makes a folder with the given name

touch index.html : Creates the file of HTML extension

ls : Shows all the including files of the directory

mv index.html above.html : replaces the filename index.html to above.html

The first thing to be done to create a git repository is to get initialization. We use the command ‘git init’. This creates an empty Git repository or reinitializes an existing one.

The ‘U’ shown in the code editor after the initialization says that the files are untracked and need to be added to track them.

Git status (shows the working tree status) gives us some useful information about the status of the files in our local machine. It also gives us an idea about which branch we are on and whether we have done any commits yet.

Each file in your working directory can be in two states: Tracked or Untracked.

Tracked Files: Files which were in the last snapshot

Untracked Files: For files which were not in the last snapshot

git add command is used to begin the tracking of the files.

Eg: $=> git add index.html

This took the file to the staging area, where it is ready to be committed.

To commit a file, we run:

$=> git commit -m ‘Some Message’

When we commit a version of the file, it gets stored in the historical snapshot.

$=> git rm — cached index.html

The above is used to untrack the files and unstage them from the staging area.

U: Untracked

A: Added

M: Modified

The below command is run for configuration on your system:

$=> git config — global user.name

Output: YOUR_NAME

$=> git config — global user.email

Output: YOUR_EMAIL

Individually adding files can be painful on git when working on a very big project. To tackle such a situation, we use the following command:

$=> git add .

This adds all the files that have been modified within the repository so that they are ready to be committed in the future.

To check the history of our commits, we use the following command:

$=> git log

It is characterized by a string of characters that are the unique identifier for every commit. It also tells us about the branch in which we have committed, the author, the date of the commit, and the files we have committed so far.

To get a shorter summary of all the commits, we write the following command:

$=> git log –oneline

The above gives the information of the commits concisely.

Each commit gets shown in one line, and the string of unique identification gets represented with just the first seven characters.

$=> code ~/.gitconfig

The above command opens the git config file in the text editor that stores some configuration stuff.

UNDOING THINGS

Here we see how to undo or discard the things in git using checkout, revert and reset. They allow us to go back in time and check the older versions of the project, along with letting us manipulate commits.

When using the command git log –oneline, the head element, by default, points to the last commit made in our project.

To ensure that the head is pointing to the last commit, we run the following command:

$=> git show HEAD

The sam output for the above command can be checked by giving the identifier of the commit as shown below:

$=> git show 2427d3c

Here, 2427d3c is a dummy identifier for the last commit that may have been done by the user.

We can even access other commits using the HEAD element as follows:

$=> git show HEAD~1

The above will point to the second commit. To access the third, fourth, fifth, etc, we simply have to replace 1 by 3/4/5 respectively.

The checkout command in git helps to unmodify the files and go back in time to check the different states of our project. It also allows us to move between different branches.

Suppose we have modified a file in our project and later realized it was a wrong modification. Thus, we need to remove this modification. We use the following command:

$=> git checkout #FILENAME

After running the above command, we do git status and see that this file is no longer in the modified state since the changes have been reverted.

To Unmodify all the files at the same time, we simply use the following command:

$=> git checkout .

OR

$=> git checkout *

The above commands remove the commits from the history and unstage the files from the staging area.

Suppose we want to go back in time and check out the state of our project on the second commit. We follow the command:

$=> git checkout #ID_OF_SECOND_COMMIT

The head points at the second commit, but that does not mean that the later commits have been deleted. We have just moved back in time and are present in the previous state of the project.

To go back and make the HEAD element point to the latest commit, we run the following command:

$=> git checkout master

After the above command, when we run git log — oneline, the HEAD element points back to the latest commit.

Moreover, the checkout command is read-only and we will not be able to change the added commit or add a new commit in the PREVIOUS STATE. To do so, we make use of the reverse or revert command.

Git revert: Helps to undo the changes to the project’s commit history. It takes the specified commit, reverses the changes from the commit, and creates a new revert commit.

$=> git revert /*ID_OF_COMMIT*/

The above command opens a temporary file on the terminal that prints the id of the commit, and upon pressing Ctrl+X, the changes that occurred in the past are reverted. This will be tagged as the new commit. Some we may make mistakes in a specific commit, and we can revert them back using the git revert that makes sure that no other commits are disturbed when reversing the specified commit.

Git reset : This is known as the dangerous command because it permanently deletes the work we have done. It is of three different flags that work in different ways:

$=> git reset — mixed *ID_OF_COMMIT*

This is the default flag, and it works anyways. This removes the commits from the history but does not change or undo the work on the files within our project. The files of the latest commit get unstaged upon running the above area. Therefore they no longer belong to the staging area. To undo the changes in the files, we will have to run the command :

— — — — — — — — — → $=> git checkout . ← — — — — — — — — — -

$=> git reset — soft *ID_OF_COMMIT*

Here the files are maintained in the staging area. To unstage them we have to do the following:

— — — — — — — — — → $=> git reset . ← — — — — — — — — — -

The above will unstage the files, but in order to undo the changes in the files, we will have to run the command :

— — — — — — — — — → $=> git checkout . ← — — — — — — — — — -

$=> git reset — hard *ID_OF_COMMIT*

To remove the commit and make changes in the file, we do a hard reset.

.gitignore : Helps us to ignore files or folders from tracking. These files and folders will not be recognized by git. There may be auto-generated files or folders that do not need tracking all the time because that may slow down our working process. Thus we ignore these files using ‘.gitignore’. We simply add the path of these files in the .gitignore file. Once we save these files, the untracked symbol next to that specific file goes away. Thus upon running ‘git status’, this will report only one untracked file, i.e .gitignore file. Had we done any modification of some files before creating the .gitignore file and later in the .gitignore file we specify the path of these specific files that we had modified before, then they will not be ignored due to the previous modifications done on them. For ignoring these files we will have to delete the cache from the history. For that we run the following command:

$=> git rm -r –cached

This will clean the cache and .gitignore will ignore these files. In case there are hundreds of files in a folder that needs to be ignored then we will have to write the following path in the .gitignore file.

NAME_OF_FOLDER/*

The above will include all the files within that specific folder and this will save us from the monotonicity of typing out all the files. This saves time and effort.

WHAT IS GITHUB?

Github is an online service that allows us to share our code or files in order to collaborate with other developers. It helps in building a centralized repository where everyone can manage the code.

Git is a version control tool that allows us to manage the project locally. Github is a hosting platform that allows us to host a repository on a remote server.

Pushing a repository from local machine to the GitHub repo:

$=> git add .

$=> git commit -m “COMMIT”

$=> git log — oneline

$=> git remote add origin “LINK_OF_REPOSITORY”

The above will connect our local repository to GitHub. Then we push it to GitHub. Here origin is the name of the remote.

$=> git push origin master

Here, the master is the branch to which we push our code to.

Pulling our repository from GitHub:

$=> git pull origin master

To update the local repository from Github, we use the git pull command.

Rather than every time writing origin and master in our commands we can set the default as follows :

$=> git branch — set-upstream-to=origin/master master

The above avoids indicating those names all the time. The default branch is master. Therefore the next time we need to update the local repository from GitHub we simply write:

$=> git pull

GIT BRANCH

By default when you create a repository and do commits, everything is operated on the master branch. Sometimes we may desire to add a new feature to our project but would not want it to break the current state of the project. In that case branching is very helpful. Here we create a new branch, and mork on this branch by adding files, commits, etc. After creating the new branch and working on the feature alongside, if we are comfortable with including it to our project, then we can merge it with the master branch. To create a new branch we run:

$=> git branch feature-1

In order to check all the branches, we run :

$=> git branch

This will inform us about all the branches present in our repository and we can decide which to work on.

To more between branches we simply run the following command:

$=> git checkout *BRANCH_NAME*

This helps us to switch to the branch desired.

To create and switch to the newly created branch with a single command:

$=> git branch -b *BRANCH_NAME*

To delete a branch we run the following command. But remember that we cannot delete the branch we are currently working on. We need to first checkout from that branch and then only we will be allowed to delete it.

$=> git branch -D *BRANCH_NAME*

To add a branch to Github we run :

$=> git push origin *BRANCH_NAME*

To add branches from GitHub to local repository:

$=> git pull origin *BRANCH_NAME*

git checkout — track origin/*BRANCH_NAME*

To delete the branch on GitHub locally we run the command:

$=> git push origin — delete *BRANCH_NAME*

The above command does not delete the branch on the local repository. To do that we need to run :

$=> git branch -D *BRANCH_NAME*

MERGING BRANCHES

To add the file into the staging area as well as commit, we run the following command:

$=> git commit -am “Commit Message”

The above command only runs for modified or deleted files. If the files are untracked then we cannot use the above command.

FAST-FORWARD MERGE:

To merge two branches we will have to first move to the master branch. Then we merge the two branches by :

$=> git merge *BRANCH_NAME*

The above merge is a basic one and is also called fast forward merge. We created a new branch from the master branch, and performed some changes on this new branch. Then we merge the two branches such that the new branch’s whatever modifications have been done with be reflected on the master branch.

THREE-WAY MERGE:

Here we create a new branch, work on the branch and at the same time, someone else makes commits on the massive branch before we merge the branches. So here along with the branch on which we have been working, someone else or we may even have worked on the master branch simultaneously. So both the branches have been committed. So here instead of the fast forward merge, we go for the three-way merge. We run the following command:

$=> git merge *BRANCH_NAME*

This will open a new file on the terminal. We simply have to do Ctrl+X. The terminal will notify that the merge has been made using the recursive strategy. Here we will see that the HEAD element will point to the master and not to both the branches.

Sometimes multiple developers may try to edit the same content which may lead to a merge conflict. For example, if one developer is trying to edit code that the second developer is editing then a conflict may occur. Git makes it relatively easy to deal with the merge conflicts compared to other version control systems.

So consider that two developers are making changes on the same file by setting the value of the variable differently. Then after committing the respective branches, we merge them. Here since a conflict occurs, git will open the specific file where the conflict takes place and notifies the user to select a particular value. Once the user makes the recommended changes then runs the git add command followed by git commit. Later on, upon checking the history, we observe that the required merging has been done.

$=> git merge *BRANCH_NAME* //Request to merge

Here the conflict is notified to the user with the file where the user needs to do the required changes. Then:

$=> git add .

$=> git commit

$=> git log — oneline

Then the branches are merged.

To stop the merging of files we can do the following:

$=> git merge — abort

The above will stop the merging and we will no longer have any conflicts. It will keep all the changes that we have kept in both the branches intact.

GIT REBASE

Git rebase is used to integrate changes from one branch into another. It is the process of moving or combining a sequence of commits to a new base commit.

$=> git reset — hard *COMMIT_ID*

This will set the HEAD element to the commit ID we want it to point towards leaving all the other commits to get deleted.

Now, we create a branch that contains all the commits that we have done on the master branch. After this, we add some new commits to the master branch. Now we desire that these new commits should also reflect on the new branch. There we need to rebase this branch on the master branch. Using git rebase allows us to rebase the future branch for the newly created commit which was made on the master branch. For this we first checkout to the new branch and then run the following command:

$=> git rebase master

This makes the HEAD element to point to both the branches i.e, master as well as the new branch.

FORKING AND CLONING

To copy someone’s repository to our account, we use the fork available on Github.

Once the new project gets added to your GitHub account, you simply run a git clone on your machine to work on the project locally.

--

--