Git
sequenceDiagram
autonumber
participant W as Workspace
participant S as Staging Area
participant L as Local Repository
participant R as Remote Repository
rect rgb(225, 240, 255)
W->>S: git add / git mv / git rm
end
rect rgb(255, 235, 220)
S->>L: git commit
W->>L: git commit -a
end
rect rgb(235, 250, 225)
S->>W: git reset path/to/file
L->>W: git reset commit-hash
end
Note over W,S: git diff<br/>Workspace to Staging
Note over W,L: git diff HEAD<br/>Workspace to HEAD
rect rgb(235, 250, 225)
L->>R: git push
end
rect rgb(255, 245, 200)
R->>L: git fetch
R->>L: git pull - fetch changes
L->>W: git pull - merge and update files
R->>L: git clone - create local repository
L->>W: git clone - create working files
end
Cheat sheet
Clone
git clone copies a remote repository to your machine and creates a local working directory.
Clone the default branch:
Clone a specific branch:
Clone into a target folder:
Clone a specific branch into a target folder:
Clone a specific tag:
Clone the repository and all submodules in one line:
Push and pull
git push uploads commits from your local branch to a remote repository.
It does not upload uncommitted file changes.
Push commits from the current branch:
| push current branch | |
|---|---|
Push a new local branch and set the remote tracking branch:
| push new branch | |
|---|---|
Push a local branch to a different remote branch name:
| push to different remote branch | |
|---|---|
Push tags:
| push tags | |
|---|---|
Delete a remote branch:
| delete remote branch | |
|---|---|
Warning
Avoid git push --force on shared branches.
If you must update a rewritten branch, prefer git push --force-with-lease because it refuses to overwrite remote work you have not fetched.
Force push after rewriting local history:
| safer force push | |
|---|---|
git pull downloads changes from a remote branch and updates your current branch.
By default, pull is similar to git fetch followed by git merge.
Pull the latest changes:
| pull latest changes | |
|---|---|
Pull from a specific remote branch:
| pull specific branch | |
|---|---|
Note
A normal git pull may create a merge commit when your local branch and the remote branch both have new commits.
If Git can fast-forward your branch, no merge commit is created.
Pull without creating a merge commit:
| pull only if fast-forward is possible | |
|---|---|
Pull with rebase instead of merge:
| pull with rebase | |
|---|---|
If you have uncommitted changes when pulling, Git tries to keep them. If the remote changes touch the same files, Git may stop the pull and ask you to commit, stash, or discard your local changes first.
Check your local changes before pulling:
| check working tree | |
|---|---|
Stash uncommitted changes before pulling:
Commit local changes before pulling:
Pull with automatic stash:
| pull with auto stash | |
|---|---|
Note
--autostash temporarily stashes your uncommitted changes, pulls the remote changes, then reapplies your work.
Conflicts can still happen when the same lines changed locally and remotely.
git pull updates the branch you are currently on.
To review remote changes in a new branch, create the review branch first.
Create a review branch from the remote branch:
Pull into an existing review branch:
After reviewing, commit your own changes on the review branch:
Fetch remote changes without merging into your current branch:
| fetch without changing current branch | |
|---|---|
Show local commits that are not pushed yet:
| show unpushed commits | |
|---|---|
Show remote commits that you have not pulled yet:
| show unpulled commits | |
|---|---|
branch
Git branches let you work on features, fixes, or experiments without changing the main code line.
Create a new branch:
| create branch | |
|---|---|
Create a new branch and switch to it:
| create and switch branch | |
|---|---|
Switch between branches:
| switch branch | |
|---|---|
Switch to a remote branch:
Show local branches:
| show local branches | |
|---|---|
Show local and remote branches:
| show all branches | |
|---|---|
Delete a local branch:
| delete local branch | |
|---|---|
Force delete a local branch:
| force delete local branch | |
|---|---|
Delete a remote branch:
| delete remote branch | |
|---|---|
Push a local branch that does not have a remote branch yet:
| push new branch to remote | |
|---|---|
Rename the current branch:
| rename current branch | |
|---|---|
Show the current branch:
| show current branch | |
|---|---|
Show merged branches:
| show merged branches | |
|---|---|
Warning
git branch --merged only shows branches that still exist locally.
If a merged source branch was already deleted, it will not appear in the output.
The merged commits are still part of the history, but the branch name is gone.
Discard file changes
Use these commands when you want to throw away local uncommitted changes.
Warning
These commands discard changes from your working tree. Make sure you do not need the changes before running them.
Discard changes in all tracked files:
| discard all tracked file changes | |
|---|---|
Discard changes in one file:
| discard one file | |
|---|---|
Discard staged changes but keep the file content:
| unstage file changes | |
|---|---|
Discard staged and unstaged changes in one file:
| discard staged and unstaged file changes | |
|---|---|
Remove untracked files and folders:
| remove untracked files and folders | |
|---|---|
Merge
git merge combines changes from another branch into the branch you are currently on.
For example, if you are on main and merge feature/login, Git brings the commits from feature/login into main.
Merge a branch into the current branch:
Merge process:
- Git checks the current branch.
- Git finds the common commit between the current branch and the branch being merged.
- Git applies the commits from the source branch into the current branch.
- If the changes do not conflict, Git completes the merge.
- If both branches changed the same lines, Git stops and asks you to resolve conflicts.
Note
If the current branch has no new commits, Git can do a fast-forward merge. If both branches have new commits, Git creates a merge commit.
Merge without creating a merge commit only if fast-forward is possible:
| fast-forward only merge | |
|---|---|
Always create a merge commit:
| merge with merge commit | |
|---|---|
Abort a merge before finishing it:
| abort merge | |
|---|---|
Resolve merge conflicts:
Rebase
git rebase moves your branch commits so they start from a newer base commit.
It is commonly used to update a feature branch with the latest changes from main while keeping a linear history.
Rebase the current branch on top of main:
Rebase one branch onto another branch:
Rebase process:
- Git finds the commits that exist only on your current branch.
- Git temporarily removes those commits.
- Git moves your branch to the new base branch.
- Git reapplies your commits one by one.
- If conflicts happen, Git stops and asks you to resolve them.
Continue after resolving rebase conflicts:
Abort a rebase and return to the previous state:
| abort rebase | |
|---|---|
Skip the current commit during a rebase:
| skip rebase commit | |
|---|---|
Interactive rebase for editing, squashing, or reordering commits:
| interactive rebase | |
|---|---|
Pull remote changes using rebase instead of merge:
| pull with rebase | |
|---|---|
Warning
Rebase rewrites commit history.
Avoid rebasing commits that were already pushed to a shared branch unless your team expects that workflow.
If you rebase a pushed branch, you usually need git push --force-with-lease.
Diff
Git provides several ways to compare files across commits and branches.
Compare the same file between two commits
Example:
This shows how src/main.cpp changed from commit a1b2c3d to commit
f4e5a6b.
Compare the same file between two branches
Example:
Compare different files
You can compare any two file versions using the <revision>:<path> syntax.
The files can have different paths and can come from different branches:
Example:
This is useful when a file was renamed or moved.
Compare a working-tree file with a commit
Compare the current working-tree version with the version from the previous commit:
Compare it with any arbitrary commit:
Compare files from arbitrary commits
The file paths can be different, which is useful when a file was renamed or moved:
Example:
Open a graphical diff tool
If a Git diff tool is configured:
Or compare the file between two commits:
Popular graphical diff tools include VS Code, Meld, KDiff3, and Beyond Compare.
Find commit IDs
Show the repository's commit hashes:
Show only commits that changed a specific file:
Useful summary
| Task | Command |
|---|---|
| Same file, two commits | git diff c1 c2 -- file.cpp |
| Same file, two branches | git diff branch1 branch2 -- file.cpp |
| Different files | git diff branch1:file1.cpp branch2:file2.cpp |
| Working tree versus commit | git diff HEAD -- file.cpp |
| Graphical diff | git difftool c1 c2 -- file.cpp |
Compare with VS Code
Compare two files that exist on disk:
In Bash or Zsh, compare two versions stored in Git without checking out either branch:
This opens VS Code's side-by-side diff editor. The <(command) syntax is
shell process substitution and works in Bash and Zsh.
Log
git log shows commit history. It helps you find commit IDs, understand recent
work, and locate when a file changed.
Show a compact history:
Use the commit IDs with commands such as git diff, git show, git revert,
and git cherry-pick.
Show branches and merges as a graph:
This gives a quick view of the branch structure and the current HEAD.
Show commits that changed a file, including history before a rename:
Use this to find when a file changed or which commit introduced a problem.
Find commits by author or by commit-message text:
These filters help locate relevant work in a large history.
Show commits on the current branch that are not on main:
Use this before opening a pull request to confirm which commits it will contain.
Stash
git stash temporarily stores uncommitted work and returns the working tree to
a clean state. It is useful when you must switch branches or pull changes before
your current work is ready to commit.
Save tracked changes with a descriptive name:
Include untracked files when they are part of the work:
List saved stashes:
Review a stash before restoring it:
Restore the newest stash and remove it from the stash list:
Use apply instead when you want to keep the saved stash as a backup:
Delete a stash only after confirming it is no longer needed:
Note
Applying a stash can cause conflicts when the same lines changed after the stash was created. Resolve the conflicts as you would during a merge.
Cherry-pick
git cherry-pick copies a specific commit onto the current branch as a new
commit. It is useful for bringing over a focused bug fix without merging the
entire source branch.
First, switch to the branch that should receive the change and confirm it:
Find the required commit and apply it:
Apply several specific commits in the given order:
Review the result after cherry-picking:
If conflicts occur, resolve the files, stage them, and continue:
Abort the operation and return to the state before the cherry-pick:
Warning
Cherry-picking creates a new commit with a different ID. Avoid copying the same change through both cherry-pick and a later merge, because this can duplicate work or cause conflicts.
TODO
- git reset
- git revert