Git - distributed version control system
Git enables developers to collaboratively manage and track changes to source code. As the most widely used version control system, Git is essential in most software projects.
Basics
General setup
Set the name used in your commits
git config --global user.name "[Firstname Lastname]"
Set the email address associated with your commits
git config --global user.email "[valid email]"
Change the default branch name from "master" to "main"
git config --global init.defaultBranch main
NOTE: The --global
option applies to all local Git repositories and is stored in your ~/.gitconfig
file.
You can also set a different email locally (e.g., a work email) for a particular repository:
# Change directory to the repo
cd /path/to/repo
# Set an email address locally
git config --local user.email "[work email]"
# Or, you don't actually need "--local" since the default is local
git config user.email "[work email]"
# Check the config
cat .git/config
Set your preferred editor for Git
git config --global core.editor "vim"
Repository setup
Initialize your current directory as a Git repository
git init
Initialize a shared Git repository. Conventionally, repositories with the --bare
flag
end in .git
.
git init --bare [directory]
# e.g.
git init --bare my_project.git
Retrieve an entire repository from a hosted location.
# via URL
git clone [url]
# via SSH
git clone [user]@[server]:[path to a bare repository]
# a bare repo on a local computer
git clone [path to a bare repository]
Stage and snapshot
Show modified files - both staged and unstaged
git status
Stage a file or directory for your next commit
git add [file/directory]
# Patch mode
git -p add [file/directory]
Unstage a file or directory while retaining the changes
git reset [file/directory]
Show changes that are not staged
git diff
Show changes that are staged but not committed
git diff --staged
Commit your staged content as a new commit snapshot
git commit -m "[descriptive message]"
Branch and merge
List branches. The current branch is marked with a *
git branch
Create a new branch at the current commit
git branch [branch-name]
Switch to another branch and check it out into your working directory
git checkout [branch]
Merge the specified branch's history into the current one
git merge [branch]
Show all commits in the current branch's history
git log
Inspect and compare
Show the history of the current branch
git log
Show commits on branchA that are not on branchB
git log branchB..branchA
Show commits that changed a file
git log --follow [file]
Show the diff of what is in branchA that is not in branchB
git diff branchB..branchA
Compare a particular file in two branches -- main and dev
git diff main..dev -- path/to/file
Removal and file path changes
Delete the file from project and stage the removal for commit
git rm [file]
Untrack the file from project and stage the removal for commit.
git rm --cached [file]
NOTE: With the --cached
option, the file isn't deleted; it will show up as an unstaged file in the output of git status
. To keep it untracked, add it to the .gitignore
file.
Change an existing file path and stage that move
git mv [existing-path] [new-path]
Show all commit logs with indication of any paths that moved
git log --stat -M
Ignoring files/directories
Create a .gitignore
file in your repository and list the files and directories
that you want to ignore. Here are examples:
logs/
*.pyc
pattern*/
To configure global ignores, create $HOME/.config/git/ignore
and list ignored files there. See
github / gitignore for examples.
Optional
git config
Create a shortcut for a Git command. For example, git glog
as git log --graph --oneline
:
git config alias.glog "log --graph --oneline"
# These two are the same now
git glog
git log --graph --oneline
Change editor (e.g. vim)
git config --global core.editor "vim"
Tips
Compare two branches (e.g. main and dev)
git diff main...dev
Tell git which ssh private key to use
# Set it permanently in the .git/config
git config core.sshCommand "ssh -i ~/.ssh/another_key"
# Just once
git -c core.sshCommand="ssh -i ~/.ssh/another_key" clone ...
# Environment variable
export GIT_SSH_COMMAND="ssh -i ~/.ssh/another_key"
Create a new empty branch
git switch --orphan <new branch>
# Create, commit, and push
git switch --orphan <new branch>
git commit --allow-empty -m "Initial commit on orphan branch"
git push -u origin <new branch>
Create a new branch in another worktree
git worktree add <path> <branch>
Create a throwaway worktree. You can make some experimental changes or do testing without disturbing existing development.
git worktree add -d <path>
Simple way to track config files by a bare git repo
Using a bare git repo with the status.showUntrackedFiles no
option allows you to safely track the files you want to keep tracking.
git init --bare $HOME/.myfiles
alias myfiles='/usr/bin/git --git-dir=$HOME/.myfiles/ --work-tree=$HOME'
myfiles config --local status.showUntrackedFiles no
Add the following to your ~/.bashrc
or ~/.zshrc
:
alias myfiles='/usr/bin/git --git-dir=$HOME/.myfiles/ --work-tree=$HOME'
Now, you're all set.
myfiles add .zshrc
myfiles commit -m "Add zshrc file"
myfiles push --set-upstream origin master
Reference: The best way to store your dotfiles: A bare Git repository
Create an empty branch
git checkout --orphan [empty-branch]
git rm -rf .
git commit --allow-empty -m "empty commit"
git push origin [empty-branch]
Delete and recreate a tag
# delete the tag locally
git tag -d v0.2.28
# delete the tag on the remote
git push --delete origin v0.2.28
# recreate the tag
git tag v0.2.28
# push the new tag
git push origin v0.2.28
git tag -f v0.2.28
git push origin -f v0.2.28
The seven rules of a great Git commit message
- Separate subject from body with a blank line
- Limit the subject line to 50 characters
- Capitalize the subject line
- Do not end the subject line with a period
- Use the imperative mood in the subject line
- Wrap the body at 72 characters
- Use the body to explain what and why vs. how
Reference: How to Write a Git Commit Message