Learn Version Control with Git: A Practical Guide to Commands and Workflows

If you've ever worked on a project and wished you could go back to a previous version, track your changes, or collaborate seamlessly with others, Git is a tool worth learning. While Git is a cornerstone in the software development world, it is just as useful for writers, researchers, students, designers, or anyone managing files and revisions over time.

In this article, you'll learn:

  • What Git is and how it works
  • The practical benefits of using Git
  • Common terminology made easy to understand
  • Essential Git commands explained clearly
  • Real-world workflows to help you get started

By the end, you’ll be confident using Git for personal or professional projects, with a clear understanding of how to version and manage your work effectively.

What It Is #

Git is a version control system. It helps you track and manage changes to files over time. Think of it like a save button for your entire project, but with a history. You can go back to previous versions, see what changed, who made the changes, and when.

Git is distributed, meaning every user has a full copy of the project history. This makes collaboration easier and safer. You can work on new ideas, fix problems, or test changes without affecting the main project until you're ready.

Git handles all types of files, not just code. It’s ideal for:

  • Writing projects (e.g., articles, books)
  • Research notes
  • Personal documents

Git is not well suited for large binary files like images or videos, as it cannot efficiently track changes in them. For such files, consider using specialised tools like Git Large File Storage (Git LFS) or dedicated asset management systems.

In short, Git lets you:

  • Save your work often
  • Revert mistakes
  • Collaborate smoothly
  • Experiment safely

It’s like having an undo button, timeline, and backup system all in one.

Key Features

  • Version control: Keep a detailed history of every change. You can view edits, compare versions, and roll back to earlier states if needed.
  • Branching: Create separate environments to work on new features, fix issues, or test ideas. All without affecting your main files.
  • Merging: Combine changes from different branches into one final version. Git helps detect and resolve conflicts along the way.
  • Distributed system: Every user has a complete copy of the project, including its full history. You don’t need a central server to work or access previous versions.

Why Use It

  • Reliability: Since all data is stored locally as well as remotely, your work is safe even if a server fails or you're offline.
  • Speed: Most actions (saving changes, viewing history, switching versions) are performed on your local machine, making Git extremely fast.
  • Collaboration: Git makes teamwork seamless. Multiple people can work on different parts of a project at the same time using branches, then merge their work together without overwriting each other.
  • Auditability: Every change is recorded with the author's name, date, and a short message describing what was done. This makes it easy to track who changed what and why.

GitHub

GitHub is a cloud-based hosting platform for Git repositories. It adds powerful features for team-based development and project automation, including:

  • Pull requests and code reviews to discuss and approve changes
  • CI/CD pipelines such as GitHub Actions to automate testing and deployment
  • Issue tracking for bug reports, tasks, and feature requests
  • Project management tools like boards, milestones, and labels

Typical Workflow

Developers commonly follow this pattern:

  • Use Git locally to write and manage code on their own machine
  • Push to GitHub to collaborate with others, share progress, and automate workflows

This separation allows Git to handle version control and GitHub to handle collaboration, visibility, and automation.

Terminology #

Repository (Repo)

A repository is a project folder managed by Git. It contains your files and all the information Git needs to track and manage changes over time.

Key Components

  • Project files – your actual content (e.g. code, documents)
  • .git/ directory – a hidden folder that stores:
    • Complete version history
    • Change tracking metadata
    • Configuration settings

Types of Repositories

  • Local repository
    • Stored on your own machine
    • Lets you work offline
    • Includes full project history
  • Remote repository
    • Hosted on a server (e.g. GitHub)
    • Used for collaboration and backup
    • Acts as the shared source of truth

Typical Workflow

  1. Clone a remote repository to your machine
  2. Pull updates from the remote when others make changes
  3. Push your changes to the remote to share your work

Working Directory

The working directory is the folder on your computer where you actively edit your files. It’s what you see and interact with directly.

Key Points

  • Definition: The folder where you make changes to your project files
  • Example: If you open ~/dotfiles, you are working in that directory

Git does not track your edits here until you stage them. Changes remain untracked or modified until added with git add.

