Most of Git is a single loop. You change files in the working directory, run git add to stage them, then run git commit to record them. Everything else here is a variation on that.
Every local clone carries the full project history, which is why commits, branches and log inspection all work without a network connection. Git is distributed in the literal sense.
Adoption is close to universal. Stack Overflow’s 2022 Developer Survey found 93.87% of all respondents use Git, and git-scm.com cites the same survey for 96% of professional developers.
One thing trips up beginners more than it should. Git runs on your machine, and GitHub, GitLab and Bitbucket only host remote repositories for it.
How to Install Git and Verify the Installation

Use your platform’s package manager or the installer from git-scm.com, then run git --version to confirm the binary is on your PATH.
| Platform | Method | Command |
|---|---|---|
| Windows | winget | winget install --id Git.Git -e --source winget |
| macOS | Homebrew | brew install git |
| macOS | Xcode Command Line Tools | xcode-select --install |
| Debian and Ubuntu | apt | sudo apt install git |
| Fedora | dnf | sudo dnf install git |
As of October 2026, git-scm.com lists 2.56.0 (released 2026-09-28) as the current source release. Builds from package managers and third parties can trail behind it.
Don’t go looking for a standalone macOS installer. According to git-scm.com it stopped at version 2.33.0 in 2021 with no updates planned, so Homebrew or the Xcode tools are the way to go.
On Windows, the installer also adds Git Bash, a Bash emulation that runs Git commands from a familiar prompt. The default options work for most setups.
Arch Linux uses sudo pacman -S git. If you want a longer, platform-by-platform walkthrough, there’s a guide to installing Git.
To verify, open a new terminal (Git Bash on Windows) and run git --version. You should get a line starting with “git version”.
Seeing “command not found” instead? The terminal was probably open before the install and still holds the old PATH. Close it, start a fresh one, and try again.
How to Configure Git Before the First Commit
Git stamps your name and email onto every commit, so set both once with git config --global.
git config --global user.name "Your Name"andgit config --global user.email "you@example.com"set your identitygit config --global init.defaultBranch mainsets the default branch namegit config --global core.editor "code --wait"makes VS Code the editor
Use the email address tied to your GitHub or GitLab account. Otherwise the platform won’t link the commits to your profile.
Git 2.28 (July 2020) introduced init.defaultBranch, according to GitHub’s blog. With the option unset, that release falls back to master when you run git init.
The setting never renames branches in repositories that already exist. And if Git rejects the command, your installed version is older than 2.28 and needs an update.
Settings live in one of three scopes, and the git config command reads them in order, so a local value beats a global one.
| Scope | Flag | Typical file |
|---|---|---|
| System | --system | /etc/gitconfig |
| Global | --global | ~/.gitconfig |
| Local | --local | .git/config in the repository |
Inside a repository, git config with no flag writes to the local file. That’s how a work project keeps a work email while every other repo uses your personal one.
To check what’s set, run git config --list for everything or git config user.name for one key.
How Git Tracks Changes: Working Directory, Staging Area and Repository
A change passes through the working directory, the staging area and the repository, in that order. A file is modified in the first, staged in the second and committed in the third.
- The working directory holds the files on disk, and you edit them with whatever tool you like
- The staging area queues changes for the next commit.
git addfills it andgit restore --stagedempties it - The repository is the hidden
.gitfolder, wheregit commitwrites the staged snapshot for good
Pro Git (Scott Chacon and Ben Straub) calls these states modified, staged and committed. A file is also either tracked or untracked, which decides whether Git watches it at all.
The staging area is what lets one commit hold two related edits while a third, unrelated edit waits for its own commit.
A commit is a snapshot of the whole project, not a list of file differences.
Each one stores a pointer to that snapshot along with the author, the message and the parent commit, and it carries a SHA-1 checksum known as the commit hash.
Linus Torvalds made the first commit on April 7, 2005, according to GitLab’s history of the project. He wrote Git after the Linux kernel community lost its free BitKeeper license.
Per Pro Git, the goals were speed, a simple design, strong support for non-linear development, a fully distributed model and the ability to handle kernel-sized projects.
The git-scm.com About page puts the Linux kernel’s full history, 1.4 million commits, at 5.5 GB as of 2025.
Every clone carries that whole history. Which is why git log, git diff and branch switching all work without a network connection.
How to Create a Repository and Make Your First Commit

Run git init inside a project folder, stage files with git add, and record them with git commit -m "message". After that the history exists.
Start with git init or git clone

For a new project, run git init in an empty or existing folder. The git init command creates the hidden .git folder and nothing else, so don’t edit that folder by hand.
git init -b main names the first branch at creation, which saves a rename later.
For an existing project, use git clone <url>. It copies the full history into a new folder and records the source as the remote called origin.
Stage, commit and inspect changes

