Git & Github Doc - Kunal Gaikwad
GitHub
Chai aur Git Series

Git & GitHub Documentation

A comprehensive guide to mastering version control — from zero to collaborating on real projects.

What you'll learn

Learning Path

This guide is structured progressively. Follow these steps in order:

1

Get the basics

Learn what Git is, install it, and understand core concepts like repository, commit and staging area.

2

Use it daily

Add files, commit changes, create branches, and build a habit of version-controlling your work.

3

Face the problems

Hit merge conflicts, deal with detached HEAD state, or accidentally deleted commits — it's normal!

4

Solve them

Use stash, rebase, reflog and diff to navigate and fix tricky situations.

5

Collaborate

Push to GitHub with SSH, work with teams via pull requests, fork and upstream remotes.

Introduction

Git and GitHub

Learn the fundamentals of version control and understand how Git differs from GitHub.


Git and GitHub are different

Git is a version control system used to track changes to your files. It is free, open-source, and available for Windows, macOS, and Linux. Git is installed as software directly on your computer.

GitHub is a web-based hosting platform for Git repositories. It allows you to store and share code with others online. While GitHub is the most popular provider, alternatives include Gitlab, Bitbucket and Azure Repos.

🖥️
Git
Local software. Tracks file changes. Works offline. Installed on your machine.
☁️
GitHub
Remote platform. Hosts repos online. Enables team collaboration. Accessed via browser or CLI.

Version Control Systems

Version control systems manage the history of your code. Think of them as checkpoints in a video game — you can move to any point in history and always go back to a previous checkpoint.

Before Git became mainstream, systems like SCCS (Source Code Control System) were used, but they were proprietary and expensive. Git was created to replace them. Other version control systems include Subversion (SVN), CVS, and Perforce.

Git was created by Linus Torvalds in 2005 to manage Linux kernel development. It was designed to be fast, distributed, and handle large projects efficiently.

Install Git

Download Git from the official website or use your system's package manager:

bash
# macOS (via Homebrew)
brew install git

# Ubuntu / Debian
sudo apt-get install git

# Windows — download from:
# https://git-scm.com/downloads

Verify your installation:

bash
git --version
# git version 2.43.0

Account on GitHub

Create a free account at github.com. You'll need it later when we set up SSH keys to push code to remote repositories. Password authentication is no longer recommended — SSH key authentication is the standard.

Core Concepts

Terminology

Git uses its own vocabulary. Here's what every term means and how to use the key commands.


Repository

A repository (repo) is a folder tracked by Git. It's not just storage — it maintains a full history of every change. Any folder can become a repo:

bash
git init          # Initialize a new repo (creates .git/ folder)
git status        # Check the current state of your repo

Config Settings

Every commit records who made it. Set your identity globally:

bash
git config --global user.email "you@example.com"
git config --global user.name "Your Name"
git config --list   # View all settings

The Complete Git Flow

The typical workflow from creating a file to pushing it to GitHub:

Working DirectoryStaging AreaLocal RepositoryRemote (GitHub)
(edit files) git add git commit git push

Stage

Staging tells Git which changes to include in the next commit. Files in the staging area are ready to be committed but not yet saved permanently:

bash
git add index.html          # Stage a single file
git add .                   # Stage all changes
git status                  # See staged vs unstaged files

Commit

A commit is a permanent snapshot of your staged changes. Each commit gets a unique hash ID.

bash
git commit -m "Add homepage layout"
git log           # Full commit history
git log --oneline # Compact one-line view

Omitting the -m flag opens your default editor (usually Vim). You can change this to VS Code: git config --global core.editor "code --wait"

Atomic Commits

Each commit should be a single, self-contained unit of work. This makes it easy to revert specific changes without breaking other things. A good commit message is: feat: add user authentication — not changes.

.gitignore

The .gitignore file lists files and folders that Git should never track:

.gitignore
node_modules/
.env
.vscode/
dist/
*.log
Internals

Git Behind the Scenes

How Git internally stores every change — snapshots, objects and hash codes.


Git Snapshots

Every time you commit, Git doesn't just record diffs — it stores a full snapshot of your project as it exists at that moment. Each snapshot is identified by a SHA-1 hash — a 40-character string uniquely identifying the contents.

This snapshot system is backed by a key-value object database inside the .git/ folder. There are three core object types.

The 3 Musketeers of Git

Commit Object
  • Points to a Tree Object
  • Points to parent commit
  • Author + Committer
  • Commit message
  • Timestamp
Tree Object
  • Container for files/dirs
  • File mode (permissions)
  • File name → hash mapping
  • Points to Blob Objects
  • Can point to sub-Trees
Blob Object
  • Raw file content
  • No filename stored here
  • Same content = same hash
  • Stored in .git/objects/