Staging Area (Index)

The staging area (also called the index) is a space where you prepare changes before permanently saving them in the repository. It acts like a checklist: you choose which changes to include in the next commit.

Key Points

  • Purpose: Gives you control over what goes into each commit
  • Use case: Useful when you want to commit only some of your changes, not all at once
  • Command:
bash
git add <file>

This command adds specific changes to the staging area.

Workflow Example

  • You edit several files
  • Use git add to select the ones you want to include
  • Then run git commit to save only those selected changes to the repository

This lets you group related changes logically and keep your history clean and understandable.

Commit

A commit is a snapshot of your project at a specific point in time. It records what was changed, by whom, and why. Each commit creates a permanent entry in the project history, allowing you to revisit, compare, or restore past versions.

What a Commit Includes

  • A unique ID (called a SHA hash)
  • Author information (name and email)
  • A commit message describing the change

Command

bash
git commit -m "<message>"

This saves the staged changes with a clear message explaining what you did. Commits help you track progress and keep your work organised. A good commit message makes it easier to understand what changed and why.

Branch

A branch is a lightweight pointer to a sequence of commits. It lets you work on new features, fixes, or experiments without affecting the main project.

Branches are key to safe and organised development. You can switch between them, develop separately, and merge your work when it’s ready.

Key Points

  • Purpose: Isolate work so the main project remains stable
  • Default branch: Usually named main or master
  • Command:
bash
git branch <branch>

Use branches to:

  • Develop features independently

  • Fix bugs without interrupting other work

  • Experiment freely, knowing the main version stays untouched

Once finished, you can merge the branch back into the main project.

Merge

Merging is the process of combining changes from one branch into another. It brings together work done in separate branches so the project stays unified.

Git attempts to merge automatically. If two branches changed the same part of a file, Git will ask you to resolve the conflict manually.

Key Points

  • Purpose: Integrate work from different branches
  • Common use: Combine a finished feature branch into the main branch
  • Command:
bash
git merge <branch>

This merges the specified branch into your current branch.

Example Workflow

1. Switch to the branch you want to merge into:

bash
git checkout main

2. Merge the feature branch:

bash
git merge feature-login
  • Always review changes before merging

  • Use branches to keep features isolated, then merge when stable and tested

Conflict

A conflict happens when Git cannot merge changes automatically because the same part of a file was modified differently in two branches.

What Happens

  • Git stops the merge
  • Marks the conflicting sections in the file
  • Requires you to review and fix the differences manually

How to Resolve

  1. Open the conflicted file
  2. Look for conflict markers (<<<<<<<, =======, >>>>>>>)
  3. Edit the file to choose or combine the changes
  4. Save the file
  5. Add the resolved file to staging:
bash
git add <file>

Complete the merge by committing:

bash
git commit -m "<message>"

Resolving conflicts carefully ensures your project stays consistent and all changes are accounted for.

Remote

A remote is a version of your repository hosted on another server or service, such as GitHub. It allows you to:

  • Share your work with others
  • Backup your project online
  • Collaborate from different locations

Key Points

  • Acts as a central copy of your project
  • Synchronises changes between your local repository and the remote

Command:

bash
git remote add origin <url>

This command connects your local repository to a remote repository, typically named origin.

After setting this up, you can:

  • Push your changes to the remote
  • Pull updates from the remote to your local copy

Clone

Cloning means downloading a complete copy of a remote repository to your local computer.

Key Points

  • Used once to get the project files and full history locally
  • Sets up a local repository linked to the remote

Command

bash
git clone <url>

Example:

bash
git clone https://github.com/user/project.git

This creates a local folder with all the files and version history, ready for you to work on.

Pull

Pulling means fetching changes from the remote repository and merging them into your local copy.

Key Points

  • Keeps your local repository up to date with the remote repository
  • Combines two actions:
    • Fetch: Download changes
    • Merge: Integrate changes into your current branch

Command

bash
git pull

Use this regularly to ensure your local files reflect the latest remote updates before starting new work.

Push