mkdir hello-git && cd hello-gitcreates and enters a project foldergit initcreates the repositoryecho "# Hello Git" > README.mdcreates the first file
git statuslists README.md as untrackedgit add README.mdmoves it into the staging areagit commit -m "Add README"records the snapshotgit log --onelineshows the new commit with its short hash
git add . stages the current directory and everything below it. git add -A covers the whole project, deletions included.
Before staging, git diff shows unstaged edits line by line. After staging, git diff --staged shows what the next commit will contain.
Small commits that each do one thing are easier to read, review and undo later.
Exclude files with .gitignore
A .gitignore file in the project root lists paths Git should never track, such as build output, logs and local secrets. Write one pattern per line.
node_modules/(a trailing slash matches directories only)*.log.env!keep.log(a leading exclamation mark brings a match back in)
Commit the gitignore file itself so every clone shares the same rules.
Git’s gitignore documentation is blunt about the limit. Files that are already tracked aren’t affected. To stop tracking one, run git rm --cached filename and commit the change.
How to Create, Switch and Manage Branches

Run git switch -c feature-name to create a branch and move onto it in one step. Commit as usual, then return with git switch main. New commits always land on whichever branch is checked out.
A Git branch is a movable pointer to a commit, so creating one copies nothing.
Keep main for stable history and give each change its own feature branch. Short-lived branches merge cleanly, and long-lived ones drift.
git branchlists local branchesgit branch namecreates one without switchinggit switch namemoves to an existing branchgit switch -c namecreates a branch and moves to itgit branch -d namedeletes a merged branchgit branch -D nameforce-deletes an unmerged one
Git 2.23 (August 2019) introduced git switch and git restore to split two jobs that git checkout used to handle alone, according to GitHub’s release highlights. Both shipped as experimental at launch.
git checkout name and git checkout -b name still work, and they fill most older tutorials.
If the target branch would overwrite uncommitted edits, git switch stops instead of discarding them. That refusal is your cue to stash.
Save unfinished work with git stash
Stash first, switch second.
The git stash command shelves modified tracked files and staged changes, then gives you a clean working directory back.
git stash listshows every saved entrygit stash popreapplies the newest entry and deletes itgit stash applyreapplies it but keeps the entry around
Untracked files stay behind unless you add -u. People get caught by this the first time a new file seems to vanish from the stash.
How to Merge Branches and Resolve Merge Conflicts

Switch to the branch that should receive the work, then run git merge feature-name. Git folds the feature branch into whichever branch is checked out.
When the receiving branch hasn’t moved since the feature branch split off, Git does a fast-forward merge, according to the git-merge documentation. It slides the branch pointer forward and creates no new commit.
Once both branches have new commits, Git builds a merge commit with two parents instead. Adding --no-ff forces that merge commit even when a fast-forward is possible, which keeps the feature visible in the log.
| Method | History shape | Rewrites commits | Safe after push |
|---|---|---|---|
| Fast-forward merge | Linear | No | Yes |
| Merge commit | Branching, two parents | No | Yes |
| Rebase | Linear | Yes, new commit hashes | No |
Merge or rebase
My rule of thumb is simple. Rebase commits nobody else has seen, and merge everything else.
A rebase replays your commits one at a time on top of the target branch, which gives you a straight line in the log. Run git switch feature-name, then git rebase main.
The catch is that Pro Git describes rebasing as abandoning the original commits and writing new ones with different hashes. If teammates already built on the old ones, both versions end up in the history as near-duplicates.
Rebasing makes sense when the branch exists only on your machine, or when you want a tidy linear log before opening a pull request. Merging is the better call once anyone else has pulled the branch, or when you want the history to show where the work joined main.
Not sure which to pick? Merge. A merge backs out cleanly with git merge --abort, while a bad rebase of shared commits costs teammates real time.
Resolve a merge conflict step by step
A conflict appears when both branches changed the same lines. Git stops partway through the merge and marks the clash inside the file.
git statuslists the files under “Unmerged paths” as “both modified”- Open each file and find the block that starts with
<<<<<<<and ends with>>>>>>> - Keep the code you want, from either side or a blend of both
- Delete all the marker lines, including the
=======divider git add filenamemarks the file as resolvedgit commit(orgit merge --continue) finishes the merge
Everything above the divider is your current branch. Whatever sits below it comes from the incoming one.
git merge --abort is the way out when the conflicts turn ugly. The manual adds a limit, though. If uncommitted changes existed when the merge started, abort can’t always rebuild them, so commit or stash before merging.
During a rebase the equivalents are git rebase --continue and git rebase --abort.
The -X ours and -X theirs options make Git pick a side without markers, as Pro Git describes. Convenient, but the losing side’s conflicting lines vanish silently, so read the diff afterwards.
For more worked examples, see this guide to resolving merge conflicts in Git.
How to Connect to a Remote Repository and Collaborate

