DEV Community

DevOps Man
DevOps Man

Posted on

Mastering Git: The Ultimate Developer's Guide to Version Control

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
Enter fullscreen mode Exit fullscreen mode
  • Local Config:
git config --local --list
Enter fullscreen mode Exit fullscreen mode
  • System Config:
git config --system --list
Enter fullscreen mode Exit fullscreen mode
  • To view all configuration levels, you can use:
git config --list
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
  • git clone: Creates a local copy of an existing remote repository. It downloads all the files, commits, branches, and history.
git clone <repository_url>
Enter fullscreen mode Exit fullscreen mode

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

git status
Enter fullscreen mode Exit fullscreen mode

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 <file_name>
git add .  # Adds all changes

Enter fullscreen mode Exit fullscreen mode
  • git commit: Records the changes in the staging area to the repository with a commit message.
git commit -m "Commit message"
Enter fullscreen mode Exit fullscreen mode

Viewing History

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

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^
Enter fullscreen mode Exit fullscreen mode

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 <file_name>
Enter fullscreen mode Exit fullscreen mode

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 <branch_name>
Enter fullscreen mode Exit fullscreen mode
  • Switch to another branch using:
git checkout <branch_name>
Enter fullscreen mode Exit fullscreen mode
  • Or using the modern alternative (since Git 2.23+):
git switch <branch_name>
Enter fullscreen mode Exit fullscreen mode
  • Create and switch in one step:
git checkout -b <branch_name>
or
git switch -c <branch_name>
Enter fullscreen mode Exit fullscreen mode

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

git merge <branch_name>
Enter fullscreen mode Exit fullscreen mode

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)

Enter fullscreen mode Exit fullscreen mode

After fast-forward merge:

*---*---*---*---* (main)

Enter fullscreen mode Exit fullscreen mode
  • 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
Enter fullscreen mode Exit fullscreen mode
  • List all stashes:
git stash list
Enter fullscreen mode Exit fullscreen mode
  • Apply the most recent stash (and keep it in the stash list):
git stash apply
Enter fullscreen mode Exit fullscreen mode
  • Apply and remove the stash from the list:
git stash pop
Enter fullscreen mode Exit fullscreen mode
  • Apply a specific stash:
git stash apply stash@{2}
Enter fullscreen mode Exit fullscreen mode
  • Drop a stash:
git stash drop stash@{0}
Enter fullscreen mode Exit fullscreen mode
  • Clear all stashes:
git stash clear
Enter fullscreen mode Exit fullscreen mode

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 <remote_repository_url>
Enter fullscreen mode Exit fullscreen mode

- List all remotes:

git remote -v
Enter fullscreen mode Exit fullscreen mode
  • Rename a remote:
git remote rename origin upstream
Enter fullscreen mode Exit fullscreen mode
  • Remove a remote:
git remote remove origin
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
  • Push a specific branch to a remote:
git push origin <branch_name>
Enter fullscreen mode Exit fullscreen mode
  • Push all local branches to origin:
git push --all origin
Enter fullscreen mode Exit fullscreen mode
  • Push with upstream tracking (first-time push):
git push -u origin <branch_name>
Enter fullscreen mode Exit fullscreen mode

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 <branch_name>
Enter fullscreen mode Exit fullscreen mode
  • If your current branch tracks a remote branch, simply:
git pull
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

After fetching, you can compare or merge changes manually:

git merge origin/<branch_name>
Enter fullscreen mode Exit fullscreen mode

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 <local_branch> origin/<remote_branch>
Enter fullscreen mode Exit fullscreen mode
  • Set upstream while pushing:
git push -u origin <branch_name>
Enter fullscreen mode Exit fullscreen mode
  • Check which remote branch your local branch is tracking:
git branch -vv
Enter fullscreen mode Exit fullscreen mode
  • Change the upstream branch:
git branch --set-upstream-to=origin/<remote_branch> <local_branch>
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
  • Create a lightweight tag:
git tag <tag_name>
Enter fullscreen mode Exit fullscreen mode
  • Create an annotated tag:
git tag -a <tag_name> -m "Tag message"
Enter fullscreen mode Exit fullscreen mode
  • Tag a specific commit:
git tag -a <tag_name> <commit_hash> -m "Message"
Enter fullscreen mode Exit fullscreen mode
  • Push tags to remote:
git push origin <tag_name>
Enter fullscreen mode Exit fullscreen mode
  • Push all tags:
git push origin --tags
Enter fullscreen mode Exit fullscreen mode
  • Delete a tag locally:
git tag -d <tag_name>
Enter fullscreen mode Exit fullscreen mode
  • Delete a remote tag:
git push origin --delete <tag_name>
Enter fullscreen mode Exit fullscreen mode

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 <commit_hash>
Enter fullscreen mode Exit fullscreen mode
  • 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 <commit_hash>
Enter fullscreen mode Exit fullscreen mode

Mixed (unstage changes):

git reset --mixed <commit_hash>
Enter fullscreen mode Exit fullscreen mode

Hard (discard everything):

git reset --hard <commit_hash>
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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 <base_branch>
Enter fullscreen mode Exit fullscreen mode
  • Apply a specific commit from one branch onto another:
git cherry-pick <commit_hash>
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
  • Delete untracked files:
git clean -f
Enter fullscreen mode Exit fullscreen mode
  • Delete untracked directories too:
git clean -fd
Enter fullscreen mode Exit fullscreen mode

⚠️ 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 <commit_hash>
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

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 <file>
Enter fullscreen mode Exit fullscreen mode
  • Ignore whitespace changes:
git blame -w <file>
Enter fullscreen mode Exit fullscreen mode
  • Blame a file as of a specific commit:
git blame <commit_hash> -- <file>
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
  • Mark the bad (buggy) commit:
git bisect bad
Enter fullscreen mode Exit fullscreen mode
  • Mark the good (working) commit:
git bisect good <commit_hash>
Enter fullscreen mode Exit fullscreen mode
  • Git checks out a commit halfway between. You test it, and mark it as:
git bisect good
git bisect bad
Enter fullscreen mode Exit fullscreen mode
  • Continue until Git pinpoints the exact commit that introduced the bug.

  • Exit bisect mode:

git bisect reset
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
  • Restore a lost commit: Find its hash in the reflog and reset or checkout:
git checkout <commit_hash>
Enter fullscreen mode Exit fullscreen mode
  • Recover a deleted branch: If you deleted a branch and want to restore it:
git checkout -b <branch_name> <commit_hash_from_reflog>
Enter fullscreen mode Exit fullscreen mode
  • Undo a hard reset:
git reset --hard <commit_hash_from_reflog>
Enter fullscreen mode Exit fullscreen mode

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 <repo_url> <path>
git submodule init
git submodule update
Enter fullscreen mode Exit fullscreen mode

🌳 Git Subtrees

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

  • Easier to manage compared to submodules.

git subtree add --prefix=<dir> <repo_url> <branch> --squash
Enter fullscreen mode Exit fullscreen mode

To update later:

git subtree pull --prefix=<dir> <repo_url> <branch> --squash
Enter fullscreen mode Exit fullscreen mode

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

Top comments (0)