Skip to main content

Git - distributed version control system

Git allows a group of software developers to manage changes of sourse code over time. It's the most popular version control system, and when you're involved in a software development, you will most-likely use Git with other people.

Basics

General setup

Set a name that is identified for credit when review version history

git config --global user.name "[Firstname Lastname]"

Set an email address that will be associated with each history maker

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 means that the values will be shared among your local git repositories, and it is stored in your ~/.gitconfig file.

You can also locally set a different email(e.g. work email) in a particular repo like this:

# 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 the 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 snapsot

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 differences of what have been changed but not staged

git diff

Show differences of what have been staged but not commited

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 shows with a *

git branch

Create a new branch at the current commit

git branch [branch-name]

Swtich 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 the commits that changed 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 change

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 that --cached option, the file won't be deleted, which will show up as an unstaged file in the output of git status. If you want it to stay there untracked, add it in 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're examples:

logs/
*.pyc
pattern*/

When you want to set the list of ignored files/dirs globally, create $HOME/.config/git/ignore, and list the ignored files in the file. You can find the examples of global ignores at github / gitignore.

Optional

git config

Create a shortcut for a git command. E.g. 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 --orpha <new branch>

# Create, commit, and push
git switch --orpha <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

And have the following in 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]

The seven rules of a great Git commit message

  1. Separate subject from body with a blank line
  2. Limit the subject line to 50 characters
  3. Capitalize the subject line
  4. Do not end the subject line with a period
  5. Use the imperative mood in the subject line
  6. Wrap the body at 72 characters
  7. Use the body to explain what and why vs. how

Reference: How to Write a Git Commit Message