Pushing means sending your local commits to the remote repository.

Key Points

  • Updates the remote repo with your changes
  • Shares your work with others
  • Usually done after committing locally

Command

bash
git push

Use this to upload your latest commits so others can access them and collaborate.

Fetch

Fetching downloads new commits and updates from the remote repository but does not merge them into your local branch.

Key Points

  • Retrieves changes without changing your working files
  • Lets you review updates before integrating them
  • Keeps your local copy aware of remote progress

Command

bash
git fetch

After fetching, you can inspect changes and decide when to merge or rebase them into your work.

HEAD

HEAD is a pointer that references the current commit or branch you are working on.

Key Points

  • Indicates your current position in the project history
  • Moves as you switch branches or check out commits
  • Shows the latest commit in your working directory

Commands Related to HEAD

View current commit and history:

bash
git log

The top entry is where HEAD points.

Change HEAD to a different commit or branch:

bash
git checkout <commit>

or

bash
git switch <branch>

HEAD helps Git know which snapshot you are currently working with.

Reset

Reset moves the HEAD pointer to a specific commit and can optionally update your staging area and working files.

Types of Reset

Reset Type Description Effect on Changes
--soft Moves HEAD to the chosen commit Keeps changes staged (ready to commit)
--mixed default Moves HEAD to the chosen commit Unstages changes but keeps them in working directory
--hard Moves HEAD to the chosen commit Discards all changes in staging and working directory (irreversible)

Use Cases

  • Undo commits but keep changes (--soft)
  • Unstage changes but keep edits (--mixed)
  • Completely reset to a clean state (--hard)

Example:

bash
git reset --hard HEAD~1

This moves HEAD back one commit and deletes all changes made since then. Use with caution.

Revert

Revert creates a new commit that undoes the changes introduced by a previous commit, without altering the project history.

Key Points

  • Safely reverses changes in shared branches
  • Does not delete or rewrite history like reset
  • Preserves collaboration integrity by adding a “fix” commit

Use Case

Use git revert when you want to undo a change but keep the commit history intact, especially when working with others.

Command:

bash
git revert <commit_hash>

Workflow

1. Display commit history:

bash
git log --oneline

Output example:

text
e3a1f45 fix: broken image path
b2d3c7a add: user authentication
7f9e5a1 Initial commit

The left part (e.g. e3a1f45) is the commit hash, used to identify a specific commit.

2. Identify and copy the commit hash you want to revert

3. Run revert:

bash
git revert <commit_hash>

This creates a new commit that reverses the changes introduced by the specified commit, preserving history.

Checkout

This checkout command lets you change branches or restore files from a specific commit.

Key Points

  • Switch branches to work on different lines of development
  • View past versions of your project by checking out a specific commit (detached HEAD state)

Commands

Switch to a branch:

bash
git checkout <branch>

View a past commit (detached HEAD state):

bash
git checkout <commit>

Using git checkout helps you navigate your project’s history and switch between tasks efficiently.

Log

The log command lets you view the commit history of your project.

Key Points

  • Shows a timeline of all commits
  • Helps track what changed, when, and by whom

Commands

Detailed commit history:

bash
git log

Summary view with one line per commit:

bash
git log --oneline

Use the log to understand your project’s progression and review past changes efficiently.

Diff

The diff command shows the differences between files or commits, helping you see what has changed.

Key Points

  • Compare unstaged changes against the last commit
  • Compare staged changes ready to be committed
  • Compare differences between two commits

Commands

Show unstaged changes:

bash
git diff

Show staged changes (what’s ready to commit):

bash
git diff --staged

Show differences between commits:

bash
git diff HEAD~1 HEAD

Use git diff to review edits before committing or merging.

Stash

Stash lets you temporarily save changes that you aren’t ready to commit yet, so you can switch tasks or branches without losing work.

Key Points

  • Saves your current changes aside safely
  • Allows you to work on something else
  • Later, you can reapply the saved changes

Commands

Save your changes:

bash
git stash

Reapply saved changes:

bash
git stash apply