Connect a local repository to a hosted one with git remote add origin <url>, then publish the branch with git push -u origin main. The -u flag records an upstream branch, so later pushes and pulls need no arguments.
Push, pull and fetch
Origin is the conventional name for the remote you cloned from or added first. Nothing in Git treats the word specially.
git fetch downloads new commits and updates remote-tracking branches such as origin/main, and it leaves your working directory alone. git pull does a fetch and then merges or rebases the result into the current branch. git push uploads local commits, and the remote rejects it if it holds commits you don’t have.
Fetch first when you want to look before integrating. git log main..origin/main then lists exactly what arrived.
When both sides have moved, git pull stops and asks how to reconcile the divergent branches, per Git’s pull documentation. Answer once with git config pull.rebase false (merge), pull.rebase true (rebase) or pull.ff only (refuse anything but a fast-forward).
A rejected push has the same cure. Pull, resolve any conflict, push again.
Authenticate with SSH keys or an HTTPS token
GitHub stopped accepting account passwords for Git operations on August 13, 2021, according to its changelog. Two routes remain, a personal access token over HTTPS or an SSH key.
An SSH key takes a few steps to set up (generate it, load it into the agent, upload the public key). After that you never paste a secret at a prompt, and one key pair covers every repository on the account. The downside is a lost laptop, since you then have to remove that key from the account.
An HTTPS personal access token works with a plain https:// remote URL and needs nothing else configured. Token scopes also limit what a leaked token can touch. But the token behaves like a password, and pasting it into a remote URL leaves it in shell history. Tokens expire or get revoked too, and pushes then fail with an authentication error.
GitHub’s documentation generates keys with ssh-keygen -t ed25519 -C "you@example.com". Then ssh-add ~/.ssh/id_ed25519 loads the key into the agent.
Paste the contents of the .pub file into GitHub under SSH and GPG keys, and test with ssh -T git@github.com. An existing clone switches over with git remote set-url origin git@github.com:user/repo.git.
I’d pick SSH for daily work on your own machine. Tokens suit scripts and CI jobs better.
Contribute through a fork and pull request
A fork is your own server-side copy of someone else’s repository. On GitHub, a fork lets you push branches without write access to the original.
- Fork the repository on the hosting platform
- Clone your fork, then
git remote add upstream <original-url> - Create a branch, commit, and
git push -u origin branch-name - Open a pull request from that branch against the original project
- Push more commits to the same branch to answer review comments
The hosts differ in extras, not in Git itself. GitHub brings pull requests and GitHub Actions for automation. GitLab calls them merge requests and bundles CI/CD. Bitbucket is Atlassian’s host, built to sit next to Jira.
All of them speak ordinary Git, so none of the commands above change.
How to Undo Changes in Git

