Cheatsheet Git
Sistema de controle de versão
Git
Introduction and Configuration
What is Git (Quick History)
Git is a distributed version control system, created by Linus Torvalds in 2005 (the same creator of Linux) to replace BitKeeper in the development of the kernel.
Main features:
- Distributed: each user has the complete repository locally, with all the history.
- Fast: operations like
commit,branchandmergeare done locally, without network. - Secure: each change is protected by a
SHA-1hash, which makes the history practically tamper-proof.
View the configuration (git config --list)
git config --list git config --global --list git config user.name git config --show-origin --list
The --list shows all active settings (system, global and local). To see just one value, pass the key, for example user.name. The --show-origin indicates which file (.gitconfig) each setting comes from — useful for resolving configuration conflicts.
Create repository (git init)
git init git init my-project git init --bare repository.git
git init creates the hidden .git folder with all the repository's internal structure. With a folder name, it also creates the directory. The --bare flag creates a repository without a working directory, used on servers.
Warning: if a .git folder already exists, don't run this again — you could corrupt the history.
Configuration levels: system, global, local
Git reads the configuration at three levels, from the most general to the most specific:
--system: the whole computer (file/etc/gitconfig).--global: your user (file~/.gitconfig).--local: only the current repository (file.git/config) — it's the default level.
The most specific level always wins: a --local setting overrides --global, which overrides --system.
Clone an existing project (git clone)
git clone https://github.com/user/repository.git git clone https://github.com/user/repository.git folder-local git clone --depth 1 https://github.com/user/repository.git git clone -b develop https://github.com/user/repository.git
git clone copies everything from the remote repository (history, branches, tags) to your machine and automatically creates the link to origin. The --depth 1 makes a shallow clone (only the last commit, faster). The -b clones a specific branch directly.
Check the version and get help
git --version git help config git config --help
git --version shows the installed version — useful to confirm whether you have recent features like git switch (Git 2.23+). The git help command opens the full manual of any command.
Configure user (git config)
git config --global user.name "Your Name" git config --global user.email "email@example.com" git config --global init.defaultBranch main git config --global core.editor "code --wait"
Sets the identity that Git records in each commit. The --global flag applies to the whole user; without it, the configuration stays only in the current repository. The init.defaultBranch sets the name of the initial branch and core.editor the editor used for messages.
Basic Commands
View the current status (git status)
git status git status -s git status --ignored
The most used command in Git. It shows the current branch, the changed files, those in staging (ready for the next commit) and the untracked ones. The -s gives a short version and the --ignored includes files ignored by .gitignore.
Commit modified files directly (-am)
git commit -am "Update dependencies"
The -a automatically adds all files that are already tracked and modified, skipping the git add. Warning: new files (untracked) are not included — those still need git add.
Ignore files (.gitignore)
node_modules/ .env *.log dist/ !dist/.gitkeep
The .gitignore file tells Git which files should not be tracked: dependencies (node_modules/), secrets (.env), logs and build artifacts. The ! negates a pattern (includes it back). Already-versioned files are not ignored — use git rm --cached first.
Add files to staging (git add)
git add file.php git add . git add -p git add *.js
Staging is the "waiting room" before the commit: you choose exactly what goes in. The git add . adds everything; the -p (patch) lets you review and approve part by part of each file. Never commit blindly: git status + git add gives you full control.
View differences (git diff)
git diff git diff --staged git diff main..feature git diff HEAD~3
git diff shows the changes outside staging; with --staged it shows what's already prepared for the next commit. You can compare two branches with main..feature or your work against an old commit with HEAD~3.
The three states of a file
Each file in Git lives in one of three states:
- Working directory: the files the they are on your disk, with unsaved changes.
- Staging area: what you prepared with
git addfor the nextcommit. - Repository: what has already been saved with
git commit.
The normal flow is always: edit → git add → git commit.
Create a commit (git commit)
git commit -m "Message clara e useful"
A commit is a saved point on the project's timeline. Good messages save hours of debugging: describe what was done and why, not just "fix". Golden rule: short and direct title, up to 50 characters.
Remove files from the repository (git rm)
git rm file.txt git rm -r folder/ git rm --cached file.txt
git rm deletes the file from the repository and from disk. The --cached removes only from the repository, keeping the local file — the correct way to stop versioning something that should go into .gitignore.
Commit with title and body
git commit -m "Add email validation" -m "Prevents records with invalid emails. Validates format and domain."
The first -m is the title; the second becomes the body of the message. Git reads the first line the the title — it should be short and direct. Use the body to explain the context and the reason for the change.
Rename or move files (git mv)
git mv old.php new.php git mv file.php folder/
git mv renames or moves files while keeping the associated change history. It's the equivalent of doing mv + git add in a single step, and Git records the operation the a rename.
History and Inspection
View full history (git log)
git log git log -5 git log --stat
Shows the commit history of the current branch: IDs (SHA-1), authors, dates and messages. The -5 limits to the last five and the --stat adds a summary of the files changed in each commit.
Search code in the history (git log -S)
git log -S "functionName" git log -S "functionName" --oneline
The -S (pickaxe) finds the commits that added or removed that text in the code — not just in the message. It's the right tool to discover in which commit a function or bug was introduced.
Find bugs with bisect
git bisect start git bisect bad git bisect good v1.0 git bisect reset
git bisect performs a binary search in the history: you mark a good commit (good) and a bad one (bad), and Git keeps testing the ones in between until it finds the exact commit that introduced the bug. The git bisect reset returns you to the original branch.
Summarized history (git log --oneline)
git log --oneline git log --oneline -10
Shows each commit on a single line, with the abbreviated ID and the message. It's the fastest way to get a clean, overall view of the project's history.
View a specific commit (git show)
git show git show a1b2c3d git show a1b2c3d --stat
With no arguments, it shows the last commit with the full diff. With an ID (just the prefix is enough, e.g. a1b2c3d), it shows that commit. It also works to view the content of a tag or of a file at another point in the history.
Contribution statistics (git shortlog)
git shortlog -sn git shortlog -sn --since="1 year ago"
git shortlog -sn groups the commits by author with the count, ordered from most active to least. Ideal for quick team activity reports.
Visual history of all branches
git log --oneline --graph --all git log --graph --pretty=format:'%h %d %s (%an)' --all
Combines --oneline, --graph (ASCII drawing of the branches) and --all (all branches, not just the current one). It lets you quickly visualize the project's structure and how the branches connect at merges.
Who changed each line (git blame)
git blame file.php git blame -L 10,20 file.php git blame -w file.php
git blame shows, line by line, the last commit and the author who touched each one. The -L 10,20 limits to the range of lines and the -w ignores whitespace changes. Useful for understanding the origin of strange code — no judgment!
Filter the history
git log --author="Name" git log --grep="word" git log --since="2 weeks ago" git log -- app/Models/
Filters commits by author (--author), by text in the message (--grep), by date (--since/--until) or by file path. Essential for finding "who did this" or "when did that bug appear".
Recover lost commits (git reflog)
git reflog git reflog --date=iso git checkout a1b2c3d
reflog records all the movements of HEAD — even commits "deleted" by a reset. It's Git's safety net: find the ID of the lost commit and recover it with git checkout or git reset. Nothing is truly lost.
Branches
Create branch (git branch)
git branch feature/branch-name
Branches are "parallel universes" of your code: main is the official timeline and the rest are branches where you work without breaking anything. Most used conventions: feature/ (new features), bugfix/ (day-to-day bugs), hotfix/ (production emergencies) and release/ (preparing versions).
Create and switch at the same time
git checkout -b feature/login
Creates the feature/login branch and switches to it right away. It combines git branch (create) and git checkout (switch) in a single step — the fastest way to start a new feature.
Force delete + delete remote
git branch -D name git push origin --delete name
The -D deletes the branch even without a merge — careful, unintegrated work is lost (although the reflog still keeps it for a while). The push origin --delete removes the branch from the remote repository.
View existing branches (git branch)
git branch git branch -v git branch --merged
Lists the local branches and marks with * the one you're on. The -v shows the last commit of each one and the --merged lists those already integrated into the current branch — good candidates for deletion.
git switch: the modern alternative
git switch branch-name git switch -c feature/login git switch -
git switch (Git 2.23+) does only the part of checkout that changes branch, without the dangerous side effects (like restoring files). The -c creates and switches, and the - returns to the previous branch.
View local and remote branches
git branch -a git branch -r
The -a shows all the branches (local and remote); the -r only the remote ones (e.g. origin/main). The remote ones are "snapshots" of the server, updated with git fetch.
Rename a branch
git branch -m new-name git branch -m name-old new-name
The -m renames the current branch (or the specified one). If the branch was already on the remote, you'll have to delete the old remote one with git push origin --delete and push the new one with -u.
Switch branch (git checkout)
git checkout branch-name
Updates the files in the working directory to reflect the chosen branch and moves the HEAD pointer to it. Git blocks the switch if there are unsaved changes that would conflict — use git stash in those cases.
Delete local branch (safe)
git branch -d name
git branch -d deletes the branch only if it has already been integrated (merged) into another. It's the safe way to clean up branches that are no longer needed, with no risk of losing work.
Merge and Rebase
Merge (normal join)
git checkout main git merge bugfix/branch-name
git merge creates a merge commit that joins the branch's work into the current one, preserving the history the it happened. Great for teams, because it records when and how each feature was integrated.
Abort merge or rebase
git merge --abort git rebase --abort
If a merge or rebase went wrong (impossible conflicts, for example), the --abort cancels the operation and returns everything to the previous state, with no damage. It's the official "panic button".
Merge without fast-forward (--no-ff)
git merge --no-ff feature/login
By default, if the branch hasn't diverged, Git just advances the pointer (fast-forward) and the merge becomes invisible in the history. The --no-ff forces the creation of the merge commit, keeping visible that that feature existed the a branch.
Resolve conflicts
<<<<<<< HEAD your code ======= code from the other branch >>>>>>> branch-name
When Git can't join two versions of the same line, it marks the file with <<<<<<< HEAD, ======= and >>>>>>>. Steps: open the file, choose what to keep (you can mix or rewrite), remove the markers, save and finish with git add . and git commit.
Merge squash (--squash)
git checkout main git merge --squash feature/login git commit -m "Add login"
The --squash joins all the branch's commits into a single set of changes, which you commit manually. Ideal for turning branches with dozens of "wip" commits into a single clean commit on main.
Cherry-pick: apply a specific commit
git cherry-pick a1b2c3d git cherry-pick a1b2c3d b2c3d4e git cherry-pick --no-commit a1b2c3d
Applies a specific commit (by ID) to the current branch, without merging the whole branch. Useful for bringing an urgent fix into the release without dragging the rest of the feature. The --no-commit applies the changes without committing.
Rebase (linear history)
git checkout feature git rebase main
"Teleports" your commits the if they had been made after the latest ones on main, leaving the history linear and clean. Dangerous on branches shared on the remote: rewriting someone else's history causes conflicts and lost work.
Merge vs Rebase: when to use
Merge: preserves the real history, creates merge commits, safe on shared branches. Use it when you work in a team on the remote.
Rebase: rewrites the history to be linear, cleaner to read. Use it only on local and personal branches, before doing push.
Golden rule: never rebase on public branches that others also use.
Remote
Link local repository to the remote
git remote add origin https://github.com/user/repo.git
Adds the remote repository with the name origin (convention for the main remote). From here you can use git push and git fetch to sync with GitHub, GitLab or Bitbucket.
git pull: fetch + merge
git pull git pull origin main
Brings the changes from the remote and applies them automatically to your current branch. It's the equivalent of git fetch + git merge. If there are divergences, it can generate conflicts or a merge commit.
Push with upstream (-u)
git push -u origin branch-name
Sends the branch and links it to the remote (sets the upstream). From then on, git push and git pull work with no arguments — Git already knows where the code comes from and goes to.
View remote repositories (git remote -v)
git remote git remote -v git remote show origin
Lists the configured remotes. The -v shows the fetch and push URLs (lets you confirm whether you're using HTTPS or SSH). The git remote show origin gives the full detail: tracked branches and sync status.
pull vs fetch
git fetch: downloads the news but doesn't touch your code — safe to peek. git pull: downloads and integrates right into your branch. When in doubt, use fetch first, see what changed with git log origin/main, and only then decide between merge or rebase.
Safe force push (--force-with-lease)
git push --force-with-lease git push --force
After a rebase, the history diverges from the remote and the normal push is refused. The --force overwrites the remote blindly and dangerously; the --force-with-lease only advances if no one has sent new commits — always use this one.
Rename or remove a remote
git remote rename origin upstream git remote remove upstream
The rename changes a remote's name (and updates all the references). The remove deletes the link — your local commits are not affected, you just can no longer push/pull to that address.
git pull --rebase (linear history)
git pull --rebase git config --global pull.rebase true
Brings the changes from the remote and reapplies your commits on top, without creating merge commits. It keeps the history clean and linear. You can make this behavior the default with the pull.rebase true configuration.
git fetch: look without touching
git fetch git fetch origin git fetch --all --prune
Downloads the news from the remote (new commits, branches) without changing your local work — you can inspect before deciding. The --prune deletes the local references to remote branches that have already been deleted on the server.
Send changes (git push)
git push origin branch-name git push
Sends the commits of your local branch to the origin remote. If the branch doesn't exist on the remote, it's created. After setting the upstream (see the next card), just git push.
Stash
Save changes without committing (git stash)
git stash git stash push
Saves the uncommitted changes and returns the working directory to the clean state of the last commit. Perfect when you need to switch branch "right now" without losing the work in progress.
Apply a stash (git stash apply)
git stash apply
git stash apply stash@{2}git stash apply reapplies the saved changes to the working directory without removing the stash from the list — you can apply it on several branches or keep the backup copy.
Stash with a message
git stash push -m "WIP: form de login"
The -m flag gives a message to the stash — essential to identify it in the list when you have several saved. Without it, Git uses the generic WIP on branch... message, hard to tell apart.
Apply and remove (git stash pop)
git stash pop
Applies the most recent stash and removes it from the list, in a single step. It's the normal flow: you saved with git stash, you return to work with git stash pop.
Stash with untracked files (-u)
git stash -u git stash --include-untracked
By default, the stash ignores new (untracked) files. The -u includes them — useful when you created files that hadn't yet had a git add.
Remove a specific stash
git stash drop stash@{0}Deletes a stash from the list without applying it. Use the identifier you see in git stash list — for example stash@{1} for the second most recent.
View the list of stashes
git stash list
git stash show stash@{1}
git stash show -p stash@{1}Lists all the stashes with identifiers stash@{0}, stash@{1}, etc. (the {0} is the most recent). The show summarizes the changes and the -p shows the full diff — so you can see what you saved before applying.
Delete all stashes
git stash clear
Deletes all the stashes at once. Warning: there's no confirmation nor a reflog that returns them easily — confirm with git stash list first.
Undo Changes
Fix the last commit (--amend)
git commit --amend -m "New message" git add file-esquecido.php git commit --amend --no-edit
Rewrites the last commit: changes the message or adds forgotten files (with --no-edit it keeps the message). Only on local commits — doing an amend on an already-sent commit rewrites the history and causes confusion on the remote.
Discard changes in a file (git restore)
git restore file.php git restore .
Reverts the file to the state of the last commit, discarding the unsaved changes. It's the modern replacement for the old git checkout -- file. Warning: discarded changes are not recoverable.
Remove the last commit keeping changes
git reset HEAD~1 git reset HEAD~3
Undoes the last commit but keeps the changes in the working directory (mixed mode, the default). The number after the ~ indicates how many commits to go back: HEAD~3 removes the last three.
Undo a commit with another commit (git revert)
git revert a1b2c3d git revert HEAD
Creates a new commit that cancels the changes of the indicated commit, without touching the history. It's the only safe way to undo on shared branches — unlike reset, which rewrites the past.
The three reset modes
git reset --soft HEAD~1 git reset --mixed HEAD~1 git reset --hard HEAD~1
--soft: removes the commit, keeps everything in staging. --mixed (default): removes the commit and the staging, keeps the files. --hard: deletes everything — commit, staging and changes on disk. The --hard is destructive: use it only when sure.
Clean untracked files (git clean)
git clean -n git clean -f git clean -fd git clean -fdx
Deletes untracked files from the working directory. The -n is a dry run (shows what would be deleted, without deleting); the -f forces, the -d includes folders and the -x also those ignored by the .gitignore. Always do -n first.
Take files out of staging (git restore --staged)
git restore --staged file.php git restore --staged .
Undoes the git add: the file leaves the staging area but the changes stay on disk. It lets you fix what will go into the next commit without losing work.
reset vs revert vs restore
git reset: moves the HEAD pointer back — rewrites the history, only for local commits. git revert: creates a commit that cancels another — safe on the remote. git restore: undoes changes in files (on disk or in staging), without touching commits. Simple rule: local → reset; shared → revert; files → restore.
Advanced
Interactive rebase (rebase -i)
git rebase -i HEAD~3 git rebase --continue
Opens an editor with the last 3 commits for you to rewrite them: change the order, join (squash), rename (reword) or delete (drop). After saving, continue with git rebase --continue. Ideal to clean up "wip" commits before a push.
Git Hooks
# .git/hooks/pre-commit #!/bin/sh php artisan test
The hooks are scripts run automatically at key points: pre-commit (before each commit — ideal to run tests or linters), commit-msg (validate the message), pre-push, etc. They live in the .git/hooks/ folder and are not versioned by default.
Maintenance (git gc)
git gc git prune git count-objects -v
The git gc (garbage collection) compresses the history and removes unreachable objects, keeping the .git folder small and fast. Git already runs it automatically from time to time; force it on very old repositories or after big cleanups.
Interactive rebase commands
In the rebase -i editor, each line starts with a command:
pick: keeps the commit the it is.reword: keeps it but edits the message.squash: joins it to the previous commit (keeping the messages to edit).fixup: joins it to the previous one, discarding the message.drop: deletes the commit.edit: stops at that commit for you to change it (with--amend).
Archive the project (git archive)
git archive -o release-v1.0.zip v1.0.0 git archive --format=tar.gz --prefix=app/ HEAD > app.tar.gz
Exports the state of the project at a given point (tag, branch or commit) to a zip or tar — without the .git history. Ideal to deliver releases or make backups of the code.
Tags (git tag)
git tag v1.0.0 git tag -a v1.0.0 -m "Version 1.0.0" git tag -l "v1.*" git push origin v1.0.0 git push origin --tags
Tags mark fixed points of the history, usually versions (v1.0.0). The annotated ones (-a) store author, date and message. Tags do not go to the remote automatically — use git push origin --tags.
Aliases: custom shortcuts
git config --global alias.st status git config --global alias.co checkout git config --global alias.lg "log --oneline --graph --all"
The aliases create shortcuts for the commands you use most. After alias.st status, you just write git st. The classic git lg gives you the full visual history with three keys.
Worktrees: several branches at the same time
git worktree add ../project-hotfix hotfix/urgent git worktree list git worktree remove ../project-hotfix
The worktree creates a second working folder of the same repository, on another branch — without duplicated clones. Perfect to fix an urgent bug without saving what you have in hand with stash.
Submodules
git submodule add https://github.com/lib/dependency.git libs/dep git submodule update --init --recursive git clone --recurse-submodules URL
The submodules embed another repository inside yours, with the version pinned at a specific commit. After cloning a project with submodules, the --init --recursive downloads them. Modern alternatives: packages via composer or npm.
Extras and Good Practices
Vim: enter edit mode
When Git opens vim (on a commit without -m, for example), you're in normal mode — the keys don't write. To edit, press:
i→ insert where the cursor isa→ insert after the cursoro→ create a new line below
You'll see -- INSERT -- at the bottom. To return to normal mode, press Esc.
Git Emojis: performance and security
⚡ PERF – Performance improvements. Ex.: ⚡ PERF: optimize database query.
🔒 SECURITY – Vulnerability fix. Ex.: 🔒 SECURITY: prevent SQL Injection in the login.
🚑 HOTFIX – Urgent fix in production. Ex.: 🚑 HOTFIX: fix downtime in payments.
🗑 REMOVE – Remove obsolete code or files. Ex.: 🗑 REMOVE: delete old tests.
Vim: save and exit
In normal mode (after Esc):
:w— save (write):q— exit (quit):wq— save and exit:q!— exit without saving:x— save and exit, but only if there were changes
If you got stuck in the editor during a commit: Esc, then :wq and Enter.
Anatomy of a good commit message
A good git commit message has three parts:
- Title (up to 50 characters): imperative and direct — "Add email validation", not "added".
- Blank line to separate.
- Body (optional): explains the why and the context, not the how (the code shows that).
If the title needs an "and", it's probably two commits.
Git Emojis: features and fixes
📦 NEW – Add a new feature or module. Ex.: 📦 NEW: create authentication module with Google.
➕ ADD – Add simple code to something already existing. Ex.: ➕ ADD: add "phone" field to the record.
🐛 FIX – Fix an error or unexpected behavior. Ex.: 🐛 FIX: fix failure in email validation.
👌 IMPROVE – Improve existing code (performance, readability). Ex.: 👌 IMPROVE: optimize dashboard loading.
🚀 RELEASE – Publish a new version. Ex.: 🚀 RELEASE: version 1.2.0 released.
Recommended daily workflow
git status git add . git commit -m "📦 NEW: add pagination" git pull --rebase git push
The safe day-to-day cycle: check the state with git status, prepare with git add, save with git commit, sync with git pull --rebase (resolve conflicts locally) and only then send with git push.
Git Emojis: documentation, style and tests
📝 DOCS – Documentation updates. Ex.: 📝 DOCS: update README com instructions de installation.
🖌 STYLE – Style/formatting changes (without affecting logic). Ex.: 🖌 STYLE: adjust colors e position dos buttons.
🐳 DOCKER – Changes in Docker configurations or images. Ex.: 🐳 DOCKER: update container base image.
♻ REFACTOR – Refactoring without changing behavior. Ex.: ♻ REFACTOR: divide func big em methods menores.
✅ TEST – Add or improve automated tests. Ex.: ✅ TEST: tests unit to authentication.
Branch naming conventions
Consistent names keep the repository predictable:
feature/name— new feature (born frommain/develop).bugfix/name— day-to-day bug, not critical.hotfix/name— urgency in production.release/1.2.0— version preparation (changelog, final tests).
Use lowercase and hyphens (feature/login-social) and be specific: fix-bug says nothing to anyone.