# All About Git and Github

### **1\. What is Version Control System (VCS)**

A software tool that helps developers track and manage changes to source code. It's like a **time machine** for your code.

### **1.1 Types of VCS**

### **1\. Local Version Control**

Keeps track of your source code on your local machine. Very hard to collaborate — you have to share code through pen-drive or email, so sharing and collaboration both suffer.

### **2\. Centralized Version Control (CVCS)**

Here we add a Central Server that all developers connect to. Still not a big improvement for collaboration — multiple developers can't work on the same file, since it locks a file when someone's editing it. If the main server goes down, everyone loses access, and history can be lost too.

### **3\. Distributed Version Control DVCS**

**Also uses a central server**, but every developer clones a full copy of the repo locally including its entire history. Most work happens offline. If the main server dies, any peer repo can restore it. No file locking, so multiple developers can edit the same file at the same time Git merges the changes. If two people edit the same line, Git raises a merge conflict that you resolve manually. Git doesn't just give you the latest files, it gives you the whole history too so you're not dependent on the central server and can work offline. It also introduced the concept of branching, which took collaboration to the next level. This is basically how Git works.

![](https://cdn.hashnode.com/uploads/covers/69137e4964be4c2a6ccf9fe9/f24daae1-352b-4eaa-8c7f-bef5c7f2b326.png align="center")

### **2\. The old system: Source Code Control System (SCCS)**

**SCCS** was the world's very first Version Control System (VCS), developed in 1972 by Marc Rochkind at Bell Labs for Unix machines.

### **How it Worked**

*   `s.` **Files:** When you tracked a file (e.g., `main.c`), SCCS created a hidden history file named `s.main.c` in the same directory.
    
*   **Deltas:** To save expensive storage space, it never copied the whole file. It only saved the line-by-line changes, known as **deltas**.
    
*   **Lock-based Access:** To edit a file, you had to run a command to **lock** it. Once locked, nobody else on that local system could edit it until you checked it back in and unlocked it.
    

### **Problem with older system**

*   **Strict File Locking:** Only one developer could edit a file at a time, completely slowing down teamwork. hard to collaborate
    
*   **Single File Tracking:** It could not track a group of files together. If you changed 5 files for one feature, you had to check them in one by one.
    
*   **No Network Support:** It only ran locally on a single machine there was no concept of internet, central sharing, or remote servers.
    
*   **Risk of Total Loss:** Since the entire history was packed into a single `s.` file, if that file got corrupted, your whole project history was permanently lost .
    
*   No support for branching
    

#### These are exactly why Linus Torvalds built Git

![](https://cdn.hashnode.com/uploads/covers/69137e4964be4c2a6ccf9fe9/290a5be0-4a75-4f30-b080-83cf7a842092.png align="center")

**Personal Note:** Git is not magic — it's just a time machine and snapshot manager for my code. I wrote these notes to clarify how Git thinks, how it manages files across local/remote stages, and how I handle real-world edge cases like merge conflicts and pull scenarios without panicking.

## 1\. Core Mental Models & Architecture

Before diving into commands, I need to keep two fundamental distinctions clear in my mind:

### Git vs. GitHub

*   **Git:** A free, open-source **Distributed Version Control System (DVCS)** that runs entirely on my local machine. It tracks file history and manages snapshots.
    
*   **GitHub:** A cloud-based platform that hosts my Git repositories remotely, enabling cloud backups, team collaboration, Pull Requests (PRs), and CI/CD pipelines.
    

![](https://cdn.hashnode.com/uploads/covers/69137e4964be4c2a6ccf9fe9/703fbc93-cd41-4215-bc93-e1e968f3b036.png align="center")

### The 3 Local Zones

When I work on a project, my code moves through 3 main zones before reaching GitHub:

![](https://cdn.hashnode.com/uploads/covers/69137e4964be4c2a6ccf9fe9/96c0175e-8ba4-48f8-9256-8ad3bcec05e7.png align="center")

1.  **Working Directory:** My actual workspace where I add, edit, or delete code files.
    
2.  **Staging Area (Index):** The draft layer where I organize and review specific changes before sealing them into history.
    
3.  **Local Repository (**`.git` **directory):** The database on my computer containing every committed snapshot (SHA-1 commit hashes).
    

![](https://cdn.hashnode.com/uploads/covers/69137e4964be4c2a6ccf9fe9/fdc8e8e1-ac08-4238-93b0-956693af1bb0.png align="center")

![](https://cdn.hashnode.com/uploads/covers/69137e4964be4c2a6ccf9fe9/e8eed48e-5e25-43f2-aec6-5140ee49680e.png align="center")

## 2\. One-Time Setup & Configuration

After installing Git, I must register my identity globally so every commit I create bears my signature:

```bash
git config --global user.name "Your name"
git config --global user.email "Your_email"

git config --list
```

## 3\. Daily Workflow & Snapshotting Commands

### Initializing & Status

*   Initialize a brand-new Git repository in my current folder
    
    ```bash
    git init
    ```
    
*   Clone an existing remote repository from GitHub to my local machin
    
    ```bash
    git clone <repository-url>
    ```
    
*   Check which files are modified, staged, or untracked
    
    ```bash
    git status
    ```
    

### Staging & Committing

*   Stage a specific file
    
    ```bash
    git add filename.js
    ```
    
*   Stage ALL modified, new, and deleted files in the workspace
    
    ```bash
    git add .
    ```
    
*   See unstaged differences between Working Directory and Staging Area
    
    ```bash
    git diff
    ```
    
*   See staged differences that are ready to be committed
    
    ```bash
    git diff --staged
    ```
    
*   Seal staged changes into a permanent snapshot with a descriptive message
    
    ```bash
    git commit -m "feat: implement user authentication API"
    ```
    

### File Management & Tracking Path Changes

*   Remove a file from the project AND stage the deletion
    
    ```bash
    git rm filename.js
    ```
    
*   Rename/move a file path AND stage the move
    
    ```bash
    git mv old-path.js new-path.js
    ```
    

## 4\. History Inspection & Navigation

*   Display the full commit history (Author, Date, SHA Hash, Commit Message)
    
    ```bash
    git log
    ```
    
*   View a clean, single-line history of my commits
    
    ```bash
    git log --oneline
    ```
    
*   View commit history with a visual graph representation of branches
    
    ```bash
    git log --graph --oneline --all
    ```
    
*   Inspect specific details of a single commit object by its SHA hash
    
    ```bash
    git show <commit-hash>
    ```
    

## 5\. Working with Remote Repositories (GitHub)

![](https://cdn.hashnode.com/uploads/covers/69137e4964be4c2a6ccf9fe9/08d4770f-9400-4a82-b1e6-ea481a53f4ae.png align="center")

Connecting my local project to GitHub and syncing changes:

*   Link my local repository to a remote GitHub URL (using 'origin' as alias)
    
    ```bash
    git remote add origin https://github.com/username/repo-name.git
    ```
    
*   Rename default branch to 'main’
    
    ```bash
    git branch -M main
    ```
    
*   Push local commits to remote repository (-u sets upstream tracking)
    
    ```bash
    git push -u origin main
    ```
    
*   Fetch and merge latest changes from remote tracking branch
    
    ```bash
    git pull origin main
    ```
    

## 6\. Branching, Merging & Rebasing

Branching lets me isolate new features or experimental code without breaking the stable code on `main`.

![](https://cdn.hashnode.com/uploads/covers/69137e4964be4c2a6ccf9fe9/a2865413-913d-4844-ac72-2409b49c345e.png align="center")

### Branching Commands

*   List all local branches (\* indicates current active branch)
    
    ```bash
    git branch
    ```
    
*   Create a new branch named 'feature/login'
    
    ```bash
    git branch feature/login
    ```
    
*   Switch to another branch
    
    ```bash
    git checkout feature/login
    ```
    
*   OR (modern Git syntax)
    
    ```bash
    git switch feature/login
    ```
    
*   Shortcut: Create and switch to a new branch immediately
    
    ```bash
    git checkout -b feature/login
    ```
    

### Integrating Branch Code

*   Merge 'feature/login' INTO my current active branch (e.g., main)
    
    ```bash
    git merge feature/login
    ```
    
*   Rebase my current branch on top of 'main' for a clean, linear history
    
    ```bash
    git rebase main
    ```
    

Creating a branch and writing code is only half the job. To safely integrate my work into the main project without breaking anything, I must follow a disciplined 4-step execution flow: **Commit Local Changes → Push to Remote → Create Pull Request (or Merge Locally) → Clean Up**.

#### Step 1: Stage & Commit Local Work

Ensure all new code, modified files, and fixes are cleanly saved into local snapshots.

*   Check modified/untracked files
    
    ```bash
    git status
    ```
    
*   Stage all changes
    
    ```bash
    git add .
    ```
    
*   Create a clear snapshot with a conventional commit message
    
    ```bash
    git commit -m "feat: implement user authentication flow"
    ```
    

#### Step 2: Push Feature Branch to GitHub

Upload the local branch to GitHub so it is backed up and visible for review.

*   Push branch and set upstream tracking (-u) for future pulls
    
    ```bash
    git push -u origin feature/user-auth
    ```
    

#### Step 3: Integrate Code into Main Branch

I have two choices depending on whether I'm following a **Team/PR Workflow** or **Solo/Local Workflow**:

#### Option A: The Team Standard Pull Request (PR) on GitHub

1.  Go to the **GitHub Repository** webpage.
    
2.  Click the yellow banner: **"Compare & pull request"**.
    
3.  Add a clear title, code summary, and click **"Create Pull Request"**.
    
4.  Once tests pass and review is complete, click **"Merge Pull Request"**.
    

#### Option B: Local Fast-Forward Merge

*   Switch back to main branch
    
    ```bash
    git checkout main
    ```
    
*   Fetch latest changes from server to avoid drift
    
    ```bash
    git pull origin main
    ```
    
*   Merge my feature branch into main
    
    ```bash
    git merge feature/user-auth
    ```
    
*   Push updated main branch to GitHub
    
    ```bash
    git push origin main
    ```
    

#### Step 4: Branch Cleanup

Once code is merged into `main`, delete the feature branch to prevent clutter.

*   Delete branch locally
    
    ```bash
    git branch -d feature/user-auth
    ```
    
*   Delete branch on remote (GitHub)
    
    ```bash
    git push origin --delete feature/user-auth
    ```
    

**My Mental Note on Merge vs. Rebase:**

*   `git merge` preserves historical context by creating a dedicated "Merge Commit".
    
*   `git rebase` rewrites history by moving my feature commits onto the tip of the target branch, keeping history straight and linear.
    

#### 1\. `git merge` (Preserving Context)

Integrates changes from one branch into another by creating a new **Merge Commit**.

*   **How it works:** Git takes the history of both branches and ties them together with a safety snapshot.
    
*   **Commit History:** Shows a branching tree structure (you can see exactly when branches diverged and re-joined).
    
*   **Pros:** Safe, non-destructive, and maintains true chronological history.
    
*   **Cons:** Commit history can quickly become cluttered with frequent "Merge branch..." commits.
    

![](https://cdn.hashnode.com/uploads/covers/69137e4964be4c2a6ccf9fe9/f8d50798-30c4-4410-8900-e70dd5fe814a.png align="center")

#### 2\. `git rebase`

Re-applies your feature branch commits on top of the target branch's latest commit.

*   **How it works:** It temporarily detaches your commits, updates your branch base to the tip of `main`, and replays your commits one by one.
    
*   **Commit History:** Clean, flat, and 100% linear (looks like all work was done sequentially in a single line).
    
*   **Pros:** Clean commit log, easier to navigate using `git log --oneline`.
    
*   **Cons:** Rewrites commit hashes/history. Can lead to complex conflict resolution if done incorrectly.
    

![](https://cdn.hashnode.com/uploads/covers/69137e4964be4c2a6ccf9fe9/b50d2aec-a663-499a-ac84-49f12c2e938c.png align="center")

*   Standard Rebase Workflow
    
    ```bash
    git checkout feature/login
    git rebase main
    ```
    
*   After rebasing, fast-forward merge into main
    
    ```bash
    git checkout main
    git merge feature/login
    ```
    

## 7\. Temporary Storage: Git Stashing

When I'm mid-task and need to switch branches quickly without committing half-finished, buggy code, I use **Stash**.

*   Temporarily stash modified and staged tracked files away
    
    ```bash
    git stash
    ```
    
*   View the stack list of my saved stashes
    
    ```bash
    git stash list
    ```
    
*   Re-apply the top stash AND keep it in the stash stack
    
    ```bash
    git stash apply
    ```
    
*   Re-apply the top stash AND delete it from the stash stack
    
    ```bash
    git stash pop
    ```
    
*   Discard the top stash completely
    
    ```bash
    git stash drop
    ```
    

## 8\. What Happens When I `git pull`? (My Decision Matrix)

When I pull code from the central server, Git behaves differently depending on whether my local code is committed or uncommitted:

| **Scenario** | **Local Code State** | **Remote Server Code** | **git pull Outcome** | **What happens to my code?** |
| --- | --- | --- | --- | --- |
| **Case 1** | **Committed** | No overlapping edits | **Auto-Merge Succeeded** | **Both preserved:** My commits + server commits stay together cleanly. |
| **Case 2** | **Committed** | Modified same lines | **Merge Conflict** | **I must manually decide:** Git pauses and inserts conflict markers in my code. |
| **Case 3** | **Uncommitted** | Modified same files | **Pull Blocked (Error)** | **Safety Lock:** Git aborts pull to prevent overwriting my unstaged work. |
| **Case 4** | **Uncommitted (Stashed)** | Any remote code | **Pull Succeeded** | **Clean Sync:** Server code downloads first, then I `git stash pop` my work back. |

## 9\. How I Handle Merge Conflicts (Step-by-Step)

When Git hits a line-by-line conflict during a `pull` or `merge`, it decorates the affected file with markers:

```jsx
<<<<<<< HEAD (My Local Code)
const userRole = "Admin";
=======
const userRole = "SuperAdmin";
>>>>>>> origin/main (Server Code)
```

### My Resolution Workflow:

1.  **Open the file** in VS Code (or text editor).
    
2.  **Choose the winning logic:**
    
    *   Accept Current Change (`Admin`)
        
    *   Accept Incoming Change (`SuperAdmin`)
        
    *   Or rewrite a combined solution.
        
3.  **Delete all Git markers** (`<<<<<<<`, `=======`, `>>>>>>>`).
    
4.  **Finalize the resolution :** Bash
    
    ```bash
    git add .
    git commit -m "fix: resolve merge conflict in user authorization"
    ```
    

## 10\. Undo, Reset & Ignoring Patterns

### Ignoring Unwanted Files (`.gitignore`)

I create a file named `.gitignore` in my project root to stop Git from tracking build logs, secrets, or dependency folders:

```plaintext
# Node dependencies
node_modules/

# Environment variables & secrets
.env
*.local

# Build outputs
dist/
build/
```

### Undoing & Resetting History

*   Unstage a staged file while retaining modifications in working tree
    
    ```bash
    git reset filename.js
    ```
    
*   Discard local uncommitted changes in working directory (Git Restore)
    
    ```bash
    git restore filename.js
    # OR
    git checkout -- filename.js
    ```
    
*   DANGER: Hard reset local repo, staging area, and workspace to a specific commit
    
    ```bash
    git reset --hard <commit-hash>
    ```
    

## 11\. Common Mistakes I Keep in Mind

*   Committed on the wrong branch (forgot to switch first)
    
    Check `git branch` before every commit session. If it happens: `git stash`, switch branch, then `git stash pop`.
    
*   Stuck in Detached HEAD state
    
    Happens when I checkout a commit hash instead of a branch. Fix: `git checkout main` to get back to a real branch, or `git checkout -b new-branch` to save the work.
    
*   Force pushed and overwrote someone's work
    
    Never use `git push --force` on shared branches like main. If really needed, use `git push --force-with-lease` — it fails safely if someone else pushed in between.
    
*   Committed a secret file (.env) by mistake
    
    Add it to `.gitignore` right away, then remove it from tracking with `git rm --cached .env`. If already pushed, rotate the secret — removing it from history is a separate, harder job.
    

Git and GitHub cheat sheet - https://education.github.com/git-cheat-sheet-education.pdf