Match the command to where the mistake lives. Use git restore for file edits, git commit --amend for the last commit, git reset for unpushed commits, and git revert for anything already shared.
| Command | What it changes | Rewrites history | Safe after push |
|---|---|---|---|
| git restore | Working files or staging area | No | Yes |
| git commit –amend | The last commit | Yes | No |
| git reset | Branch pointer, optionally files | Yes | No |
| git revert | Adds an inverse commit | No | Yes |
To discard file edits, git restore notes.txt throws away uncommitted changes, and git restore --source HEAD~1 notes.txt brings the file back as it was one commit ago.
No commit ever held those discarded edits, so no command brings them back.
To fix the last commit, stage the forgotten file and run git commit --amend, which also opens the message for editing. The amended commit gets a new commit hash, so amend before pushing, never after.
The git reset command moves the branch pointer back, and the mode decides how much else it undoes.
--softmoves the branch only, so the staging area and files stay put--mixedis the default and also empties the staging area, though your files are kept--hardalso overwrites the working directory and discards uncommitted edits
Git’s manual shows a tidy use of the first mode. git reset --soft HEAD~5 followed by git commit squashes the last five commits into one.
For commits already on the remote, reverting a commit adds a new commit that reverses the old one and leaves history intact.
A merge commit needs git revert -m 1 <hash>, where -m names the parent that counts as the mainline. The manual warns that reverting a merge declares its changes unwanted, so revert the revert commit to bring them back.
To recover lost commits, git reflog lists where HEAD has pointed, branch switches included. Find the entry from before the mistake, then run git reset --hard HEAD@{2} or git switch -c rescue <hash>.
Reflog entries expire after 90 days by default, and entries for commits left behind by an amend or rebase expire after 30, according to the git-gc documentation. The reflog also belongs to your clone, so a fresh clone starts with none.
When Git Causes Problems
Git tends to break down around large binary files, secrets committed to history, force pushes over shared branches, and commits made on a detached HEAD. Each has a documented way out, and each gets harder once a commit has been pushed.
Large binary files hit limits on GitHub. Per GitHub Docs, browser uploads top out at 25 MiB, Git prints a warning on push at 50 MiB, and files of 100 MiB are blocked from regular repositories.
Git LFS keeps small pointer files in the repository and the real files elsewhere. git lfs install, then git lfs track "*.zip", records the pattern in .gitattributes. For finished binaries, GitHub Releases is the other documented route.
A commit that already contains the oversized file keeps it in history, so the push stays rejected even after a later commit deletes the file. Undo the unpushed commit with git reset --soft HEAD~1, unstage the file, and commit again.
Secrets are worse. Deleting a committed secret in a new commit changes nothing for the older commits that still hold it.
Toyota learned this the expensive way. A subcontractor pushed part of the T-Connect source code, including a data-server access key, to a public GitHub repository in December 2017, and it stayed reachable until September 15, 2022. Toyota’s notice, as reported by BleepingComputer, put the number of customers whose data was exposed to access at 296,019 and records the database keys being changed on September 17, 2022.
Rotate the credential first. Rewriting history comes second.
GitHub’s documentation walks through git-filter-repo --sensitive-data-removal --invert-paths --path FILE followed by a force push. It also warns that the old commits can survive in clones and forks, and that GitHub Support only helps when rotating credentials cannot contain the risk.
If the secret never left your machine, none of that applies. Run git reset --soft HEAD~1, remove the secret, commit again.
Prevention is cheaper, and a guide on keeping an API key out of a GitHub repository walks through the habit.
git push --force overwrites the remote branch and, per the git-push documentation, disables the safety checks along with the lease checks.
git push --force-with-lease refuses when the remote branch has moved since your last fetch. The documentation warns that the lease loses its meaning if something fetches in the background, a cron job for example, because the fetch updates the value Git compares against.
Rebasing or amending pushed commits forces this situation. Keep force pushes on your own feature branches and away from main.
A detached HEAD happens when you check out a commit hash, or run git switch --detach HEAD~3, and HEAD ends up on a commit instead of a branch.
Commits made in that detached HEAD state belong to no branch, and switching away hides them. Run git switch -c rescue-branch before leaving to keep the work, or find the commits afterwards in git reflog.
Git FAQ
What is Git used for?

Teams use Git to record the history of a set of files, usually source code. That lets them see who changed what, return to an earlier version, and work on separate branches without overwriting each other.
Documentation and configuration files fit too. Large binaries fit poorly.
Is Git the same as GitHub?
No. Git is the version control tool on your machine, while GitHub is a hosting service for remote repositories that adds pull requests and GitHub Actions.
GitLab and Bitbucket fill the same role, and all three accept ordinary Git commands.
Should I use the command line or a graphical client?

Start with the command line. Every graphical client wraps the same commands, and the terminal covers every operation while the graphical tools cover most of them.
VS Code has Git built in, and GitHub Desktop is a dedicated client. Both handle daily commits and pushes well.
How do I write a good commit message?
Write a short summary line in the imperative, such as “Add README”, then a blank line, then a body that explains why the change was made.
The diff already shows what changed. The message carries the reason.
What does HEAD mean in Git?
HEAD is a pointer to the commit you currently have checked out, normally through the current branch. HEAD~1 names its parent.
When HEAD points straight at a commit instead of a branch, Git reports a detached HEAD.
What is the best way to practice Git?
Practice in a throwaway repository. Make an empty folder, run git init, and break things freely. Nothing there can damage a real project.
git help commit opens the manual page for any command offline, and the free Pro Git book at git-scm.com goes deeper. A one-page git cheat sheet covers the daily commands.
Which Git Workflow Suits a Small Team?

Short-lived feature branches merged into main every day work best for a small team. DORA, the DevOps Research and Assessment program, ties that trunk-based pattern to stronger delivery performance, with three or fewer active branches and no code freezes (dora.dev, verified October 2026).
Adopt the pieces in a sensible order. Start with branches that live under a day, add pull request review before every merge, and finish with automated tests on each merge into main.
The order matters because daily merging without tests sends broken commits straight to main, which is the trade-off this pattern carries.
Release branches earn their place only when several versions ship in parallel. Comparing each Git workflow model, Git Flow included, is the natural next step.
- How to Turn On Dark Mode in Notepad++ (Built-In, No Plugin) - October 3, 2026
- PostgreSQL Cheat Sheet - October 2, 2026
- How to Repair a Corrupt SQL Server Database Without Any Data Loss - October 2, 2026



