Skip to main content

Command Palette

Search for a command to run...

Git & GitHub — The Complete Developer’s Guide (From History to Advanced Commands)

A practical, beginner-friendly and deeply complete guide to everything Git — from history to branching, merging, stashing, diffs, commits, resetting,

Updated
•21 min read•View as Markdown
Git & GitHub — The Complete Developer’s Guide (From History to Advanced Commands)

This is a guide, which enough to contribute to open source / for collaborating with other / to work on your own projects.

What is Git?

Git is a Version Control System (VCS) — think of it as a time machine for your code.

It allows you to:

  • Track every change you make.

  • Go back to any previous version.

  • Work with others without overwriting each other’s code.

  • Maintain a complete history of your project.

Git is the tool that sits between you and chaos. It keeps your work safe, organized, and collaborative.


History of git - Story time :

Story Time — How Git Was Born

Back in the 2000s, Linux Kernel — one of the biggest open-source projects in the world — had thousands of developers contributing from all over the globe.

They initially used a commercial tool called BitKeeper to manage version control. But in 2005, its free license for open-source development was revoked.

So Linus Torvalds (the creator of Linux) famously said:

“Fine. I will build my own VCS.”

He wanted a tool that was:

  • ⚡ Fast (lightning fast).

  • 🌍 Distributed (no central server).

  • 🔐 Secure (every version cryptographically verified).

  • 🔀 Easy to merge code.

And in April 2005, Git was born.


🧠 What Does Git Actually Do?

Think of Git like Track Changes in MS Word/Google Docs —
but for code… and for multiple people at the same time.

Git is a Version Control System (VCS) — think of it as a time machine for your code.

Git keeps track of:

  • What changes were made

  • Who made them

  • When they were made

  • And lets you go back in time anytime you want

It enables safe and powerful collaboration on any project.


Where Is Git Used?

Git is everywhere:

1. Software Development

Used by all major tech companies:
Google, Microsoft, Netflix, Meta, Amazon, etc.

2. Open-Source Projects

Linux, React, TensorFlow, Python, Kubernetes —
all managed using Git + GitHub.

3. Freelancing / Startups / College Projects

Perfect for project management, research, documentation, design, and prototyping.


Why Is Git So Powerful?

Imagine you and a friend are writing a book together.

Without Git:

  • You send files via Email/WhatsApp

  • You lose track of versions

  • If both edit the same paragraph → total mess

With Git:

  • Both of you have your own copies (repositories)

  • You work separately and commit changes

  • Git merges edits cleanly

  • Every version is saved forever

Git = Smart Collaboration + Time Travel + Backup


Git vs GitHub

Git

A local version control system installed on your computer.
The engine that handles commits, branches, merging, etc.

GitHub / Git Lab / Bit bucket

Cloud platforms that host your Git repositories and allow team collaboration.

Think of it this way:

  • Git = Engine

  • GitHub = Parking place + Marketplace of repositories / projects

We have seen git is distributed VCS. But what is distributed ?


Centralized vs Distributed Version Control

Centralized Version Control

Everything is stored on one central server.
If the main server is down → no work can be done.

  • Single point of failure ❌

  • Clients depend on the server for history + version retrieval

Distributed Version Control (Git)

Every developer has a full copy of the repository.
Work continues even without the internet or server.

  • Everyone has a full copy of the project.

  • No dependency on a central server for work.

  • Collaboration is flexible and resilient.

  • Git, Mercurial follow this model.


How to access / use Git ?

  • Command line (Fast and Easy) (Most developers prefer this way).

  • Code Editors / IDE such as Git lens.

  • GUI such as Git Kracken, Source Tree.

Download the Git from git-scm, open Git Bash if you are on windows or You can directly use from terminal if you are on Mac OS or Any other Linux Distros.

Check whether the Git is installed properly or not by using:

git --version

You should see the version as output.


Settings:

First thing after installing the Git is to set and understand the Name, Email, Default Editor and Line Ending.

A system or a computer can have multiple users with different kinds of access in Unix bases OS es.

We can set these attributes on 3 levels:

  • System Level → For all users

  • Global Level → All repositories of the current user.

  • Local Level → The current repository.

What is repository ? We will look that further in this blog.

Let’s continue with Settings:

Command format goes something like below

git config --<level> user.<attribute> "attribute details"

