Version Control and Git

Git is an open-source distributed version control system that allows developers to manage and track changes made to their code. It was created by Linus Torvalds in 2005 and is widely used by developers to collaborate on projects, track changes, and manage code revisions.

Git is an essential tool for software development.

In this blog post, we will discuss the basics of Git and how it works.

Git Basics

Git is a distributed version control system, which means that every developer has a copy of the code repository on their local machine. This allows developers to work on code changes independently, and then merge their changes with the central repository when they are ready.

The central repository is hosted on a server and is accessible to all developers. Git uses a tree-like structure to organize code changes, with each node representing a commit. A commit is a snapshot of the code repository at a specific point in time.

Git also uses branches to allow developers to work on code changes independently of each other. Each branch represents a version of the code repository, and developers can switch between branches to work on different features or bug fixes.

Install git

To use Git, you first need to install it on your local machine.

  1. Download the Git installer from the official website at Git - Downloads.

  2. Run the installer and follow the on-screen instructions to complete the installation.

  3. Once the installation is complete, open a command prompt or terminal window and type “git” to confirm that Git has been installed correctly.

Git is available for Windows, Mac, and Linux operating systems, and the installation process may vary slightly depending on the operating system you are using.

Once you have Git installed, you can use it to create a new repository, clone an existing repository, or make changes to an existing repository.

Creating a new repository

To create a new repository on local machine, you first need to create a new directory on your local machine. Once you have created the directory, you can use the following command to initialize a new Git repository.


git init

Note that you have created this repository on local and not synchronized with any remote such as github/gitlab/bitbucket repository etc.

To add a remote to this local repository creating using git init you can use the following command:


git remote add origin <repo-url>

where repo-url is a url of a remote git repository.

Verify that the remote URL has changed.


git remote -v

Creating a remote git repository

  • Go to github.com, create your account, login to your account and create a new repository by clicking on the “New” button in the top left corner of your screen.

  • Give your repository a name and a short description, and choose whether it should be public or private.

  • Click on the “Create repository” button.

Else, you can use the set-url subcommand to edit an existing remote:


git remote set-url origin <repo-url>

If there is an existing repository, this command creates a new Git repository in the current directory.

Cloning an existing repository

To clone an existing repository, you need to use the following command:


git clone <repository-url>

This command creates a copy of the repository on your local machine.

Creating new branch and making changes to an repository:

To make changes to an existing repository, you first need to make sure that you are on the correct branch. You can use the following command to switch to a different branch:


git checkout <branch-name>

or Create a new branch


git branch <branch-name>

or

git checkout -b <branch-name>

Add file and commit

Once you are on the correct branch, you can make changes to the code. When you are ready to commit your changes, you can use the following command:


git add <file1>

git add <file2>

etc.

or

git add <file1> <file2>

git commit -m "commit message"

The git add <file> command adds all changes to the staging area, and the git commit command creates a new commit with a commit message. Using single git add you can add one or more files or folders.

Push changes to remote:


git push origin <branch-name>

This command pushes your changes to the central repository and makes them available to other developers.

Git commands

Here are some of the most useful Git commands and tips that can help developers be more productive:

  1. git clone: This command is used to create a copy of an existing repository on your local machine. It’s a great way to start working on a project that’s already been set up.

  2. git status: This command shows the current state of the repository, including any changes that have been made and any files that are not yet tracked by Git.

  3. git add: This command is used to add files to the staging area, which is where changes are prepared for a commit. It’s important to stage only the changes that you want to commit, to avoid committing unnecessary changes.

  4. git commit: This command is used to create a new commit with the changes that have been staged. It’s important to write clear and informative commit messages to make it easier to understand the changes later on.

  5. git push: This command is used to push the changes from your local repository to a remote repository, such as GitHub or GitLab.

  6. git pull: This command is used to fetch changes from a remote repository and merge them into your local repository.

  7. git merge: This command is used to merge changes from one branch into another. It’s important to resolve any conflicts that may arise during the merge process.

  8. git branch: This command is used to create, list, and delete branches. It’s a great way to keep different versions of your code separate and to work on different features or fixes simultaneously.

  9. git stash: This command is used to temporarily save changes that are not yet ready to be committed. It’s a great way to switch to a different branch or work on a different feature without losing your progress.

  10. git log: This command shows a history of all the commits that have been made to the repository. It’s a great way to track changes and understand the evolution of the codebase.

Merge strategy

Git provides different merge strategies to use when merging branches. Each strategy has its own advantages and disadvantages, and developers should choose the appropriate strategy based on their specific needs.

Recursive Merge Strategy

The recursive merge strategy is the default merge strategy in Git. It is used to merge two branches by finding a common ancestor and merging the changes made since that ancestor. This strategy is well-suited for most use cases, as it tries to automatically resolve conflicts. However, it may result in more conflicts than other strategies.

