Git from the Command Line
Learn Git from the terminal: install, configure, init or clone a repo, stage and commit changes, create branches, merge, and push to a remote.
Before you start
- ▸A terminal and a non-root user account with sudo privileges
- ▸Internet access to install packages and optionally push to a remote
- ▸A GitHub or GitLab account if you intend to push to a remote repository
Git is the version control system used by nearly every serious software project. Learning it from the terminal gives you a complete, unambiguous picture of what is happening — no GUI hiding the details. This guide walks through the daily workflow: creating and cloning repositories, staging and committing changes, branching, merging, and pushing to a remote like GitHub or GitLab.
Install Git
Most distros ship Git in their main repositories. Install it with your package manager if it is not already present.
Debian / Ubuntu
sudo apt update && sudo apt install git
Fedora / RHEL / Rocky
sudo dnf install git
Arch
sudo pacman -S git
Confirm the installed version:
git --version
Output will vary, but expect something like git version 2.43.0. Anything 2.28 or newer covers all the features used here.
First-Time Configuration
Git stores your identity in every commit. Set it once globally and it applies to all repositories on the machine.
git config --global user.name "Your Name"
git config --global user.email "[email protected]"
git config --global init.defaultBranch main
The third line sets the default branch name to main for any new repository you initialise — this matches the current convention on GitHub and GitLab. Verify your settings:
git config --list --global
Creating a Repository
Initialise a new repo
git init creates a hidden .git directory that tracks everything. Run it inside an existing project folder or a new one.
mkdir my-project && cd my-project
git init
Clone an existing repo
If the project already lives on a remote server, clone it instead. This downloads the full history and sets up the remote automatically.
git clone https://github.com/example/my-project.git
cd my-project
For SSH-based access (recommended once you have a key pair configured with your remote):
git clone [email protected]:example/my-project.git
The Stage-and-Commit Workflow
Git separates staging (selecting what goes into the next commit) from committing (recording it permanently). This two-step design lets you craft precise, logical commits rather than dumping every changed file in at once.
Check current status
git status
This shows untracked files, modified files, and what is already staged. Run it constantly — it is free and always informative.
Stage files
# Stage a specific file
git add README.md
# Stage all changes in the current directory tree
git add .
Use git add -p to review and stage changes in chunks — essential when one file contains unrelated edits you want in separate commits.
Commit staged changes
git commit -m "Add initial README with project overview"
Write commit messages in the imperative mood and keep the subject line under 72 characters. If you need more detail, omit -m and Git will open your default editor for a multi-line message.
View commit history
git log --oneline --graph --decorate
The --oneline flag condenses each commit to one line. --graph draws branch topology in ASCII, which becomes useful once you start branching.
Branching
Branches let you develop features or fixes in isolation without affecting the main line of work. They are cheap to create and fast to switch between.
Create and switch to a new branch
git switch -c feature/login-page
git switch -c is the modern replacement for git checkout -b, available since Git 2.23. Both work, but switch has a clearer, single-purpose interface.
List branches
git branch
The current branch is marked with an asterisk. Add -a to include remote-tracking branches.
Switch between existing branches
git switch main
Delete a branch after merging
git branch -d feature/login-page
Merging
Once work on a branch is complete, merge it back into main (or whatever your integration branch is called).
Fast-forward merge
If main has not moved since the branch was created, Git performs a fast-forward: it simply moves the main pointer forward.
git switch main
git merge feature/login-page
Merge with a commit (no fast-forward)
Use --no-ff to always create a merge commit, preserving branch history even when a fast-forward is possible. Many teams enforce this for traceability.
git merge --no-ff feature/login-page
Resolving merge conflicts
When the same lines were changed differently in both branches, Git stops and marks the conflicts. Open the affected files and look for conflict markers:
# Git will tell you which files conflict
git status
# Open the file, resolve the markers, then stage the fix
git add path/to/conflicted-file.txt
git commit
Conflict markers look like <<<<<<< HEAD … ======= … >>>>>>> feature/login-page. Delete the markers, keep the correct code, then stage and commit.
Working with Remotes
A remote is a named URL pointing to another copy of the repository, typically on a hosting service. When you clone, Git automatically creates a remote called origin.
Add a remote to a local repo
git remote add origin [email protected]:youruser/my-project.git
Push a branch to the remote
# First push: set the upstream tracking branch
git push -u origin main
# Subsequent pushes on the same branch
git push
Pull changes from the remote
git pull is shorthand for git fetch followed by git merge. Fetching first and inspecting is safer on shared branches:
git fetch origin
git log origin/main --oneline
git merge origin/main
Check configured remotes
git remote -v
Verification
After a full workflow cycle, your log should show a clean history. Run:
git log --oneline --graph --all
You should see your commits on main, any branch commits, and merge points if you used --no-ff. git status should report nothing to commit, working tree clean.
Troubleshooting
Accidental commit to the wrong branch
Use git reset HEAD~1 to undo the last commit but keep the changes staged, then switch to the correct branch and recommit. Do not use reset on commits already pushed to a shared remote.
Push rejected due to diverged history
Someone else pushed to the same branch. Pull and integrate their changes first:
git pull --rebase origin main
git push
--rebase replays your local commits on top of the updated remote history, avoiding an unnecessary merge commit.
Forgot to set user name or email
If commits show the wrong author, fix the global config with git config --global as shown earlier. To amend only the very last commit's author before pushing:
git commit --amend --reset-author --no-editFrequently asked questions
- What is the difference between git fetch and git pull?
- git fetch downloads changes from the remote but does not touch your working branch. git pull is fetch plus an automatic merge. Fetching first lets you inspect incoming changes before integrating them.
- When should I use rebase instead of merge?
- Rebase rewrites your local commits on top of another branch, producing a linear history with no merge commits. It is useful for cleaning up a feature branch before merging, but never rebase commits that have already been pushed to a shared remote.
- How do I undo a commit I have not pushed yet?
- Use git reset HEAD~1 to move the branch pointer back one commit while keeping your changes staged, or add --hard to discard the changes entirely. Never use --hard unless you are certain you do not need those changes.
- What is a .gitignore file and do I need one?
- A .gitignore file lists file patterns that Git should never track, such as build artefacts, IDE config files, or secrets. You almost always need one. Create it at the root of the repo before your first commit.
- Should I use HTTPS or SSH to connect to GitHub or GitLab?
- SSH is generally more convenient for regular use because authentication is handled by your key pair rather than a password or token prompt. Set up an SSH key pair, add the public key to your account, and use the git@ clone URL.
Related guides
Bash Arrays and Associative Arrays
Master bash indexed and associative arrays: declaration, element access, looping, mapfile, namerefs, and practical patterns for real scripting work.
Bash Functions and Variable Scoping
Master Bash function scoping with local variables, source-based libraries, correct use of return codes, and array passing techniques including namerefs.
Bash Loops: for, while and until
Learn all three Bash loop types — for, while, and until — with practical, copy-paste examples covering file iteration, counting, polling, and safe line reading.
Bash Scripting for Beginners
Learn Bash scripting from scratch: shebang lines, variables, conditionals, loops, and arguments, plus a real backup script to tie it all together.