If two files have identical content, Git stores only one Blob Object. The filename lives in the Tree Object, not the Blob — this is why Git is so storage-efficient.

Exploring Internals

You can inspect Git's objects directly with these plumbing commands:

bash
# View raw commit data
git show -s --pretty=raw <commit-hash>

# List files in a tree object
git ls-tree <tree-id>

# View a blob's content
git show <blob-id>

# Pretty-print any object
git cat-file -p <object-id>
Branching

Branches in Git

Work on multiple features simultaneously without affecting the main codebase.


What is a Branch?

A branch is an independent line of development. Multiple developers can work on different features in parallel — one on a header, another on a footer, another on auth — without stepping on each other's code.

main: ●──●──●──────────────● (merge commit)
               ╲              ╱
feature: ●──●──●

HEAD in Git

HEAD is a special pointer that always points to your current branch's latest commit. When you switch branches, HEAD moves with you. The default branch is now called main (previously master) — it's just a convention, nothing special.

Branch Commands

git branch
List all local branches
git branch <name>
Create a new branch
git switch <name>
Switch to a branch (modern way)
git switch -c <name>
Create and switch in one step
git checkout <name>
Switch to a branch (classic way)
git branch -m <old> <new>
Rename a branch
git branch -d <name>
Delete a branch (safe)

Always commit your work before switching branches. Uncommitted changes can cause conflicts or get overwritten when you switch.

Merging Branches

Merging brings changes from one branch into another. Git has two merge strategies:

Fast-Forward Merge

Used when the target branch has no new commits since the feature branch was created. Git simply moves the pointer forward — no merge commit needed.

bash
git checkout main
git merge bug-fix      # Fast-forward: no conflicts, clean history

3-Way Merge

Used when both branches have diverged (both have new commits). Git looks at 3 commits: the common ancestor + the tip of each branch, then creates a new merge commit.

Conflicts arise when both branches modified the same lines. You must manually resolve them — there are no shortcuts.

VS Code has an excellent built-in merge conflict editor. Look for "Accept Current Change", "Accept Incoming Change", or "Accept Both" options highlighted inline.

Managing Conflicts

Conflict resolution isn't scary — it's about communication with your team. When Git marks a conflict, it looks like this:

function greet() {
<<<<<<< HEAD
return "Hello World";
=======
return "Hi there!";
>>>>>>> feature-branch
}

Choose which version to keep (or combine them), then git add the resolved file and commit.

Advanced Commands

Diff, Stash and Tags

Powerful but often overlooked commands for debugging, context-switching and release management.


Git Diff

git diff compares different versions of files. Git treats the before and after as two separate files and highlights exactly what changed:

SymbolMeaning
a/The original file (before changes)
b/The updated file (after changes)
---Marks the start of the original file section
+++Marks the start of the updated file section
@@Shows line numbers where changes occur
- (red)Removed line
+ (green)Added line
git diff
Unstaged changes (working dir vs staging)
git diff --staged
Staged changes (staging vs last commit)
git diff <branch1> <branch2>
Compare two branches
git diff <hash1> <hash2>
Compare two specific commits

Git Stash

Stash is a temporary clipboard for uncommitted work. When you need to switch branches but aren't ready to commit, stash saves your changes to a stack:

bash
git stash                              # Save changes to stash
git stash save "WIP: login feature"   # Save with a name
git stash list                        # View all stashes
git stash apply                       # Apply most recent stash
git stash apply stash@{0}             # Apply specific stash
git stash pop                         # Apply + remove from list
git stash drop                        # Remove most recent stash
git stash clear                       # Remove all stashes

Git Tags

Tags are permanent bookmarks on specific commits — ideal for marking release versions like v1.0.0. Unlike branches, tags don't move when new commits are added.

Lightweight vs Annotated Tags

bash
# Lightweight tag (just a pointer)
git tag v1.0.0

# Annotated tag (stores metadata — preferred for releases)
git tag -a v1.0.0 -m "Release version 1.0.0"

# Tag a specific commit
git tag v0.9.0 <commit-hash>

# List all tags
git tag

# Push tags to remote
git push origin v1.0.0
git push origin --tags     # Push all tags

# Delete a tag
git tag -d v1.0.0
git push origin :v1.0.0    # Delete from remote

Always use annotated tags for releases — they store the tagger name, date, and a message, making them much more useful for changelogs and auditing.

History

Managing History

Keep your project history clean with rebase, and recover anything with reflog.


Merge Commits

A merge commit is automatically created during a 3-way merge. It has two parents and preserves the full history of both branches. This results in a non-linear history that explicitly shows when and where branches were merged.

Rebase in Git

Rebase rewrites commit history by replaying your branch's commits on top of another branch. The result is a clean, linear history — as if you had started your feature branch from the latest commit on main.

Before rebase:
main: A──B──C
             ╲
feature: D──E

