= git == general, basic information stage = index = cache HEAD … activated branch Head … latest commit of a branch a ref file points to a commit file a commit file lists tree objects each tree object is the digest of a BLOB file git add … filesystem → stage git commit … stage → git repo git commit -a … filesystem → stage git checkout … git repo → filesystem git reset … remove file from stage without touching file on filesystem git restore … restore state of file at latest commit (since Git 2.23) git revert … creates a new commit which undoes the changes of the provided commit --git-dir … defaults to “.git” as folder name for git internal information --work-tree … defaults to the folder where “git init” or “git clone” was run man git-for-each-ref … documents formatting syntax git config --global init.defaultBranch main … set default branch to 'main' git config --local status.showUntrackedFiles no … skip listing untracked files git update-index --assume-unchanged FILEPATH … now file at FILEPATH behaves as if it were ignored == basic commands VERSION … ~ (information based on commit objects) … HEAD, HEAD~, HEAD~2, HEAD~3 … goes back in history; HEAD can also be a tag/branch name … ^ (information based on tree parents) … HEAD^ first parent of HEAD … HEAD^2 second parent of HEAD … @ (information based on reflog) … HEAD@{4} … is four local actions before the last commit (referring to reflog) … main@{3 weeks ago} … refers to the first commit in branch develop which is older than 3 weeks … @^2 … refers to the second parent of the merge commit … tag name … branch name git show VERSION:FILEPATH … show file at FILEPATH in a committed VERSION git diff OLDVERSION NEWVERSION -- FILEPATH … compare a file at FILEPATH in two different versions git checkout VERSION -- FILEPATH … copy file at FILEPATH from VERSION to HEAD git log VERSION1..VERSION2 … show all commits starting at common base between VERSION1 and VERSION2 and ending at VERSION2 git log VERSION1...VERSION2 … show all commits that are in the history of VERSION1 and VERSION2 git log --simplify-by-decoration --pretty='format:%ai %d' … show only commits with tags, branch-name, etc. git reflog … show the reflog (changes concerning modification of HEAD; empty after a clone; might be incomplete due to storage reasons) git reflog --all … show the reflog with reflog information from all references git blame -L 28,43 FILEPATH … line-ranged blame for lines 28 to 43 for file at FILEPATH git blame -C -C -C … try harder to understand code movements across files git diff --word-diff … show difference between words, not lines git config --global branch.sort -committerdate … set ‘sort branches by committerdate’ git config --list --show-origin … list configuration settings and their origin git rev-list VERSION1..VERSION2 --count … count number of commits between VERSION1 and VERSION2 == .git file structure ./.git ./.git/branches ./.git/hooks ./.git/hooks/applypatch-msg.sample ./.git/hooks/commit-msg.sample ./.git/hooks/fsmonitor-watchman.sample ./.git/hooks/post-update.sample ./.git/hooks/pre-applypatch.sample ./.git/hooks/pre-commit.sample ./.git/hooks/pre-merge-commit.sample ./.git/hooks/pre-push.sample ./.git/hooks/pre-rebase.sample ./.git/hooks/pre-receive.sample ./.git/hooks/prepare-commit-msg.sample ./.git/hooks/push-to-checkout.sample ./.git/hooks/sendemail-validate.sample ./.git/hooks/update.sample ./.git/info ./.git/info/exclude ./.git/description ./.git/config ./.git/refs ./.git/refs/heads ./.git/refs/tags ./.git/HEAD ./.git/objects ./.git/objects/pack ./.git/objects/info .git/config … repo-specific .gitconfig file .git/description … short, human-readable description of project .git/HEAD … e.g. “ref: refs/head/main”, refers to current active branch .git/info/exclude … repo-specific .gitignore file .git/index … stores “stage” .git/logs … contains commit information, essentially the basis of reflog .git/objects … contains {commit, BLOB, tree, tag} objects .git/refs … contains references to commits (or the file .git/packed-refs) if a merge conflict is given, the following files exist: .git/MERGE_HEAD .git/MERGE_MODE .git/MERGE_MSG .git/ORIG_HEAD == read git-internal files git show-ref … lists hash stored in .git/refs/* files and their name (hence branches and tags with their hash digest) git cat-file -t … print type of the object file associated with this digest git cat-file … print content of object file associated with this digest git cat-file -p … print content of object file associated with this digest == maintaining the .git directory SHA-1 used to be standard. Since Git 2.29, SHA256 is standard: git init --object-format=sha256 git gc … run garbage collection git hash-object FILEPATH … compute hash code of file at FILEPATH git ls-tree … show content of a tree object git rev-list … “git log” with hashcodes only git rev-parse HEAD~ … resolves “HEAD~” and shows the corresponding hash code == notes per action === related to merging git rebase A B → conflict ⇒ conflict tag shows data A first, data of B second git rebase A B → no conflict ⇒ B is put on top of A git mergetool --tool meld … start external program “meld” to resolve merge conflict types: • fast-forward • octopus • resolve • recursive • subtree recommendable settings for the [merge] section in .gitconfig: # if true, git generates a normalized text file representation e.g. considering normalized line endings before considering it as rename renormalize = true # the number of files to consider when performing rename detection during a merge renameLimit = 0 # if set to false ignores "renameLimit", equals "git diff --no-renames" renames = false === related to pull types (since 2.27, a type is required; shows a warning otherwise): • git pull --ff-only … fast-forward or throw error • git pull --no-rebase … fast-forward or merge • git pull --rebase … rebase Alternatively, you can set it in a config file (optionally add --global): • git config pull.ff only … fast-forward or throw error • git config pull.rebase false … fast-forward or merge • git config pull.rebase true … rebase Furthermore: git config branch.autosetuprebase always … set --rebase for every new tracking branch, also: never|local|remote git config branch.BRANCHNAME.rebase true … overwrite pull.rebase for a specific branch === related to branches A branch is a file in .git/refs/head use "git switch -c NEWBRANCH" instead of "git checkout -b NEWBRANCH" … since Git 2.23 git branch --merged … list branches which have already been merged with current one git branch --no-merged … list branches which have not yet been merged with current one git merge-file … for merging a single file === related to rebase git rebase --onto BRANCH1 BRANCH2 … use BRANCH2 as base instead of BRANCH git merge --squash BRANCH && git commit … squash all commits of BRANCH into a single commit and put it on the current branc Fetch upstream changes manually (“git pull --rebase …”): 1. git fetch REMOTE 2. git rebase −p origin/MYBRANCH == related to committing git commit --amend … amend the previous commit message git commit --amend --no-edit … amend the previous commit (run “git add” for the change before) git add -p FILEPATH … only add selected segments of a file at FILEPATH git restore -s VERSION FILE … overwrite file in working directory with version at VERSION git revert VERSION1 VERSION2 … … allows to create a revert commit for multiple commits/changes == related to stashing stashes are stored in the file .git/refs/stash (contains references to commit objects) git stash … move local changes into stash commit git stash list … list stack of stash commits git stash show -p stack@{n} … show the changes in the n-th stash commit === related to tagging git tag -l --format='%(committerdate) %09 %(refname)' === related to listing git config --global core.pager 'less --raw-control-chars' … use “less --raw-control-chars” as paging application (e.g. git show) git log --follow -- FILEPATH … show changes of file at FILEPATH including files at different filepath if they have been renamed to FILEPATH git log --graph --oneline --all … pretty neat representation: {visualizes branch graph, summarize metadata and commit message in one line, show commits of other branches} git blame --color-by-age … annotate authorship to code and color represents age git ls-tree --name-only -r COMMIT … list all files of a commit git diff-tree --no-commit-id --name-only -r COMMIT … list changed files of a commit git log --pretty=format:"%C(yellow)%h %ad%Cred%d %Creset%s%Cblue [%cn]" --decorate --date=short | grep "first-line-of-commit-message" how to determine when a git commit ended up on the main branch? … not really possible, but you can list commits of a branch and then filter for it. Adjacent git commits tell you the context. git log --author="$AUTHORNAME" --pretty=format:"%C(yellow)%h %ad%Cred%d %Creset%s%Cblue [%cn]" --decorate --date=short BRANCH … show all [accumulated] changes of one author on a branch --decorate … show tags as well --name-only … list names of modified files only --name-status … show change type per modification (e.g. M := modified) --pretty=online|short|medium|full|fuller|… … specific representation for metadata & commit message --numstat … list number of modified lines per file --stat … list types of changes per file as bar diagram --author --since DATE == --after DATE --until DATE == --before DATE … where DATE is in ISO 8601 --walk-reflogs … information of “git reflog” with details aligned with “git log --walk-reflogs” === related to searching git grep PATTERN … search for PATTERN in all objects git grep --count PATTERN … search for PATTERN but only show count per matching file; not matches themselves === related to aliasing git config --global alias.whatever 'log --oneline --stat' … defines an alias globally git config --get-regexp alias … lists all aliases === related to statistics git shortlog … lists commits per author git shortlog --summary --numbered --email --no-merges --since 2024-01-01 … a different representation to represent how many commits per author were created git diff --shortstat VERSION1..VERSION2 … list how many files are changed/created/deleted between two versions === related to submodules git submodule add REPOURL FOLDERPATH … add a submodule git submodule status … list current status git clone --recurse-submodules … … clone submodules as well git submodule update --init --recursive … clone submodules if it was skipped at during clone/checkout === related to subtrees git subtree add --prefix=FOLDERPATH REPOURL VERSION --squash … add subtree, squash merged all commits into a single one … does not create .git folder in FOLDERPATH, information is stored as “git-subtree-dir” and “git-subtree-split” in commit messages git subtree pull --prefix=FOLDERPATH REPOURL VERSION --squash … pull latest changes git subtree split --prefix=FOLDERPATH -b BRANCHNAME … split folder FOLDERPATH of existing repository into a separate tree only existing in branch BRANCHNAME … “git fetch REPOPATH BRANCHNAME && git checkout -b main FETCH_HEAD” required to git only this subtree in a different repository == git inconsistencies • Referring to a file at a specific version sometimes happens with "VERSION:FILEPATH" and sometimes the version is provided as CLI argument • merge: “ours” is the local/current version, “theirs” is the imported version rebase: “ours” is the imported version, “ours” is the local/current version == web interfaces • Azure DevOps • Bitbucket • Forgejo https://forgejo.org/ • Gitea https://gitea.io/en-us/ • GitHub • GitLab • Gitolite • Gogs https://github.com/gogits/gogs == snippets === pull a PR from github git fetch origin pull/PULLREQID/head:LOCALBRANCHNAME === show whitespace in diff git diff --ws-error-highlight=all === Rewriting git history with different author & committer in bash AUTHOR="meisterluk" EMAIL="admin@lukas-prokop.at" git filter-branch -f --env-filter ' export GIT_AUTHOR_NAME="'$AUTHOR'"; export GIT_AUTHOR_EMAIL="'$EMAIL'"; export GIT_COMMITTER_NAME="'$AUTHOR'"; export GIT_COMMITTER_EMAIL="'$EMAIL'";' HEAD; === reset file permissions (e.g. if a FAT filesystem lost them) git diff -p -R --no-color | grep -E "^(diff|(old|new) mode)" --color=never | git apply === Remove all files unknown to git in this repository for f in $(git ls-files --others); do echo "Removing $f …" && rm "$f"; done; == URLs github's git cheatsheet:: https://education.github.com/git-cheat-sheet-education.pdf dealing with common emergencies:: https://ohshitgit.com/ “Oh shit, Git!?!” ”A successful git branching model” git-flow article by Vincent Driessen (2010):: https://nvie.com/posts/a-successful-git-branching-model/ submodule vs. subtree:: https://training.github.com/downloads/submodule-vs-subtree-cheat-sheet/ git tools:: https://git.wiki.kernel.org/index.php/InterfacesFrontendsAndTools#git-subtree_.28contrib.29 git for large binary files:: https://git-lfs.com/ rewrite git repo history (filter-branch replacement):: git-filter-repo https://github.com/newren/git-filter-repo R git operations interface:: githug https://github.com/jennybc/githug early git presentation at Google Tech Talk by Linus Torvalds:: https://www.youtube.com/watch?v=4XpnKHJAok8