Skip to content

Git: In a nutshell

nuriba edited this page Mar 19, 2025 · 17 revisions

Git is a distributed version control system, originally developed by Linus Torvalds (in 2005) to track Linux kernel development.

🔹 Installing Git

To install Git, use the following command based on your OS:

  • Windows: Download from git-scm.com
  • Mac: Install via Homebrew:
    brew install git
    

🔹 Basic Git Commands

📌 Initialize a New Repository

Creates a new Git repository in your project folder.

git init

📌 Clone an Existing Repository

Downloads a copy of a repository from GitHub.

git clone <repository-url>

Example:

git clone https://github.com/user/repository.git

📌 Check the Status of Your Repo

Displays modified files and staged changes.

git status

📌 Display History As A Tree

Display commit history as a visual tree.

git log --graph --oneline

📌 Changing Branches

branch, switch and checkout are all useful for branching. First one creates a new branch, second switches to another and third both creates and checks out a new branch.

git branch iss53

git switch iss53

git checkout iss53

🔹 Resources/ Useful Links

  • Git-reference categorizes common commands and gives clear descriptions of each command.
  • Oh My Git! is an open source game about learning Git. With its visuals and carefully designed levels, it's a fun way to master Git.
  • Git Cheat Sheet

🔹 Intermediate Git

📌 Cherry-Picking a Commit

git cherry-pick <commit-hash> applies a specific commit from another branch onto the current branch. It’s useful when you want to apply a fix or feature without merging the entire branch.

git cherry-pick a1b2c3d

This applies the commit a1b2c3d to the current branch.


📌 Merge vs Rebase

Merge (git merge)

Combines changes from another branch into the current branch, creating a new merge commit.
✅ Keeps commit history
✅ Preserves original branch structure
❌ Can cause merge commits (messy history)

git merge feature-branch

Rebase (git rebase)

Moves the current branch on top of another branch, rewriting commit history.
✅ Creates a linear history
✅ No merge commits
❌ Can cause conflicts if used incorrectly

git rebase main

📌 Squashing Commits (git rebase -i)

Squashing combines multiple commits into one, keeping the history cleaner.

  1. Run interactive rebase:
    git rebase -i HEAD~3  # Squash last 3 commits
  2. Change pick to squash (s) for the commits you want to combine.
  3. Save and close the editor.
  4. Edit commit message and finalize.

After squashing, push with force:

git push origin branch-name --force

📌 Resetting Commits (git reset)

git reset is used to undo local changes. It can modify the staging area (index) and the working directory depending on the options used.

Main Modes:

  1. Soft Reset --soft
  • Moves HEAD to the specified commit.
  • Keeps changes in the staging area (index)
  • Useful for undoing commits while retaining changes for further edits.
    git reset --soft <commit-hash>
  1. Mixed Reset (default)
  • Moves the HEAD pointer to the specified commit.
  • Resets the staging area to match the commit but keeps changes in the working directory.
    git reset <commit-hash> # Alternatively, git reset --mixed <commit-hash>
  1. Hard Reset --hard
  • Moves the HEAD pointer to the specified commit.
  • Resets both the staging area and working directory to match the commit.
  • ⚠️ All changes will be lost, so use with caution.
    git reset --hard HEAD~1  # Resets to the previous commit and discards changes
    git reset --hard a1b2c3d # Resets to the commit `a1b2c3d` and discards changes

📌 Reverting Commits (git revert)

Reverting a commit creates a new commit that undoes a previous commit. Unlike reset, it doesn’t modify commit history.

git revert a1b2c3d # Creates a new commit that negates the changes of the commit `a1b2c3d`.

Key Difference From reset:

git revert is safer because it does not rewrite history, making it useful for tracking our shared repository.

📌 Stashing Your Work (git stash)

Allowing you to “stash” (temporarily save) changes that are not ready to be committed. This is extremely useful when you need to switch branches quickly, or pull in updates without losing your local modifications.

git stash # Save uncommitted changes to a new stash

git stash list # List all stashed changes

git stash apply stash@{2} # Apply a specific stash from the list. 
#If you don't write stash@{number}, you will apply the most recent stash

git stash branch <new branchname> #Creates a branch from a stash

What Happens when you run 'git stash'?

It takes all the changes in your working directory which can be checked by running 'git status' command and staging area (index) and saves them in a special stash “stack” inside .git/refs/stash. After stashing, your working directory and the staging area are reverted back to the state of the last commit, so it looks like you haven’t made any local changes.

Resource Link: Stashing and Cleaning