Stashing is useful when you need a clean working directory but want to keep your unfinished work for later.

Tag

A tag is a label you attach to a specific commit to mark important points in your project, such as releases or milestones.

Key Points

  • Marks a commit with a meaningful name
  • Commonly used to identify versions (e.g., v1.0, v2.1)
  • Tags are easy to reference later

Command

bash
git tag v1.0

This command tags the current commit as v1.0. You can also tag earlier commits by specifying their ID.

.gitignore

Always set up a .gitignore file to exclude sensitive files (e.g., credentials, keys, config files) from your repository. This prevents accidental publishing of sensitive information on GitHub or other remote platforms. Double-check your .gitignore before pushing changes.

The .gitignore file tells Git which files or folders to ignore and not track in the repository.

Key Points

  • Prevents unnecessary or sensitive files from being committed
  • Uses patterns to specify files or directories to exclude

Example

.gitignore
# Backup files
*.bak

# Logs and temporary files
*.log
*.tmp

# Editor and project configuration
.prettierignore
.prettierrc
.vscode/
.workspace

# Git-related files
.gitignore~
.git/

# OS and system files
.DS_Store
.Spotlight-V100
.Trashes

# Secrets and credentials
*.key
*.pem

Using .gitignore keeps your repository clean and secure.

.gitmessage

The .gitmessage file defines a custom commit message template to guide how you write commit messages in Git.

Key Points

  • Helps maintain consistent, readable commit messages
  • Acts as a template when using git commit (especially without -m)
  • Can be used globally or on a per-project basis

Examples

.gitmessage
# Commit Message Guidelines

# Commit message should complete the sentence:  
# “If applied, this commit will...”

# Summary line:
# - Max 50 characters, no punctuation  
# - Format: <type>: <keyword> <summary>  
# Example:  
docs: add installation instructions to readme

# Commit Types:
# - chore:     Maintenance or deletions
# - docs:      Documentation only
# - feat:      New feature
# - fix:       Bug fix
# - perf:      Performance improvement
# - refactor:  Code change without behaviour change
# - revert:    Revert a previous commit
# - style:     Formatting (whitespace, comments)
# - test:      Adding or updating tests

# Commit Keywords:
# - add:       Introduce new content
# - clean:     Simplify or remove unused code
# - disable:   Turn off a setting or feature
# - document:  Improve comments or documentation
# - enable:    Turn on a setting or feature
# - fix:       Correct broken or buggy behaviour
# - format:    Adjust spacing or formatting
# - move:      Relocate items
# - refactor:  Restructure without changing behaviour
# - remove:    Delete or deprecate
# - rename:    Rename items
# - update:    Modify existing content

# Optional Body (wrap at 72 characters):
# - Explain what and why, not just how
# - Provide context for future maintainers
# - Link related issues or tickets

# Optional Footer:
# - Closes #123
# - Co-authored-by: <name> <email>

Notes:

  • Lines starting with # are ignored by Git
  • A blank line is required between the title and description

