What is Git? What is Version Control?

Git is a distributed version control system (VCS) designed to track changes in source code during software development. It allows multiple developers to work on the same project simultaneously without interfering with each other's work.

Version control, in general, is the practice of tracking and managing changes to software code over time. It allows developers to revert to previous versions, collaborate effectively, and maintain the integrity of their codebase.


Types of Version Control and Difference Between Them

Centralized Version Control (CVCS): A system where the version history is stored on a central server, and developers access this repository to make changes. Examples include Subversion (SVN) and Perforce. The main issue is that if the central server goes down, no one can access the version history or make changes.

Distributed Version Control (DVCS): Systems like Git, where each developer has a complete copy of the repository, including its history, on their local machine. This allows for greater flexibility and resilience. Git is an example of a DVCS, and it doesn't rely on a central server for basic operations, allowing offline work and better collaboration.


Git Config – Global, Local, and System Config
Git provides three types of configuration levels to control settings:

  • Global Config: This configuration applies to all repositories of the current user. It's stored in the user's home directory
    (~/.gitconfig or ~/.config/git/config).

  • Local Config: This configuration applies only to a single repository. It is stored in the .git directory of the repository
    (.git/config).

  • System Config: This configuration applies to all users on the system and is stored in the system's Git config file, usually located at /etc/gitconfig.


Git Config Command to View
To view the configuration values set at different levels, you can use the following commands:

  • Global Config:
git config --global --list
  • Local Config:
git config --local --list
  • System Config:
git config --system --list
  • To view all configuration levels, you can use:
git config --list

Git Workflow Overview (Working Directory, Staging Area, Repository)
Git workflow involves three main areas:

  • Working Directory: The directory where files are modified. This is where you make changes to your files.

  • Staging Area (Index): This is where files are prepared before being committed. It allows you to decide which changes to include in the next commit.

  • Repository (Git Directory): The .git directory where the full history and configuration of the project are stored. This is where the commits are made and tracked.


Creating a Repository

  • git init: Initializes a new empty Git repository in the current directory.
git init
  • git clone: Creates a local copy of an existing remote repository. It downloads all the files, commits, branches, and history.
git clone

Checking Status
To check the current state of your repository, including which files have been modified or are staged, use:

git status

This command will show you the differences between your working directory, the staging area, and the repository.


Adding and Committing

  • git add: Adds changes in the working directory to the staging area, preparing them to be committed.
git add 
git add .  # Adds all changes
  • git commit: Records the changes in the staging area to the repository with a commit message.
git commit -m "Commit message"

Viewing History

  • git log: Displays the commit history with commit hashes, authors, dates, and messages.
git log
  • git show: Displays detailed information about a specific commit.
git show
  • git diff: Shows the differences between the working directory and the staging area or between commits.
git diff

Reverse of Git Workflow (Working Directory to Staging Area and Staging Area to Repository)

  • From Repository to Staging Area: You can undo a commit and move the changes back to the staging area using:
git reset --soft HEAD^

This will reset the repository to the previous commit but keep the changes in the staging area.

  • From Staging Area to Working Directory: If you want to unstage changes (move them back to the working directory without losing them):
git reset

This will unstage a specific file but leave it in the working directory.


Branching and Merging

Git branches allow developers to work on new features or bug fixes in isolation from the main production code. Branching is a powerful feature that enables parallel development, experimentation, and clean merging of code.

Merging is the process of integrating changes from one branch into another. Usually, changes from a feature branch are merged into the main branch once the feature is complete.


Creating and Switching Branches

  • Create a new branch using:
git branch
  • Switch to another branch using:
git checkout
  • Or using the modern alternative (since Git 2.23+):
git switch
  • Create and switch in one step:
git checkout -b 
or
git switch -c

Merging Branches
To merge changes from one branch into the current branch:

git merge

This command applies the changes from the specified branch into the branch you're currently on.


Fast-forward vs. 3-way Merge

  • Fast-forward Merge: If there have been no changes on the base branch since the feature branch was created, Git will simply move the pointer forward to include the new commits.
*---*---*   (main)
         \
          *---*---* (feature)

After fast-forward merge:

*---*---*---*---* (main)
  • 3-Way Merge: If both branches have diverged, Git uses a 3-way merge to combine changes. It compares the common ancestor with both branches and creates a new commit to reconcile them.

Merge Conflicts and Resolving Them
A merge conflict occurs when Git is unable to automatically merge changes due to overlapping edits on the same lines in the same file.

When this happens:

  • Git will mark the conflict in the file.

  • Manually edit the file to resolve the conflict.

  • After resolving the conflict, do add and commit again.


git stash – Save and Reapply Work
The git stash command allows you to temporarily save changes that you don’t want to commit immediately. It's helpful when you need to switch branches or pull updates without committing unfinished work.

  • Stash current changes:
git stash
  • List all stashes:
git stash list
  • Apply the most recent stash (and keep it in the stash list):
git stash apply
  • Apply and remove the stash from the list:
git stash pop
  • Apply a specific stash:
git stash apply stash@{2}
  • Drop a stash:
git stash drop stash@{0}
  • Clear all stashes:
git stash clear

Adding Remotes (git remote add)

A remote is a reference to a repository hosted elsewhere (typically on GitHub, GitLab, Bitbucket, etc.). You can connect your local repository to a remote to collaborate and share code.

  • Add a remote repository:
git remote add origin

- List all remotes:

git remote -v
  • Rename a remote:
git remote rename origin upstream
  • Remove a remote:
git remote remove origin

Pushing Changes (git push)

After committing locally, you need to push the changes to a remote repository so others can access them.

  • Push to the default remote (origin) and current branch:
git push
  • Push a specific branch to a remote:
git push origin
  • Push all local branches to origin:
git push --all origin
  • Push with upstream tracking (first-time push):
git push -u origin

Pulling Changes (git pull)

The git pull command fetches and integrates changes from a remote repository into your current branch. It's a combination of git fetch and git merge.

  • Pull latest changes from origin:
git pull origin
  • If your current branch tracks a remote branch, simply:
git pull

Fetching Changes (git fetch)

The git fetch command downloads commits, files, and refs from a remote repository without merging them into your working branch.

  • Fetch from origin:
git fetch origin

After fetching, you can compare or merge changes manually:

git merge origin/

git fetch is a safe way to see what others have pushed without touching your current work.


Tracking Branches

A tracking branch is a local branch that is connected to a remote branch. This relationship makes commands like git push and git pull more convenient.

  • Create a tracking branch manually:
git checkout -b  origin/
  • Set upstream while pushing:
git push -u origin
  • Check which remote branch your local branch is tracking:
git branch -vv
  • Change the upstream branch:
git branch --set-upstream-to=origin/

Git Tags (git tag, git tag -a)

Tags are used to mark specific points in history as important — typically to label releases (v1.0.0, v2.0.1, etc.).

  • List all tags:
git tag
  • Create a lightweight tag:
git tag
  • Create an annotated tag:
git tag -a  -m "Tag message"
  • Tag a specific commit:
git tag -a   -m "Message"
  • Push tags to remote:
git push origin
  • Push all tags:
git push origin --tags
  • Delete a tag locally:
git tag -d
  • Delete a remote tag:
git push origin --delete

Reverting Changes (git revert, git reset)

  • git revert: Safely undoes a commit by creating a new commit that reverses the changes. It preserves history.
git revert
  • git reset: Moves the HEAD and optionally resets the index (staging area) and working directory. Can erase commits if used carelessly. Soft (keep changes staged):
git reset --soft

Mixed (unstage changes):

git reset --mixed

Hard (discard everything):

git reset --hard

Difference Between reset, revert, checkout

Command Effect on Commits Effect on Working Directory Safe? Usage
reset Removes commits Optional (hard resets files) ❌ Risky Clean up local history before pushing
revert Adds new commit Leaves files as-is ✅ Very Safe Undo changes in a shared/public branch
checkout Switches branches or restores files Overwrites working directory files ⚠️ Safe (with caution) Restore files or move between branches

Rewriting History

  • Modify the most recent commit (message or contents):
git commit --amend

This is useful when you forgot to add a file or want to edit the commit message.

  • Rebase allows you to replay commits from one branch onto another, enabling a clean linear history.
git rebase
  • Apply a specific commit from one branch onto another:
git cherry-pick

This is useful to copy fixes or features without merging the entire branch.


Cleaning Up (git clean)

Removes untracked files and directories from your working directory.

  • Dry run (see what will be deleted):
git clean -n
  • Delete untracked files:
git clean -f
  • Delete untracked directories too:
git clean -fd

⚠️ Use this command with care — it permanently deletes files not tracked by Git.


Detached HEAD

A detached HEAD state means you're not on any branch — instead, you're pointing directly to a commit.

This happens when you:

git checkout

You can view, explore, or test changes, but any commits made now won’t belong to any branch unless you create one:

  • Create a branch from detached HEAD:
git checkout -b new-branch

This is useful for reviewing or reverting specific historical commits without affecting branches.


git log with Options

The git log command shows the commit history of the repository. It’s highly customizable using flags.

  • Basic log:
git log
  • Compact one-line per commit:
git log --oneline
  • Show graph of branches and merges:
git log --graph
  • Decorate with branch and tag names:
git log --decorate
  • Combine all (graph, oneline, decorate):
git log --oneline --graph --decorate
  • Limit the number of commits:
git log -n 5
  • Show commits by a specific author:
git log --author="Author Name"
  • Filter commits by date:
git log --since="2 weeks ago"
git log --after="2024-01-01" --before="2024-12-31"
  • View changes made in each commit:
git log -p

git blame – Who Changed What, When

git blame shows who last modified each line of a file. It’s useful for tracking down when a line of code was added or changed.

  • Basic usage:
git blame
  • Ignore whitespace changes:
git blame -w
  • Blame a file as of a specific commit:
git blame  --

git bisect – Find the Bug

git bisect helps you find the commit that introduced a bug by using binary search between a known good and bad commit.
Steps:

  • Start bisect:
git bisect start
  • Mark the bad (buggy) commit:
git bisect bad
  • Mark the good (working) commit:
git bisect good
  • Git checks out a commit halfway between. You test it, and mark it as:
git bisect good
git bisect bad
  • Continue until Git pinpoints the exact commit that introduced the bug.

  • Exit bisect mode:

git bisect reset

git reflog – Recover Lost Commits

The reflog records all movements of your HEAD — even commits not visible in git log. If you've lost a branch, a commit, or reset hard by mistake, git reflog can rescue you.

  • Show all recent HEAD changes:
git reflog
  • Restore a lost commit: Find its hash in the reflog and reset or checkout:
git checkout
  • Recover a deleted branch: If you deleted a branch and want to restore it:
git checkout -b
  • Undo a hard reset:
git reset --hard

Submodules and Subtrees

Both let you include one Git repository inside another.

🧩 Git Submodules

  • Track external repositories as subfolders.

  • You need to init/update them manually.

git submodule add  
git submodule init
git submodule update

🌳 Git Subtrees

  • Merge another repository directly into a subdirectory of your project.

  • Easier to manage compared to submodules.

git subtree add --prefix=   --squash

To update later:

git subtree pull --prefix=   --squash

More Git magic coming soon — stay tuned for advanced workflows, GitOps, and real-world use cases!