Octopus Merge Strategy

The octopus merge strategy is used to merge multiple branches at once. It is useful when merging several related branches into a single branch. This strategy does not try to resolve conflicts automatically, so developers must manually resolve any conflicts that arise.

Resolve Merge Strategy

The resolve merge strategy is used to merge two branches by applying the changes made in one branch to the other. This strategy is well-suited for cases where the changes in one branch are minor and can be easily applied to the other branch. However, it may result in conflicts if the changes are significant.

Subtree Merge Strategy

The subtree merge strategy is used to merge a subdirectory of one branch into another branch. This strategy is useful when you only want to merge a specific part of a branch, such as a single feature. It requires specifying the subdirectory to merge, which can be cumbersome.

Squash Merge Strategy (Recommended)

The squash merge strategy is used to merge a branch into another branch by creating a single commit that includes all of the changes from the branch being merged. This strategy is useful when you want to keep the commit history clean and avoid a cluttered commit history. However, it can make it difficult to track changes over time.

Merge Conflicts and Conflicts resolve

Git conflicts can occur when two or more developers are working on the same file or code at the same time and make conflicting changes. These conflicts can be resolved using Git’s built-in tools.

Example 1: Conflicting Changes in the Same Line

Let’s say two developers, Rohit and Virat, are working on the same file and make changes to the same line of code. Rohit changes the line to read “Hello, world!” while Virat changes it to read “Hi, everyone!”. When they both try to push their changes to the remote repository, Git will detect a conflict.

To resolve this conflict, Rohit and Virat will need to manually edit the file to merge their changes. Git will mark the conflicting lines with “<<<<<<<” and “>>>>>>>”. The changes made by Rohit will be between “<<<<<<< HEAD” and “=======”, while the changes made by Virat will be between “=======” and “>>>>>>> branch-name”.

Here’s an example of what the file might look like with conflicts:


Hello, world!

<<<<<<< HEAD

Hi, everyone!

=======

Hello, Git!

>>>>>>> branch-name

To resolve the conflict, Rohit and Virat will need to manually edit the file to merge their changes. They might decide to change the line to read “Hello, everyone!”:


Hello, everyone!

Once they have resolved the conflict, they can save the file and commit the changes.

Example 2: Conflicting Changes in Different Lines

Let’s say Rohit and Virat are working on the same file, but they make changes to different lines of code. Rohit changes line 1 to read “Hello, world!” while Virat changes line 5 to read “Hi, everyone!”. When they both try to push their changes to the remote repository, Git will detect a conflict.

To resolve this conflict, Git will automatically merge the changes and create a new version of the file. The merged version will include both Rohit’s and Virat’s changes.

Here’s an example of what the merged file might look like:


Hello, world!

This is some code.

This is more code.

This is even more code.

Hi, everyone!

Rohit’s changes are on line 1, while Virat’s changes are on line 5.

Once the conflict has been resolved, Rohit and Virat can save the merged file and commit the changes.

Example 3: Conflicting Changes in Different Files

Let’s say Rohit and Virat are working on different files in the same repository. Rohit changes file A to read “Hello, world!”, while Virat changes file B to read “Hi, everyone!”. When they both try to push their changes to the remote repository, Git will not detect any conflicts.

In this case, both Rohit and Virat’s changes can be merged without any issues. Each developer’s changes will be applied to the correct file, and there will be no conflicts to resolve.

Merge tool

Git conflicts can also be resolved using Git’s built-in merge tool. The merge tool provides a graphical interface that can make it easier to visualize and resolve conflicts.

Configure the Merge Tool

Before we can use the merge tool, we need to configure Git to use it. We can do this by setting the “merge.tool” configuration option. We can set this option using the following command:


git config --global merge.tool <merge-tool-name>

Replace with the name of the merge tool that you want to use. Some popular merge tools include meld, vimdiff, kdiff3, and p4merge.

Start the Merge Tool

Once we have configured Git to use the merge tool, we can start the merge tool by running the following command:


git mergetool

Resolve the Conflicts

The merge tool will display the conflicting files and highlight the conflicting lines. We can use the merge tool’s interface to select which changes we want to keep and which changes we want to discard.

Once we have resolved all of the conflicts, we can save the file and exit the merge tool.

Step 4: Commit the Changes

After resolving the conflicts using the merge tool, we can commit the changes using the following command:


# add files if modified

git add <files>

# commit

git commit -m "Resolved conflicts using merge tool"

Git stash

Switch between branches without committing.

Git stash is a command used to save changes that are not yet ready to be committed, allowing developers to switch to another branch or task without losing their work. It is a useful tool for managing changes when working on multiple tasks at the same time.