After rebase (feature onto main):
main: A──B──C
                  ╲
feature: D'──E'
bash
# Switch to your feature branch
git checkout feature-branch

# Rebase onto main (replay your commits on top of main)
git rebase main

# If conflicts arise, resolve them, then:
git add <resolved-files>
git rebase --continue

# To abort the rebase entirely:
git rebase --abort

Never rebase shared public branches. Rebasing rewrites commit hashes, which breaks history for anyone else who has those commits. Only rebase local, unshared branches. Avoid --force unless you know exactly what you're doing.

Git Reflog

Reflog is your safety net. It records every movement of HEAD — even actions that aren't in regular git log output, like resets and rebases. This means you can recover almost anything.

bash
# View the full reflog
git reflog

# Example output:
# a3f8d21 HEAD@{0}: commit: add dark mode
# b9c1e45 HEAD@{1}: rebase (finish): refs/heads/feature
# c2d7f90 HEAD@{2}: checkout: moving from main to feature

# Recover a lost commit or branch
git reset --hard <commit-hash>
# or using HEAD reference:
git reset --hard HEAD@{2}

Reflog is local and expires after ~90 days by default. It cannot recover work that was never committed. Always commit (or stash) before risky operations!

GitHub

Collaborate with GitHub

Push your code to the cloud, set up SSH authentication, and collaborate with your team.


What is GitHub?

GitHub is a web-based Git repository hosting service — the most popular platform for open-source and team development. Alternatives include GitLab Bitbucket Azure Repos Gitea, but GitHub dominates the ecosystem.

Configuring Git

bash
git config --global user.email "you@example.com"
git config --global user.name "Your Name"
git config --list

Setup SSH Key

Password authentication is deprecated. SSH keys are the secure, recommended way to authenticate with GitHub:

1

Generate an SSH key

bash
ssh-keygen -t ed25519 -C "you@example.com"
2

Save the key

Press Enter to accept the default location (~/.ssh/id_ed25519). Optionally add a passphrase for extra security.

3

Add to ssh-agent

bash
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
4

Add public key to GitHub

Copy the output of cat ~/.ssh/id_ed25519.pub, then go to GitHub → Settings → SSH and GPG Keys → New SSH Key and paste it.

Publish Code to Remote

bash
# 1. Initialize and commit locally
git init
git add .
git commit -m "Initial commit"

# 2. Add remote repository
git remote add origin git@github.com:username/repo.git

# 3. Check your remote
git remote -v

# 4. Push and set upstream (first time)
git push -u origin main

# After that, just:
git push

Getting Code from Remote

git fetch origin
Download changes but don't merge
git pull origin main
Download + merge into current branch
git clone <url>
Copy a full remote repo to local
git remote add upstream <url>
Track the original repo (for forks)

🎉 Congratulations! You've completed the Chai aur Git series. You now understand version control from core concepts to real-world collaboration on GitHub. Keep practicing and happy coding!

Reference

Command Cheatsheet

All the essential Git commands in one place.


Setup

bash
git --version
git config --global user.name "Name"
git config --global user.email "email"
git config --global core.editor "code --wait"
git config --list

Repository Basics

bash
git init                    # Initialize new repo
git clone <url>             # Clone remote repo
git status                  # Check current state
git add <file>              # Stage a file
git add .                   # Stage all changes
git commit -m "message"     # Commit staged changes
git log                     # View commit history
git log --oneline           # Compact history

Branching

bash
git branch                  # List branches
git branch <name>           # Create branch
git switch <name>           # Switch branch
git switch -c <name>        # Create + switch
git merge <branch>          # Merge into current
git branch -d <name>        # Delete branch
git branch -m <old> <new>   # Rename branch

Diff & Stash

bash
git diff                    # Unstaged changes
git diff --staged           # Staged changes
git diff <branch1> <branch2>
git stash                   # Stash changes
git stash list              # List stashes
git stash pop               # Apply + drop stash
git stash apply stash@{0}   # Apply specific stash
git stash clear             # Clear all stashes

Remote & GitHub

bash
git remote -v               # List remotes
git remote add origin <url> # Add remote
git push -u origin main     # Push + set upstream
git push                    # Push (after -u set)
git fetch origin            # Fetch (no merge)
git pull origin main        # Fetch + merge
git pull                    # Pull (after -u set)

History Management

bash
git rebase <branch>         # Rebase current onto branch
git rebase --continue       # Continue after conflict
git rebase --abort          # Abort rebase
git reflog                  # View HEAD history
git reset --hard <hash>     # Reset to commit

Tags

bash
git tag                     # List tags
git tag v1.0.0              # Lightweight tag
git tag -a v1.0.0 -m "msg"  # Annotated tag
git push origin v1.0.0      # Push tag
git tag -d v1.0.0           # Delete local tag