Resources:
# Setup a repository
> git init
> git remote add origin ssh://user@website/blah.git
> git status # List changes / status
> git add [File to push] # Add changes
> git commit -m "[message]" # Finalize changes by adding a message
> git push -u origin main # Initial push.
# "git push" is sufficient afterwards
# Edit commit message
> git commit --amend
# Move files / directories without losing the history
> git mv [to move] [new location]
# Add change onto already made commit
> git add [File(s) with small edit]
> git commit --amend --no-edit
# Show changes since last commit
> git diff
# Show changes of file since last commit
> git diff [path to file]
# Compare two files from two commits
> git diff [commit hash]:[file] [commit hash]:[file]
# Compare the changes between two commits
> git diff [commit hash old] [commit hash new]
# Show stats of the changes between two commits
> git diff --stat [commit hash old] [commit hash new]
# Create and push a new branch
> git checkout -b [name]
> ... # Make changes to the branch
> git push -u origin [name]
# Switch branches
> git checkout [branch]
# Remove branches
> git push -d origin [branch] # Delete remote branch
> git branch -d [branch] # Delete local branch
# Temporarily remove changes
# (also possible if you want to temporarily switch branches)
> git stash
> ...
> git stash pop
# Pull changes/commits from another _remote_ branch
# onto the current one
> git pull origin [branch]
# Pull changes/commits from another _local_ branch
# onto the current one
> git pull . [branch]
# If you have the same repository in multiple directories,
# you can also pull the changes locally:
> git pull [path to repository]
# Undo a specific commit
# Find [hash] using git log, then:
> git revert [hash]
# Revert file to a specific commit
# Find [hash] using git log, then:
> git checkout [hash] -- path/to/fileA path/to/FileB
# _Completely_ discard all local changes
> git reset --hard HEAD
> git clean -d -f -i
# Merge changes from a branch onto main
> git checkout main
> git merge [branch]
# Rebase changes from a branch onto main
> git checkout [branch]
> git rebase main
# Remove a commit from your history before pushing
> git rebase -i HEAD~3 # List last 3 commits
# Opens a text editor. Now delete / modify the line of the commit
## Tags
# List tags
> git tag
# Create tag
> git tag -a [tag_name] # Creates tag
> git tag -a [tag_name] -m "[annotation]" # Creates tag with annotation
# Show tag info
> git show [tag_name]
# Push tag to remote
# (by default, git push does not push tags)
> git push origin [tag_name] # Push a single tag
> git push origin --tags # Push all local tags
# Delete tag locally
> git tag -d [tag_name]
# Delete tag on remote
> git push origin --delete [tag_name]
# Checkout tag (either of these work)
> git checkout [tag_name]
> git checkout tags/[tag_name]
Sometimes git
refuses to do operations for seemingly no reason.
In practice, it might be that some operation is in progress without any indication.
bisect
: check if .git/BISECT_BEGIN
existsmerge
: git rev-parse --verify MERGE_HEAD
(or check if .git/MERGE_HEAD
or .git/MERGE_MSG
exists or if git merge HEAD
fails)rebase
: git rev-parse --verify REBASE_HEAD
(or check if .git/REBASE_HEAD exists
)revert
: git rev-parse --verify REVERT_HEAD
cherry-pick
: git rev-parse --verify CHERRY_PICK_HEAD
Remove --global
to make changes local to a repository:
# Initial git configuration
> git config --global user.name "Your Name"
> git config --global user.email "Your@Mail.com"
# Change default branch name
> git config --global init.defaultBranch main
# When working with submodules, automatically update when updating a branch
> git config --global submodule.recurse true
# For multiple operating systems:
# If the different line endings are making problems,
# consider setting "autocrlf" to "true" or "input"
> git config --global core.autocrlf input
# Signing
# Enable commit signing
> git config --global commit.gpgsign true
> git config --global tag.gpgSign true
# Use GPG keys: List keys and use from key ID
# Example key ID: 3AA5C34371567BD2
> gpg --list-secret-keys --keyid-format=long
> git config --global user.signingkey [Key ID]
# Use SSH keys
# Example key location: /home/myUser/.ssh/id_rsa.pub
> git config --global gpg.format ssh
> git config --global user.signingkey [Path to Key]
This is super useful if you e.g.
have your own personal version of a public project
in your own git
repo, but you want
to pull updates from the public project
if necessary.
In my case, I cloned the repo and adjusted the repo settings:
> git clone [link to original repo]
> git remote set-url origin [url to personal repo]
And then add the original repository back under another upstream name.
> git remote add [name] [link to original repo]
> git pull [name] [branch]
Now I can work on my local version
without having to constantly remind myself to specify
where to push to.
In my case, I added an upstream called "upstream".
In the rare occasion that I want to pull in updates
from the original repo, just
do git pull upstream master
.
Recently I started a project with a friend, and each wanted to host
an up-to-date repository on a local server.
For a very basic mirroring setup, you can configure a "main"
repository for your project, and setup your local git
repo
such that you git push
to all of your mirrors automatically.
Simply setup your local repository as follows:
> git init
> git remote set-url --add --push origin [link to main repo]
> git remote set-url --add --push origin [mirror 1]
> ...
While all of the main actions (e.g. git pull
) is done on the
"main" repository, you git push
will automatically also
push to each mirror.
git
has a built-in command/process such that
you can binary search for the commit
in which a bug was introduced:
# Identify
# - a "good" commit hash [goodHash] in which the
# error is not present, and
# - a "bad" commit hash [badHash] in which the
# error is present
# (use "git log" and "git checkout [hash]")
#
# Then start the bisect process:
> git bisect start
> git bisect good [goodHash]
> git bisect bad [badHash]
# Git will then repeatedly switch you onto other commits.
# If the bug _is not_ present, do:
> git bisect good
# If the bug _is_ present, do:
> git bisect bad
# If the commit is not testable, do:
> git bisect skip
# After doing this a bunch of times,
# git will stop and tell you the commit
# in which the bug was introduced
[hash] is the first bad commit
...
# If you want to abort this process at any point:
> git bisect reset
# NOTE:
# You can use git bisect to find when a bug has been fixed,
# but git bisect is designed to find regressions.
# Therefore when finding the fix, you have to use
# "git bisect bad" when the bug was fixed, and
# "git bisect good" when the bug is present.
Many git
commands have additional options,
which provide helpful visualizations and/or denser/quieter outputs.
As typing the args each time is annoying, you can either
configure your shell, or add aliases to git
directly.
Find out where your git config is:
> git config --list --show-origin
And then you can e.g. define aliases for common operations:
[alias]
# Overview:
#
# Parameter alias:
# testA = "commit -A"
# -> "git testA" becomes "git commit -A"
#
# Insert shell commands:
# testB = "!git log; git push"
# -> "git testB" becomes "git log; git push"
# Shorthand for simple projects
update = "!git add -A; git commit; git push"
update-no-push = "!git add -A; git commit"
# Shorthand for quieter/denser outputs
ll = "log --oneline"
llv = "log --oneline --graph --decorate"
st = "status -s -b"
c = "commit"
br = "branch -a -v"
co = "checkout"
cb = "checkout -b"
You can run automatically run a script
when a certain git
command is issued.
In your git
project, the script file needs
to be placed in ./.git/hooks/
with a name
specific to the command you want to hook into
(see here
for a list of hooks).
The folder also already contains a bunch of example
scripts.
Here is the pre-commit
-hook I use on programming projects.
It automatically formats files of a commit before it is finalized
(./.git/hooks/pre-commit
):
#!/bin/sh
# Get list of changed files
ARGUMENTS=$(git diff-index --name-only --cached HEAD)
# Run formatter on files
[YOUR_FORMATTER] $ARGUMENTS
# Assuming the formatter run without problems,
# add the changes to the commit
git add $ARGUMENTS
# Signal that hook ran successfully
exit 0
Don't forget: For very simple projects (e.g. updating this website), you can even automate / simplify your commits if aliases are not sufficient! For this website, I don't care about commit messages, and I keep have to add new posts/files to git. So I use the following script:
#!/bin/sh
# Overview pages
git add byName.html index.html
# Content pages
git add posts/
# Other
git add style.css Icon16.png Icon32.png
# Push
git commit -m "$(date)"
git push
# Assume you are currently in [original repo],
# [splitBranch] is just a name for the split
git subtree split -P [to move] -b [splitBranch]
# If you want to move the items onto a new repository
> cd [new repo]
> git checkout [your branch]
> git pull [path to original repo] [splitBranch]
# If you want to move the items into an existing repository
> cd [other repo]
> git checkout [your branch]
> git checkout --orphan [new temporary branch]
> git pull [path to original repo] [splitBranch]
# Do git mv here if you want to change the file / directory location
> git checkout [your branch]
> git merge --allow-unrelated-histories [new temporary branch]
> git branch -d [new temporary branch]