Commit Message Style Guide

  • Use lowercase for type and keyword (e.g., docs: add)
  • Keep the summary short (max 50 characters), no ending punctuation
  • Summaries should complete: “If applied, this commit will…”
  • Use an optional body to explain what and why (wrap at 72 characters)
  • Include references in the footer (e.g., Closes #123) for context

Examples

Basic commit message:

text
docs: add installation instructions to readme

Commit message with description:

text
docs: add installation instructions to readme

Added a new section to the README that details step-by-step
installation instructions for the project. This will help new users
set up the environment quickly without confusion.

Closes #123

How to Use

Set globally:

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

Set per project:

bash
git config commit.template .gitmessage

Using .gitmessage helps enforce clear, structured commit messages, improving project maintainability and collaboration.

Essential Commands #

Repository Setup and Configuration #

Command Description
git init Initialise a new Git repository
git clone <url> Clone a remote repository
git config --global user.name "<name>" Set global username
git config --global user.email "<[email protected]>" Set global email address
git config --global commit.template ~/.gitmessage Set global commit message template
git config commit.template .gitmessage Set commit message template for current repository
git config --list List all configuration settings

Staging and Committing #

Command Description
git status Show current working directory status
git add <file> Stage a specific file
git add . Stage all changes in current directory
git commit Commit staged changes (open message template)
git commit -m "<message>" Commit staged changes with a message
git commit --amend Modify the last commit

Branching and Merging #

Command Description
git branch List local branches
git branch <branch> Create a new branch
git checkout <branch> Switch to a branch
git checkout -b <branch> Create and switch to a new branch
git checkout --orphan <branch> Create a new orphan branch (no commit history)
git branch -m <new_name> Rename current branch
git branch -m <old> <new> Rename a specific branch
git merge <branch> Merge a branch into the current one
git branch -d <branch> Delete a local branch
git branch -a List all branches (local and remote)

Remote Repositories #

Command Description
git remote -v List remote repositories
git remote remove <remote> Delete remote
git remote add origin <url> Add a remote named origin
git push origin <branch> Push changes to a remote branch
git pull origin <branch> Fetch and merge from a remote branch
git fetch Download changes without merging

Viewing and Comparing #

Command Description
git log Show commit history (press q to quit log view)
git log --oneline Compact log view
git diff Show unstaged changes
git diff --staged Show staged changes
git show <commit> Show details for a specific commit

Undoing and Cleaning #

Command Description
git reset <file> Unstage a file
git reset --hard <commit> Reset to a specific commit (destructive)
git checkout -- <file> Discard changes in working directory
git clean -f Remove untracked files
git revert <commit> Create a new commit to undo a previous one

Stashing

Command Description
git stash Stash uncommitted changes
git stash list List stashed changes
git stash apply Re-apply stashed changes
git stash drop Delete a specific stash

Tags

Command Description
git tag List all tags
git tag <name> Create a new tag
git tag -d <name> Delete a tag
git push origin <tag> Push a tag to the remote
git push origin --tags Push all tags to the remote

Workflow #

Install #

To use Git and GitHub effectively, you need to install two tools:

  • Git: The core version control system to track and manage changes in your projects.
  • GitHub CLI (gh): A command-line tool to interact with GitHub directly, enabling you to manage repositories, pull requests, issues, and more from your terminal.

Linux (Debian/Ubuntu):

bash
sudo apt install git gh -y

macOS (using Homebrew):

bash
brew install git gh

Verify installation:

bash
git --version
gh --version

Authenticate GitHub CLI:

bash
gh auth login

Follow prompts. Choose:

  • GitHub.com
  • Protocol: SSH
  • SSH public key: skip
  • Authenticate: browser

Basic Git Workflow #

A typical Git workflow follows these key steps:

bash
# Create a new local repository
git init

# Or clone an existing remote repository
git clone https://github.com/<user>/<repo>.git

# Check the current status of your repository
git status

# Add files to the staging area
git add <file1> <file2>

# Commit staged changes with a descriptive message
git commit -m "<message>"

# View the commit history
git log

# Push your commits to the remote repository (e.g., GitHub)
git push origin main

# Pull the latest changes from the remote repository
git pull origin main

Setting Up SSH Access to GitHub #

Step 1: Check for Existing SSH Keys

Check if you already have SSH keys:

bash
ls -l ~/.ssh

If keys exist and you want to reuse them, skip to step 3.

Step 2: Generate a New SSH Key

Generate a key using the ed25519 algorithm:

bash
ssh-keygen -t ed25519 -C "<[email protected]>" -f ~/.ssh/<key_name>

Key name example: github

Step 3: Add SSH Key to Agent

Linux

Start the SSH agent (if not already running):

bash
eval "$(ssh-agent -s)"

Add private key:

bash
ssh-add ~/.ssh/<key_name>

macOS

Make the key persist across reboots and login sessions:

bash
ssh-add --apple-use-keychain ~/.ssh/<key_name>

This:

  • Adds the key to the agent
  • Stores the passphrase in the keychain

Step 4: Edit SSH Config

Open SSH config:

bash
vim ~/.ssh/config

Linux

GitHub accepts SSH connections only on ports 22 and 443 (via ssh.github.com). Custom ports are not supported.

Add:

~/.ssh/config
Host github.com
  HostName ssh.github.com
  Port 443
  User git
  IdentityFile ~/.ssh/<key_name>
  IdentitiesOnly yes

Set permissions:

bash
chmod 600 ~/.ssh/config

Verify permissions:

bash
ls -l ~/.ssh/config

macOS

Add:

~/.ssh/config
Host github.com
  HostName github.com
  User git
  IdentityFile ~/.ssh/<key_name>
  IdentitiesOnly yes
  UseKeychain yes
  AddKeysToAgent yes

Explanation:

Directive Description
Host github.com Alias used in SSH commands and Git remotes.
HostName github.com Actual hostname to connect to.
User git Required SSH user for GitHub access.
IdentityFile ~/.ssh/<key_name> Path to your private SSH key.
IdentitiesOnly yes Use only the specified key, not others loaded in the agent.
UseKeychain yes Store key passphrase in the system keychain (macOS only).
AddKeysToAgent yes Automatically add the key to the SSH agent (macOS only).

Step 5: Copy Public Key to Clipboard

Display public key:

bash
cat ~/.ssh/<key_name>.pub

Use this output to add the key to your GitHub account.

Step 6: Add SSH Key to GitHub

  1. Go to GitHub → Settings → SSH and GPG keys
  2. Click New SSH key
  3. Add:
    • Title: <device>-<location>-github
    • Key type: authentication key
    • Key: *** (paste your public SSH key here)
    • Click "Add key" to save

SSH key title examples:

  • imac-home-github

  • desktop-work-github

  • linode-website-github

Step 7: Test Connection to GitHub

bash
ssh -T [email protected]

If prompted the first time, type yes to accept GitHub’s SSH fingerprint.

You should see:

text
Hi <user>! You've successfully authenticated, but GitHub does not provide shell access.

Step 8: Configure Git

Set identity:

bash
git config --global user.name "<name>"
git config --global user.email "<[email protected]>"

Verify Git config:

bash
git config --list

Press q to exit.

Setting Up a Git Repository #

Step 1: Initialise Local Repository

bash
mkdir -p <path/to/repo>
cd <path/to/repo>
git init

This creates a .git folder which tracks all changes.

Step 2: Create .gitignore

Create file:

bash
vim .gitignore

Add:

.gitignore
# Backup files
*.bak

# Logs and temporary files
*.log
*.tmp

# Editor and project configuration
.prettierignore
.prettierrc
.vscode/
.workspace

# Git-related files
.gitignore~
.git/

# OS and system files
.DS_Store
.Spotlight-V100
.Trashes

# Secrets and credentials
*.key
*.pem

Step 3: Set Up Commit Message Template

Create file:

bash
vim ~/.gitmessage

Add:

~/.gitmessage
# Commit Message Guidelines

# Commit message should complete the sentence:  
# “If applied, this commit will...”

# Summary line:
# - Max 50 characters, no punctuation  
# - Format: <type>: <keyword> <summary>  
# Example:  
docs: add installation instructions to readme

# Commit Types:
# - chore:     Maintenance or deletions
# - docs:      Documentation only
# - feat:      New feature
# - fix:       Bug fix
# - perf:      Performance improvement
# - refactor:  Code change without behaviour change
# - revert:    Revert a previous commit
# - style:     Formatting (whitespace, comments)
# - test:      Adding or updating tests

# Commit Keywords:
# - add:       Introduce new content
# - clean:     Simplify or remove unused code
# - disable:   Turn off a setting or feature
# - document:  Improve comments or documentation
# - enable:    Turn on a setting or feature
# - fix:       Correct broken or buggy behaviour
# - format:    Adjust spacing or formatting
# - move:      Relocate items
# - refactor:  Restructure without changing behaviour
# - remove:    Delete or deprecate
# - rename:    Rename items
# - update:    Modify existing content

# Optional Body (wrap at 72 characters):
# - Explain what and why, not just how
# - Provide context for future maintainers
# - Link related issues or tickets

# Optional Footer:
# - Closes #123
# - Co-authored-by: <name> <email>

Configure Git to use it:

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

Verify Git configuration:

bash
git config --list

Press q to exit.

Step 4: Commit Files

bash
git add .
git status
git commit
  • git add .: Stages all tracked and untracked files, excluding .gitignore entries
  • git commit: Launches editor with .gitmessage template

Default First Commit

Use the message:

text
Initial commit
  • Marks the first commit in a new repository
  • Common convention to indicate project start

Step 5: Create and Link Remote Repository (GitHub CLI)

bash
gh repo create <user>/<repo> --private --source=. --remote=<remote> --push

Options:

  • --private: Make repository private. Use --public for public.
  • --source=.: Use current directory as source.
  • --remote=<remote>: Set remote name (default: origin).
  • --push: Push current commits.

Cloning a Repository #

You only run git clone once, the first time you set up the repository.

Run:

bash
git clone [email protected]:<user>/<repo>.git <local_folder>

This will:

  • Create the <local_folder> directory
  • Pull all files into it

Pull latest changes:

bash
cd <local_folder>
git pull

Reverting to a Specific Commit #

1. Using git revert

  • Safely undo changes made in a specific commit by creating a new commit that reverses them.
  • This method preserves history and is safe for shared/public branches.

Step 1: List Commits

Display history of commits:

bash
git log --oneline

Output example:

text
e3a1f45 fix: broken image path
b2d3c7a add: user authentication
7f9e5a1 Initial commit

The left part (e.g. e3a1f45) is the commit hash, used to identify a specific commit.

Step 2: Revert Commit

Run:

bash
git revert <commit_hash>

Git opens your editor with a default commit message like:

text
Revert "Add user authentication"
  • Edit or accept the message
  • Save and close the editor to finalise the revert
bash
git push origin master

Step 3: Push to Remote

Push the new revert commit to GitHub:

bash
git push origin master

2. Using git reset

  • Only use git reset on branches that you alone are working on.

  • Rewriting history on shared branches can cause conflicts and data loss for others.

  • Use this method to permanently remove one or more commits from your local history.
  • This is not safe on shared/public branches because it rewrites history.

Step 1: List Commits

Display history of commits:

bash
git log --oneline

Output example:

text
e3a1f45 fix: broken image path
b2d3c7a add: user authentication
7f9e5a1 Initial commit

The left part (e.g. e3a1f45) is the commit hash, used to identify a specific commit.

Step 2: Hard Reset to a Specific Commit

Run:

bash
git reset --hard <commit_hash>
  • This removes all commits after <commit_hash>
  • Your working directory and staging area will also be reset to that state

Step 3: Push to Remote

Push the new revert commit to GitHub:

bash
git push origin master --force

Result: Remote history is overwritten with local state.

Deleting a Repository #

Step 1: Add Delete Repo Permission (optional)

Add user rights to delete repositry:

bash
gh auth refresh -h github.com -s delete_repo

Step 2: Delete Repository

bash
gh repo delete <user>/<repo> --yes
  • --yes - Skip confirmation prompt and delete immediately.

Step 3: Verify Deletion

List all repositories:

bash
gh repo list <user>

Press q to exit.

Best Practices #

Following these best practices will help you use Git effectively, keep your history clean, and avoid common problems:

  • Make small, focused commits with clear messages
    Break your work into logical steps. Each commit should capture a single change, with a message that explains what changed and why.
  • Write commit messages that complete the sentence:
    “If applied, this commit will...”. This approach ensures messages clearly describe the impact of the commit. Example: If applied, this commit will docs: add installation instructions to readme.
  • Pull frequently to stay up to date
    Run git pull before you start working to ensure you have the latest changes. This reduces the risk of conflicts and rework.
  • Use branches for all new work
    Create a separate branch for each feature, fix, or experiment. This keeps your main branch stable and makes reviews, testing, and rollbacks easier.
  • Check your status regularly
    Use git status to monitor changes, staged files, and your current branch. This helps you stay in control and avoid mistakes.
  • Use .gitignore to exclude unnecessary files
    Prevent build artefacts, system files, and secrets from being tracked. This keeps the repository clean and secure.
  • Use a .gitmessage template for consistent commits
    Define a commit message template to encourage clear, structured, and meaningful commit messages. Especially useful for teams.
  • Clean up unused branches
    Delete branches that have been merged or are no longer needed. This keeps your repository organised and easier to navigate.
  • Use public and private repositories appropriately on GitHub
    • Use public repos for open source, demos, or portfolio work meant to be shared.
    • Use private repos for proprietary, internal, or experimental work.
    • Never publish sensitive data, such as API keys, passwords, or personal information.
    • Audit visibility and access regularly to maintain proper control.

Troubleshooting #

Not a git repository #

Symptoms

Running any Git command results in the following error:

text
fatal: not a git repository (or any of the parent directories): .git

Cause

This error occurs when you run a Git command outside of a Git repository, meaning there is no .git directory in the current or parent folders.

Solution

1. Check if you are inside a Git repository:

bash
ls -a

Look for a .git directory. If it's not there, you're not in a Git repo.

2. Navigate to the correct repository directory:

bash
cd <path/to/repo>

3. If you haven’t initialised a repository yet

Initialise one in your current directory:

bash
git init

4. If your repository was deleted or moved:

Re-clone the repository:

bash
git clone <url>

Or restore .git from a backup if available.

Modify Last Commit Message #

Problem

You need to change the message of your most recent commit.

Solution

1. Check for uncommitted changes:

bash
git status

Ensure your working directory is clean.

2. Amend the last commit message:

bash
git commit --amend
  • This opens the commit message in your default editor
  • Edit the message, save, and close the editor

3. Verify the updated commit message:

bash
git log -1

4. If the commit is already pushed

You must force-push the amended commit:

bash
git push --force

Force-pushing rewrites history and can disrupt collaborators.

Could not resolve HEAD #

Problem

Running the command:

bash
git restore --staged <file>

returns the error:

text
fatal: could not resolve HEAD

Cause

This error occurs because your Git repository does not have any commits yet. The git restore --staged command relies on comparing the staged changes against the latest commit (HEAD). Without a commit, HEAD is undefined, causing the failure.

Solution

1. If this is a new repository with no commits:

Use git reset to unstage files instead:

bash
git reset <file>

Or to unstage all files:

bash
git reset

2. Alternatively, create an initial commit:

bash
git commit -m "Initial commit"

After this, git restore --staged <file> will work as expected.

Unable to add remote #

Symptoms

  • Running a gh repo create command results in:
text
Unable to add remote "<remote>"
  • The repository is created successfully on GitHub, but no remote is added or push fails.

Cause

A Git remote named <remote> already exists in the local repository, causing a conflict when the GitHub CLI (gh) tries to add a new remote with the same name.

Solution

Check existing remotes:

bash
git remote -v

If <remote> is listed, remove the conflicting remote:

bash
git remote remove <remote>

Re-run the gh repo create command:

bash
gh repo create <user>/<repo> --private --source=. --remote=<remote> --push

Alternatively, use a different remote name if <remote> is intentionally in use:

bash
gh repo create <user>/<repo> --private --source=. --remote=<another_remote> --push

Next Steps #

Now that you’ve learned the essentials of Git, start applying your knowledge with real, practical use. Focus on the following two steps to build confidence and reinforce what you've learned.

1. Practise with Real Projects

  • Start by creating a Git repository for a personal or hobby project
  • Use branches to test new features or ideas
  • Practise staging, committing, merging, and reverting changes

2. Explore GitHub

  • Create a GitHub account (if you haven’t already)
  • Push a project to a remote repository
  • Learn to use pull requests, issues, and collaboration tools
  • Set up GitHub Actions to automate tasks such as testing or deployment

As you keep practising, Git and GitHub will become second nature. The key is consistency and treating version control as an essential part of your development workflow.