📌 Cleaning Your Working Directory (git clean)

you may not want to stash some work or files in your working directory, but simply get rid of them; that’s what the 'git clean' command is for.

‼️ Important Note

The command designed to remove files from your working directory that are not tracked. This means that if you need them again, There is often no retrieving the content of those files.

Resource Link for stashing and cleaning: Stashing and Cleaning

📌 Git Fetch vs Git Pull (When to use fetch over pull)

Both git fetch and git pull are used to update your local repository with changes from a remote repository, but they behave differently.

git fetch

  • Downloads new changes (commits, branches, tags) from the remote repository without modifying your working directory.
  • You can review the updates before merging them.
  • It is useful when you want to check for updates without automatically applying them.
git fetch origin

git pull

  • Downloads changes and automatically merges them into your current branch.
  • Equivalent to git fetch + git merge.
  • Can lead to unexpected merge conflicts if changes are not reviewed beforehand.
git pull origin main

✅ When to use fetch instead of pull?

  • When working in a team and you want to see updates before merging.
  • When checking for remote changes without modifying your local branch.
  • To avoid potential merge conflicts when pulling unknown changes.

📌 Git Diff vs Git Show (Inspecting file changes effectively)

git diff

  • Shows changes between commits, branches, or working directory files.
  • Useful for reviewing modifications before committing.
git diff        # Show unstaged changes
git diff --staged   # Show changes that are staged for commit
git diff main feature-branch   # Compare two branches
git diff HEAD~1 HEAD  # Compare last commit with the current state

git show

  • Displays detailed information about a specific commit, including its changes and metadata.
  • Useful when investigating previous commits.
git show <commit-hash>

✅ When to use git diff vs git show?

  • Use git diff when you want to compare changes before committing.
  • Use git show when you want to examine a specific commit’s details.

📌 Git Ignore (.gitignore & .gitkeep)

Git provides .gitignore and .gitkeep to manage ignored files and track empty directories.

.gitignore (Ignoring files and directories)

  • Specifies files and folders that should not be tracked by Git.
  • Useful for ignoring compiled files, environment variables, or temporary files.
📌 Example .gitignore:
# Ignore node_modules and logs
node_modules/
logs/

# Ignore all .env files
*.env

# Ignore system files
.DS_Store

After defining .gitignore, you need to remove previously tracked files manually:

git rm --cached <file>

.gitkeep (Tracking empty directories)

  • Git does not track empty folders by default.
  • If you want to keep an empty directory in your repo, create an empty .gitkeep file inside it.
touch path/to/directory/.gitkeep
git add path/to/directory/.gitkeep

🚀 Use Case:

You want to keep an empty logs/ directory in the repo, for example your program will create log files and print log messages automatically when it runs. Create logs/.gitkeep to ensure it is tracked.


📌 Git Hooks

Git hooks are used to automate scripts to run before or after specific Git commands. They are stored in the .git/hooks directory.

Types of Git Hooks

Git hooks are categorized into client-side and server-side hooks. Below are some commonly used hooks:

Client-Side Hooks

  • pre-commit: Runs before a commit is created. Useful for linting or running tests.
  • commit-msg: Checks the commit message format.
  • pre-push: Runs before pushing changes to a remote repository. Can be used to ensure all tests pass before pushing.
  • post-commit: Runs after a commit is completed. Useful for notifications or logging.

Server-Side Hooks

  • pre-receive: Runs on the remote repository before accepting pushed commits. Can enforce policies like branch protection.
  • update: Similar to pre-receive, but runs once per branch.
  • post-receive: Runs after changes are accepted. Useful for deployment or notifications.

📌 Git Templates (Customize commit messages)

Git templates allow you to enforce structured commit messages by predefining message formats.

1️⃣ Set a Commit Message Template

You can define a standard commit message template that gets loaded into your commit editor. This helps using a clean and homogenous structure within the project.

git config --global commit.template ~/.gitmessage.txt

2️⃣ Example .gitmessage.txt Template

# Commit message template
# ----------------------
# Type (feat, fix, refactor, docs, test): Short description (max 50 chars)
#
# Body (Optional) - Explain what this commit changes
# - Use bullet points for clarity
# - Keep it concise
#
# Related Issue: #ISSUE_NUMBER (Optional)

3️⃣ Enforce Commit Format with Hooks

You can use Git hooks (e.g., prepare-commit-msg) to ensure all commits follow the template.

🚀 Why Use Git Templates?

  • Helps maintain consistent commit messages.
  • Ensures better readability and organization in team projects.
Clone this wiki locally