Let’s see how we generally setup these things in daily life:

  1. Name:

     git config --global user.name "Muzammil Shaik"
    
  2. Email:

     git config --global user.email "abcd@gmail.com"
    
  3. Code Editor:

    • By default the code editor is Vim (Some people are scared of it), If you want to change, Let’s set it to VS code:

        git config --global core.editor "code --wait"
      
    • when you execute the above command, It opens up a new window in vs code. After editing and making the changes, Just save it and close the window, because the terminal will be waiting for you to close the window. If it’s not closed, Terminal will keep waiting until its closed.

    • To access or edit the file:

        git config --global -e
      
  4. End of the lines:

    • In Windows, It ends with two escape characters - CRLF (Carriage return line feed) :

      • \r → Carriage return.

      • \n → Next line or Line feed.

    • In Mac OS / Linux Distros - LF (Line feed) :

      • \n → Next line or Line feed.
    • This can create problems where Git shows changes even when nothing actually changed.

    • When collaborating, People uses different OS in their machines, Let’s understand this with a picture.

    • Windows:

        git config --global core.autocrlf true
      
    • What does this do ?

      • Prevents weird extra changes.

      • Keeps repository clean.

      • Makes your local files compatible with Windows.

    • Mac OS / Linux:

        git config --global core.autocrlf input
      
    • What does this do for Mac OS / Linux ?

      • Ensures the repository stays with clean LF endings.

      • Your local editor (VS Code, Vim, etc.) remains unchanged.

  5. Need any help with command:

     git commit --help # Pulls Docs in terminal.
     git commit -h # Pulls short summary of each command.
    

Creating a Directory and Getting Started with Git:

Before we dive into creating repositories. I want you guys to try some handy Linux commands, which will be very helpful further.

  1. Create a new directory/folder through terminal:

     mkdir Moon # mkdir - Make Directory
    
  2. Change Directory: (Going inside of the folder)

     cd Moon
    
  3. To print something on the terminal, We use:

     echo "hello" # Outputs - hello
    
  4. To insert over write something into a file:

     echo "hello" > file.txt
    
    • Create a file if file.txt does not exist in the current repository.

    • If file already exists then, Overrides all its content with hello.

    • To just append things to file contents we can use “>>“ instead of “>“.

I think that’s more than enough to understand, If you wanna dive deep you can checkout my Linux commands blog. If there are any commands remained, we will discuss them as we move forward.


Staging:

We will create a new directory / folder called git-practice.

mkdir git-practice # Creates a New Directory
cd git-practice # Going inside of git-practice folder.

Now git-practice is a directory, It’s not a repository yet.

To create a new repository inside the git-practice, use the following command:

git init # Initializes git repository in the current folder

This command will create a .git folder inside the current folder. It will not be visible but you can see it by un-hiding the hidden folder or you can type:

ls -a # This will show all the hidden files.

This is the folder responsible for tracking every information you save in using git.

If this folder is gone, You cannot recover it, So be cautious.

/git-practice/.git - Is called as git repository of that particular folder.

/git-practice is the project folder.

Let’s create a two files. We have already discussed how to create new files using command line.

file1.txt and file2.txt.

Think of it like a marriage ceremony, Where people will be waiting in line to meet the bride or bride-groom to take a picture. That picture will go to marriage photo album.

Here,

  • People who are waiting in the line are un-staged (About to take a picture / Waiting to take a picture).

    Queue is a staging area.

  • People who are on the stage are staged people. They can take picture any time.

  • Marriage photo is a snapshot of that day. It’s called commit in git. Your codes screenshot has been taken if committed.

  • Once committed you can

    • Review that any time.

    • Revert to that particular time and see how it looks at that time.

    • Basically do whatever you want. That is the whole idea right !!!

  1. To see the status of the current files we use status commands:

     git status # Shows what are all the tracked/staged files or untracked/unstaged files
    

If it says untracked files, They are not added into the staging area yet !!!

  1. To track the changes / To get them on stage we need to use:

     git add . # . -> refers to all unstatged files in the current working directory recursively
     git add <filename> # Adds only that particular file in the staging area
     git add <file1> <file2> # We can add multiple files at once.
    

Just like whom you want to go on to the stage.

  1. To take a picture or snap shot of code use:

     git commit -m "Two files added" # This will create a commit or Snapshot of the code.
    
     # You can use short-form
     git commit # open the default editor and add short description and close it.
    

You can view whether the snapshot has been taken or not by using the following command:

git log # Will show all the commits in the current git repository.