When you run the Git stash command, Git saves the changes in the working directory and the staging area into a “stash”. The stash is stored as a stack, allowing developers to save multiple stashes and apply them in a specific order.

The syntax for the Git stash command is:


git stash

This command saves the changes in the working directory and the staging area into a stash.

How Git Stash Works

When you run the Git stash command, Git saves the changes in the working directory and the staging area into a stash. Git then resets the working directory and staging area to the last commit. This allows developers to switch to another branch or task without committing their changes.

Here is an example of how Git stash works:


$ git status

On branch feature

Changes not staged for commit:

modified: file1.txt

modified: file2.txt

In this example, the developer has made changes to two files in the feature branch, but these changes are not ready to be committed. To save the changes using Git stash, the developer would run the following command:


$ git stash

Saved working directory and index state WIP on feature: c123456 Some changes made

Git would then save the changes into a stash and reset the working directory and staging area to the last commit. The developer could then switch to another branch or task, and when they return to the feature branch, they could apply the changes from the stash.

Git stash apply

To apply the stash, the developer would run the following command:


$ git stash apply

This command applies the most recent stash to the current branch. If the developer has multiple stashes, they can apply a specific stash using the following command:

Use git stash list to display all available stashes.


$ git stash list

stash@{0}: WIP on master: 1234567 Commit message

stash@{1}: WIP on master: 890abcd Another commit message


$ git stash apply stash@{1}

This command applies the third stash in the stack to the current branch.

Git Stash Pop

The git stash pop command is used to apply the most recent stash to the current branch and remove it from the stash list. It is a convenient way to apply a stash and avoid cluttering the stash list with outdated or unused stashes. Here is an example of how to use git stash pop:


$ git stash list

stash@{0}: WIP on master: 1234567 Commit message

stash@{1}: WIP on master: 890abcd Another commit message

$ git stash pop

In this example, the most recent stash in the list is applied to the current branch using the git stash pop command. The stash is also removed from the list, making it easier to manage the stash list and avoid confusion.

When to Use Apply vs Pop

The git stash apply command is useful when a developer wants to apply a stash without removing it from the list. This can be helpful if the same stash needs to be applied multiple times or if the stash is not yet complete.

The git stash pop command is useful when a developer wants to apply the most recent stash and remove it from the list. This can be helpful to avoid cluttering the stash list with outdated or unused stashes.

In general, it is a good practice to use git stash apply if the stash needs to be applied multiple times, and git stash pop if the stash is no longer needed after applying it.

Benefits of Git Stash

Git stash has several benefits, including:

  1. Saves work in progress: Git stash allows developers to save their work in progress without having to commit their changes, making it easy to switch to another task or branch.

  2. Multiple stashes: Git stash allows developers to save multiple stashes and apply them in a specific order, making it easy to manage changes when working on multiple tasks at the same time.

  3. Easy to use: Git stash is easy to use, requiring only a single command to save and apply changes.

Git Rebase

Git rebase is a command used to modify the commit history of a Git branch. It is a powerful tool that allows developers to reorganize and simplify the commit history of a branch by applying changes from one branch to another.

When you rebase a branch, Git takes the changes from the branch you are rebasing and applies them onto the branch you are rebasing into. This creates a new commit history for the branch being rebased.

The syntax for the Git rebase command is:


git rebase <branch-to-rebase-on>

This command applies the changes from the current branch onto the branch.

How Git Rebase Works

When you run the Git rebase command, Git first determines the common ancestor commit between the two branches. It then creates a new branch with the changes from the current branch applied on top of the branch. This creates a linear commit history for the rebased branch.

Here is an example of how Git rebase works:


A---B---C feature

/

D---E---F---G master

In this example, the feature branch was created from the master branch. The feature branch has three commits (A, B, and C) and the master branch has four commits (D, E, F, and G). To rebase the feature branch onto the master branch, you would run the following command:


git checkout feature

git rebase master

Git would then create a new commit history for the feature branch with the changes from the feature branch applied on top of the master branch:


D---E---F---G---A'---B'---C' feature

In this new commit history, the changes from the feature branch are applied on top of the changes from the master branch, creating a linear commit history.

Benefits of Git Rebase

Git rebase has several benefits, including:

  1. Simplifies the commit history: Rebase can help simplify the commit history by creating a linear history, making it easier to read and understand the changes made to a branch.

  2. Prevents merge conflicts: Rebase can help prevent merge conflicts by applying the changes from the current branch on top of the branch being rebased into, rather than merging the two branches together.

  3. Helps to keep the code up-to-date: Rebase can help to keep the code up-to-date by applying the changes from the branch being rebased on top of the current branch, ensuring that the changes are incorporated into the codebase.

Delete git branch

Delete a local branch

git branch -D <branch_name>

Delete a remote branch

git push origin -d <branch_name>