Learn Git - Version Control
Git Knowledge Summary
Related Stuff
Core Concepts
- Repository (Repo): A storage space for your project’s files and their history. It lives in the
.gitdirectory. - Working Directory: The folder on your computer containing the project files you're currently editing.
- Index (Staging Area): A "holding area" where you place changes you want to include in your next commit.
- Commit: A snapshot of the staged changes in your repo at a specific point in time.
- Branch: A parallel version of your repo. It's essentially a movable pointer to a specific commit.
- HEAD: A pointer that refers to your current location in the repository. This is usually the tip of the branch you're working on.
- Merge: Combines changes from one branch (or commit) into another.
- Rebase: Re-applies commits from one branch onto the tip of another branch, creating a cleaner, more linear history.
- Remote: A shared version of your repo hosted on a server (e.g., on GitHub or GitLab) for collaboration.
- Fetch: Downloads changes from a remote repository but doesn't integrate them into your working directory.
- Pull: Fetches changes from a remote repository and merges (or rebases) them into your current branch.
- Push: Uploads your local commits to a remote repository.
Commands
Setup & Basic Workflow
This section covers initializing a repository, configuring Git, and the fundamental "add, commit, check status" loop.
| Command | Description |
|---|---|
git init |
Initializes a new Git repository in the current directory. |
git clone <url> |
Clones an existing repository from a remote URL to your local machine. |
git config --global user.name "<name>" |
Sets the user name that will be attached to your commits. |
git config --global user.email "<email>" |
Sets the email address that will be attached to your commits. |
git config --global init.defaultBranch <name> |
Sets the name for the default branch (e.g., main). |
git status |
Displays the state of the working directory and the staging area. |
git add <file> |
Stages changes in the specified file for the next commit. |
git add . |
Stages all changes (new, modified, deleted) in the current directory. |
git add -p |
Interactively stages portions of changes within files. |
git commit -m "<msg>" |
Records staged changes to the repository with a descriptive message. |
git commit -am "<msg>" |
Stages all tracked, modified files and commits them in one step. |
git commit --amend |
Amends the most recent commit (e.g., to change the message or add files). |
git log |
Shows the commit history for the current branch. |
git log --oneline --graph --decorate |
A more concise, visual log showing branches and commit history. |
git diff |
Shows changes in the working directory that are not yet staged. |
git diff --staged |
Shows changes that are staged but not yet committed. |
git diff <branch1>..<branch2> |
Shows the differences between two branches. |
git rm <file> |
Removes a file from the working directory and stages the removal. |
git mv <old-name> <new-name> |
Renames a file and stages the move. |
Branching Commands
This section focuses on all commands related to creating, managing, and integrating branches.
| Command | Description |
|---|---|
git branch |
Lists all local branches. git branch -a lists all local and remote branches. |
git branch <branch-name> |
Creates a new branch based on the current commit. |
git branch -d <branch-name> |
Deletes a specified local branch (if it has been merged). |
git branch -D <branch-name> |
Force-deletes a specified local branch (even if unmerged). |
git branch -m <old-name> <new-name> |
Renames a branch. |
git branch -vv |
Lists all local branches with their upstream tracking information. |
git merge <branch> |
Merges changes from the specified branch into the current branch. |
git merge --no-ff <branch> |
Merges, but creates a merge commit even if a fast-forward is possible. |
git merge --abort |
Aborts a merge operation that has conflicts. |
git rebase <branch> |
Applies commits from the current branch onto the tip of <branch>. |
git rebase -i <commit> |
Interactively rebase commits, allowing for reordering, squashing, editing, etc. |
git rebase --continue |
Continues a rebase after resolving conflicts. |
git rebase --abort |
Aborts a rebase operation and returns to the state before it began. |
git cherry <branch> |
Shows the commits in <branch> that are not in the current branch. |
git cherry-pick <commit> |
Applies the changes from a specific commit to the current branch. |
|
Checkout & Navigation (The checkout, switch, and restore commands)
This section covers commands used to move around the repository, switch branches, and discard changes. Note: git switch and git restore are modern commands (added in Git 2.23) that are recommended over the "overloaded" git checkout for these actions.
| Command | Description |
|---|---|
| Modern Commands (Recommended) | |
git switch <branch> |
Switches the HEAD pointer and working directory to the specified branch. |
git switch -c <new-branch> |
Creates a new branch and switches to it. |
git restore <file> |
Discards changes in the specified file in the working directory. |
git restore --staged <file> |
Unstages a file, moving it from the staging area back to the working directory. |
Legacy checkout Command |
|
git checkout <branch> |
(Legacy) Switches to the specified branch. (Use git switch instead). |
git checkout -b <new-branch> |
(Legacy) Creates a new branch and switches to it. (Use git switch -c instead). |
git checkout -- <file> |
(Legacy) Discards changes in the specified file. (Use git restore instead). |
git checkout <commit> -- <file> |
Checks out a specific version of a file from a past commit. |
git checkout <commit> |
Enters a "detached HEAD" state, checking out a specific commit, not a branch. |
Working with Remotes
These commands are essential for collaborating with others and synchronizing your local repository with a remote one.
| Command | Description |
|---|---|
git remote -v |
Displays the remote repositories (and their URLs) associated with your local repo. |
git remote add <name> <url> |
Adds a new remote repository with a specified name (e.g., origin). |
git remote remove <name> |
Removes the remote repository specified by <name>. |
git remote set-url <name> <new-url> |
Changes the URL for a remote repository. |
git fetch |
Retrieves all updates from all remote repositories without merging. |
git fetch <remote-name> |
Retrieves updates from a specific remote (e.g., git fetch origin). |
git pull |
Fetches changes from the remote and merges them into the current branch. |
git pull --rebase |
Fetches changes and rebases your local commits on top of the remote changes. |
git push |
Pushes committed changes from your current local branch to its upstream remote branch. |
git push <remote-name> <branch-name> |
Pushes a specific branch to a specific remote. |
git push -u <remote-name> <branch-name> |
Pushes a branch and sets it to track the remote branch (links them). |
git push --force-with-lease |
A safer way to force-push, as it won't overwrite remote work you haven't seen. |
git push <remote-name> --delete <branch> |
Deletes a specific branch on the remote repository. |
Advanced & Utility Commands
This section includes commands for inspecting history, undoing mistakes, and other useful tools.
| Command | Description |
|---|---|
git stash |
Temporarily saves changes that are not ready to be committed. |
git stash list |
Lists all stashed changes. |
git stash pop |
Applies the most recent stash and then removes it from the stash list. |
git stash apply |
Applies the most recent stash but leaves it in the stash list. |
git stash drop |
Deletes the most recent stash. |
git reset <commit> |
(Mixed reset) Moves HEAD to <commit> and unstages changes made since. |
git reset --soft <commit> |
Moves HEAD to <commit> but leaves changes staged (ready to re-commit). |
git reset --hard <commit> |
(Dangerous) Moves HEAD to <commit> and discards all changes since. |
git revert <commit> |
Reverts a commit by creating a new commit that undoes the changes. |
git reflog |
Shows a log of all actions HEAD has taken. Your "safety net" for recovering lost commits. |
git blame <file> |
Shows who made changes to each line of the specified file and in which commit. |
git show <commit> |
Displays information about a specific commit (metadata and changes). |
git tag <tag-name> |
Creates a lightweight tag at the current commit. |
git tag -a <tag-name> -m "<msg>" |
Creates an annotated tag (recommended) with a message. |
git push --tags |
Pushes all local tags to the remote repository. |
git clean -fd |
(Dangerous) Removes all untracked files (-f for force) and directories (-d). |
git bisect |
Uses binary search to find the specific commit that introduced a bug. |
git archive |
Creates an archive (e.g., a .zip file) of files from a particular tree or commit. |
Cherry pick
The standard command is:
git cherry-pick <start-commit-hash>..<end-commit-hash>
Important: This command selects all commits after <start-commit-hash> up to and including <end-commit-hash>. The starting commit itself is not included.
Including the Starting Commit
If you want to include the <start-commit-hash> in the range as well, you must add a ^ (caret) symbol to it:
git cherry-pick <start-commit-hash>^..<end-commit-hash>
This tells Git to start from the parent of the <start-commit-hash>, thus including the <start-commit-hash> itself in the list of commits to be picked.
Useful Option
--no-commitor-n: This flag applies the changes from all the commits in the range to your working directory and stages them, but it does not create individual commits. This allows you to review all the changes at once and make a single new commit.
git cherry-pick -n <start-commit-hash>^..<end-commit-hash>
# (Review changes)
git commit -m "Cherry-picked features from C to E"
Git rebase
git rebase -i (or git rebase --interactive) is a powerful command that lets you clean up your local commit history before sharing it with others.
Think of it as opening a "to-do list" for your recent commits. Instead of just accepting your history as is, you get to edit that list, changing what you did and how it's presented.
The main use case is to make your commit history clean and easy to read before you merge it into a shared branch (like main) or open a pull request.
How It Works: The Basic Steps
-
You run the command: You tell Git which commits you want to edit. A common way is
git rebase -i HEAD~3. This means "I want to interactively rebase the last 3 commits." -
Git opens an editor: Git opens your default text editor with a "to-do" list of the commits you selected. It looks something like this:
pick 1a2b3c4 Add login button pick 5d6e7f8 Fix typo in login button pick 9a8b7c6 Add user profile page # Rebase 1a2b3c4..9a8b7c6 onto 1a2b3c4 (3 commands) # # Commands: # p, pick = use commit # r, reword = use commit, but edit the commit message # s, squash = use commit, but meld into previous commit # d, drop = remove commit # ...and more -
You edit the list: You change the "command" (the word
pick) for each commit to tell Git what you want to do. -
You save and close: When you save and close the editor, Git executes your "to-do" list from top to bottom.
The Most Common Commands
Here are the most common commands you'll use in that interactive list:
pick(p): (Default) Use this commit as is. Don't change anything.reword(r): Use the commit's changes, but Git will pause and let you rewrite its commit message.squash(s): This is the most popular one. It melds (combines) this commit into the commit directly above it. Your two commits become one. Git will pause to let you write a new commit message for the combined commit.fixup(f): This is just likesquash, but it throws away this commit's message. It's great for "oops, typo" commits.drop(d): Completely deletes the commit.- Reordering: You can also just change the order of the lines in the file to reorder your commits.
Example
Let's say your history looks messy like this:
$ git log --oneline
9a8b7c6 (HEAD -> feature) Add user profile page
5d6e7f8 Fix typo
1a2b3c4 Add login button
This is messy. The "Fix typo" commit isn't useful. We want to combine it with "Add login button" and reword the "Add user profile page" commit.
Step 1: Run the command to edit the last 3 commits.
git rebase -i HEAD~3
Step 2: Your editor opens. You edit the file to look like this:
# Change 'pick' to 'reword' on the first line
r 1a2b3c4 Add login button
# Change 'pick' to 'fixup' to merge it into the commit above
f 5d6e7f8 Fix typo
# Leave this as 'pick' (or change order, etc.)
p 9a8b7c6 Add user profile page
Step 3: Save and close the editor.
Step 4: Git executes your list:
- It stops at
1a2b3c4and opens an editor for you to reword the message. You change it to "feat: Add login button" and save. - It automatically fixup
5d6e7f8into the newly reworded commit. No questions asked. - It picks
9a8b7c6as-is.
The Result: Your history is now clean and looks like this:
$ git log --oneline
c4d5e6f (HEAD -> feature) Add user profile page
a1b2c3d feat: Add login button
You now have two clean commits instead of three messy ones.
⚠️ The Golden Rule of Rebasing
NEVER use git rebase -i on commits that you have already pushed and shared with other people (e.g., on the main or develop branch).
Rebasing rewrites history by creating brand new commits. If you rewrite history that others are already working on, it will cause massive conflicts and problems for your team.
Use it only on your own local commits that nobody else has seen.
Links
- ← Previous
Learn Git Rerere - resolve a conflict once