Disclaimer: When we actually work in an organization, We don’t directly commit like above. We will create a new branch for every single feature and then we will add all files and then we will commit them. Now you might have questions like what is branching ? Don’t worry we will discuss it further !

We will continue learning, after discussing some best practices of commits:


Best Practices Of Commits:

  1. Our commit should not be too big or too small.

  2. As you reach a stage where you want to record and then make a commit.

  3. Each commit should represent the logical update / feature.

  4. Bug fixes, Typos → Two different commits, Make it meaningful. It’s upto the maintainer how he wants to arrange these commits.

  5. Wording in commit messages should be present tense. (Fix bug in user authentication). It should NOT be like Fixed bug in user authentication.


Branching in Git

Branching is one of the most powerful features in Git.
It allows you to create separate timelines (or “paths of development”) inside the same project without affecting the main code.

This means you can:

  • Work on new features

  • Fix bugs

  • Experiment safely

  • Merge work back when ready

All without breaking the main project.


Why Branching?

Without branching:

  • You change code directly on main

  • Risk of breaking production

  • Hard to work on multiple features simultaneously

With branching:

  • Each feature gets its own isolated workspace

  • Main branch stays clean

  • Collaboration becomes easier

  • Merging integrates your changes safely


Visual Explanation of Branching

Imagine your project timeline:

A --- B --- C   (main)

You create a new branch:

A --- B --- C   (main)
           \
            D   (feature-login)

You now have two timelines:

  • main branch (stable)

  • feature-login branch (your new work)

You can update the feature branch independently.

If you add more commits:

A --- B --- C               (main)
           \
            D --- E --- F   (feature-login)

When work is complete, you merge it back.


Creating and Working With Branches

Create a new branch

git branch feature-login        # Create a branch

Switch to another branch

git checkout feature-login      # Move HEAD to this branch

Modern version:

git switch feature-login        # Switch branch (recommended)

Create + switch in one command

git switch -c feature-login     # Create and switch immediately

List all branches

git branch                      # Shows all local branches

Current branch is marked with *.


Merging Branches

After finishing work on the feature branch, merge it into the main branch.

Step 1: Switch to main

git switch main                 # Move to main branch

Step 2: Merge the feature branch into main

git merge feature-login         # Merge feature-login into main

Visual representation of merging:

Before merging:

main:    A --- B --- C
                  \
feature:           D --- E

After merging:

main:    A --- B --- C --------- M
                  \             /
feature:           D --- E ----

Depending on project structure and commit history, Git may:

  • Perform a fast-forward merge (if main has not moved)

  • Create a merge commit (if both branches have diverged)


Pulling and Pushing (Remote Integration)

Add remote URL (connect GitHub)

git remote add origin <repo-url>      # Connect local repo to GitHub
  • origin is the name of the url

Push code to GitHub

git push -u origin main               # First push + set upstream tracking

Pull the latest changes

git pull origin main                  # Fetch + merge changes from GitHub

Skipping The Staging Area:

git commit -am "Fix the bug the users form sign up"

- a → This flag represents add all to staging area.

You know the rest.


Removing Files:

git ls-files # shows all the files in the statging area
  • To remove the files from staging area, just add it again with file name.

      git add file2.txt # removes the file2.txt file from staging area even though
                        # its not in project folder.
    
  • Now we have made a change, What should we do ? If you said “We should commit“ , Then you’re absolutely correct. Deletion is also a change right ?

  • You can directly remove from staging area using:

      git rm file2.txt
    

    rm → Means remove


Renaming or Moving Files:

In Git (and your terminal), you can rename or move files using the mv command.

mv file1.txt main.js

The mv command does two things:

  1. Renames the file

  2. Moves a file/folder from one directory to another
    (if a new path is provided)


What Happens in Git When You Rename?

When you rename file1.txt → main.js, two things happen:

  1. file1.txt becomes deleted in the project directory but still exists in the staging area.

  2. main.js is treated as a new file, even if the content is the same.

Git sees renamed files as:

  • One file deleted

  • One file created

(because Git tracks content, not file names)


Add Both Files to Staging Manually

git add file1.txt main.js

But there is a better way…


Do Everything in One Command

Git provides a shortcut:

git mv file1.txt main.js

This:

  • Renames the file

  • Removes the old file

  • Adds the new file to staging

  • Does everything in one step


🗑️ Ignoring Files

To ignore files or directories:

  1. Create a folder:
mkdir logs

(This line continues in the next image—send the next page and I’ll complete it.)


Ignoring Files & Folders in Git

Git allows you to ignore specific files or directories so they are not tracked. This is useful for:

  • Log files

  • Build folders

  • Temporary files

  • Environment files

  • OS-specific junk files

Let’s walk through it step by step.


Create a directory to ignore

mkdir logs

Creates a new directory.


Create a file inside it

echo "hello" > logs/dev.log

Adds a file with some content.


Check the Git status

git status

You will see:

Untracked files:
   logs/

Git will attempt to track all files unless you explicitly tell it not to.


Tell Git to Ignore Specific Files/Folders

To ignore files or directories, create a .gitignore file.


Add “logs/” to .gitignore

echo logs/ > .gitignore

The / at the end indicates it is a directory.


Add and commit the .gitignore file

git add .gitignore
git commit -m "Add .gitignore"

Now Git knows that anything inside logs/ must be ignored.


Example .gitignore Structure

#photo-5

logs/
*.txt
*.env

If you already committed a file or folder earlier, and then you add it to .gitignore, Git WILL NOT ignore it until you remove it from tracking.

This is a common mistake.


Removing Files/Folders That Were Accidentally Committed

To check what's tracked

git ls-files

This will show files like:

bin/app.bin

If you want to remove a tracked file from both disk & Git

git rm bin/

This removes it from:

  • Working directory

  • Staging area

(Everything deleted permanently)


But we usually want to remove it only from tracking, not from disk.

To do that:

Understanding git rm Options

7️⃣ View help for rm

git rm -h

You’ll see the --cached flag:

--cached   # only remove from the index (staging area)

Remove folder only from Git (not from disk)

git rm --cached bin/

Now the entire bin/ directory is removed from tracking only.
It remains physically present on your computer.

If you want to remove all its files recursively:

git rm -r --cached bin/

Whatever you do in Git — create, delete, modify — is a change.
To save the change, you must commit it.


Commit the removal

git commit -m "Remove bin/ directory that was accidentally committed"

From this point onward, Git will stop tracking changes inside the bin/ folder because:

  • You removed it from tracking

  • You added it to .gitignore


Bonus: GitHub’s .gitignore Templates

GitHub provides ready-made .gitignore templates for all languages & frameworks.

Visit:

github-language-specific-templates

Useful templates include:

  • Node.js

  • Python

  • Java

  • React

  • Go

  • Android

  • macOS / Linux / Windows system files


Short Status in Git

Checking the status of your files

git status       # Shows the status of tracked and untracked files

To make the output cleaner and more compact, use:

git status -s    # Short status view

Short status symbols:

M  file.js    # Modified
A  file.js    # Added
?? file.js    # Untracked

Viewing Staged and Unstaged Changes

git status only shows which files are modified.
To see what has changed inside those files, you must use git diff.

View changes that are staged (ready to commit)

git diff --staged    # Shows differences between staged files and the last commit

It displays every single line that will go into the upcoming commit.

Example output:

diff --git a/file1.js b/file1.js
index 1bd0b0d..47c8321 100644
--- a/file1.js
+++ b/file1.js
@@ -1,3 +1,5 @@
 hello
 world
 test
+sky
+ocean

View unstaged changes (working directory vs staging area)

git diff     # Shows what is in your working directory vs what is staged

This compares:

  • Working directory

  • Staging area


Visual Diff Tools

You can also use external tools to compare changes visually:

  1. KDiff3

  2. P4Merge

  3. WinMerge (Windows only)


Configuring a Visual Diff Tool

Set a diff tool globally

git config --global diff.tool vscode    # Assign a tool name "vscode"

This does not automatically set VS Code as the actual diff tool yet.
You must specify how VS Code should behave.

Configure how the diff tool runs

git config --global difftool.vscode.cmd "code --wait --diff $LOCAL $REMOTE"
# Tells Git to launch VS Code for diffing local and remote versions

Editing Global Git Configurations

git config --global -e    # Open global config file in default editor 
                            # (usually VS Code)

This lets you edit your global Git settings.

Example:

git config --global user.name "Muzammil Shaik"     # Set your global Git username

When you open .gitconfig, you will see something like this:

[user]
    name = Mosh Hamedani
    email = pro.me@gmail.com

[core]
    autocrlf = input
    editor = code --wait

This looks similar to JSON key-value structure.
Just an observation—Git config format is its own style.


Comparing Working Directory vs Staging Area

Using diff tool for working directory

git difftool       # Shows difference between working directory and staging area

7. Using diff tool for staged content

git difftool --staged    # Shows staged changes compared to the last commit

Example output:

- hello
  world
  test
  sky

+ hello
  world
  test
  sky

Note:

Today, most modern code editors (VS Code, JetBrains IDEs, etc.)
automatically show diffs inline.
You do not need to explicitly run difftool unless you want to.


Viewing Commit History in Git

View full commit history

git log    # Shows complete commit history from latest to oldest

This displays details such as:

  • Commit hash

  • Author

  • Email

  • Date

  • Commit message

Example:

commit e7e8c3d1ab...
Author: Your Name <email@gmail.com>
Date: Tue Aug 4 16:56:10 2020 -0700

    Remove the bin directory

View commit history in one line per commit

git log --oneline     # Shows short commit ID + message

To reverse the order:

git log --oneline --reverse   # Oldest → Latest

Viewing a Specific Commit

Show a commit using its ID

git show d601690      # Shows diff and details of this specific commit

Show a commit relative to HEAD

git show HEAD~1       # Shows the commit just before the latest commit

Explanation:

  • HEAD → refers to the current/most recent commit

  • HEAD~1 → one commit behind

  • HEAD~2 → two commits behind, etc.

This command shows the diff of that commit.


Viewing Exact File Contents from a Previous Commit

Show a file from an older commit

git show HEAD~1:.gitignore   # View the .gitignore file as it existed one commit ago

path → path to the file inside the repo.

Example output:

logs/
main.log
*.log
bin/

Showing the Latest Commit

Show the commit HEAD points to

git show HEAD       # Shows the latest commit and its diff

If you want to see ALL files and folders changed in the commit instead of diff, use the tree.


Viewing File and Folder Structure of a Commit

Use Git’s internal tree structure

Git stores your filesystem in a tree data structure.

To list files and folders inside a commit:

git ls-tree HEAD~1         # Shows files/folders modified one commit before HEAD

Example output structure:

100644 blob a7d8c...    file.txt
040000 tree b921f...    src

Explanation:

  • blob → represents a file

  • tree → represents a directory

  • Git stores everything as objects (commits, blobs, trees, tags)


Unstaging Files

Unstage a file (move from staged → unstaged)

git restore --staged file1.js    # Unstages file1.js

This keeps the file in your working directory but removes it from the staging area.


Discarding Local Changes

Undo all local changes in tracked files

git restore .       # Undo all local changes in working directory

If some files still remain, it means:

  • They are untracked

  • Git has no previous version of those files


Remove untracked files/folders

git clean -fd       # -f = force, -d = remove directories

Be careful — untracked files will be permanently deleted.


Restoring a File to an Earlier Version

If you accidentally deleted or modified a file, you can restore it from the previous commit.

Restore a file from an older commit

git restore --source=HEAD~1 file1.js
# Restores file1.js to how it looked one commit ago

Hidden Files/Folders in Git

Any filename that begins with a dot (.) represents a hidden file or folder.

Examples:

  • .gitignore

  • .git/

  • .env


Resetting to a Specific Commit

To go to a specific snapshot, copy the hash of the commit.

Reset to a specific commit (undo commits)

git reset <commit-hash>    # Move HEAD and branch pointer to this commit 
                            # (soft by default)

Soft reset explanation:

  • Keeps your working directory untouched

  • Moves HEAD pointer

  • Useful for modifying or redoing commits


Git Stash (Temporary Shelving for Work)

Stash is used when you want to switch branches but have unfinished work.

Save changes temporarily

git stash                             # Save staged + unstaged changes

See all stashes

git stash list                        # Show list of saved stashes

Apply last stash (keep it in stash list)

git stash apply

Apply and remove stash

git stash pop

Reset vs Revert

Reset (rewrites history)

git reset --soft <commit>             # Move HEAD, keep all changes staged
git reset --mixed <commit>            # Move HEAD, unstage changes (default)
git reset --hard <commit>             # Move HEAD, delete all changes

Reset rewrites commit history.
Use with caution.


Revert (safe undo)

git revert <commit>                   # Creates a new commit that undoes an 
                                    # old commit

Revert is safe for team collaboration because it does not rewrite history.

So that it about the git. I know it’s a long blog. Please use it as resource when you want quick reference or knowledge base.

In the next blog we will discuss about how we use git in open-source contributions.