Git as a version control software manages your code changes.

Github / Gitlab are hosting & collaborating platforms.

Concepts

General

Read Git-Fu Basics: White Belt for a quick introduction into git.

Above article covered:

    ┌─────────┐     ┌───────┐     ┌──────────┐     ┌──────────┐
    │Working  │     │Staging│     │Local     │     │Remote    │
    │directory│     │area   │     │repository│     │repository│
    └────┬────┘     └────┬──┘     └─────┬────┘     └─────┬────┘
         │               │              │                │
     add │──────────────►│              │                │
         │               │              │                │
  commit │               ├─────────────►│                │
         │               │              │                │
    push │               │              ├───────────────►│
         │               │              │                │
    pull │               │              │◄───────────────┤
         │               │              │                │
 restore │◄──────────────┤              │                │
         │               │              │                │
  revert │◄─────────────────────────────┤                │

Merge

Output produced by git log --all --oneline --graph

Two diverging branches: main and day-2

* 3acf970 (HEAD -> main, origin/main, origin/HEAD) reformulate additional notes
* ed8a33f add documentation about git
| * a7c27b9 (origin/day-2, day-2) docs: add link to pycharm integration of ruff
| * 2a3c318 add ruff as linter and formatter
|/
* a1195fa initial commit

Merge of the two branches (git merge day-2) creates a new commit. Merge commits are special commits pointing to multiple previous commits.

*   628f615 (HEAD -> main) Merge branch 'day-2'
|\
| * a7c27b9 (origin/day-2, day-2) docs: add link to pycharm integration of ruff
| * 2a3c318 add ruff as linter and formatter
* | 3acf970 (origin/main, origin/HEAD) reformulate additional notes
* | ed8a33f add documentation about git
|/
* a1195fa initial commit

Merge conflicts

[https://swcarpentry.github.io/git-novice/09-conflict.html](How to resolve merge conflicts?)

Cheatsheet (CLI)

General workflow

# Where am I?
git status

# Pull changes from remote (GitLab)
git pull

# Create new branch and switch to it
git switch --create branchname

# Add modified files from working tree to staging area
git add filename
git add -p filename

# Remove and move
git rm filename
git mv bug.c feature.c

# What changed? -> GUI might be more helpful
git diff
git diff origin/main

# Commit files from staging area
git commit
# Add and commit in one command
git commit -am "fixup"

# Push commited changes to remote (GitLab)
git push
git push --force-with-lease --force-if-includes

# Show history! -> GUI might be more helpful
git log
git log --graph --oneline --decorate --all

# Switch back to main
git switch main

Undo changes

# Remove from staging area
git restore --staged filename

# Undo last local commit:
git reset c5f567 filename
## --soft to keep changes
git reset --soft HEAD~
## --hard to throw away changes
git reset --hard HEAD~
## Hard reset all files to main
git reset --hard origin/main

# Undo last remote commit.
## create a new commit wich undoes previous one
git revert HEAD~

Rewrite or Change History

# Split an existing Git commit
git rebase -i <hash-of-previous-commit>
## Edit the commit you want to split (change pick to edit)
## Save and exit (:wq)
git reset HEAD~
git add [files-to-add]
git commit
git rebase --continue

# Rebase onto first commit
git rebase -i --root main

# Change author
## Last commit
git commit --amend --author="John Doe <john@doe.org>" --no-edit
## Every commit:
git rebase -i --root main -x "git commit --amend --reset-author -CHEAD"

# Sign every past commits of branch
git rebase --exec 'git commit --amend --no-edit -n -S' -i commit-hash

# Remove a file from history
git filter-repo --invert-paths --path <path to the file or directory>
## Or
git filter-branch --index-filter 'git rm -rf --cached --ignore-unmatch path_to_file' HEAD

Time Travel

# Show/view a file at a specific commit
git show REVISION:path/to/file
git show REVISION:path/to/file > file.copy

# Log/commits since last tag/release
git log tag..HEAD

Branches

# Deleting local branches in Git
git branch -d feature/login
# Deleting remote branches in Git
git push origin --delete feature/login

# Deleting gone branches
# https://www.erikschierboom.com/2020/02/17/cleaning-up-local-git-branches-deleted-on-a-remote/
## Identifying the gone branches
git for-each-ref --format '%(refname:short) %(upstream:track)' |
  awk '$2 == "[gone]" {print $1}'
## Deleting the gone branches
git for-each-ref --format '%(refname:short) %(upstream:track)' |
  awk '$2 == "[gone]" {print $1}' |
  xargs -r git branch -D

Misc

# List file sizes:
git rev-list --objects --all |
git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' |
sed -n 's/^blob //p' |
sort --numeric-sort --key=2 |
cut -c 1-12,41- |
$(command -v gnumfmt || echo numfmt) --field=2 --to=iec-i --suffix=B --padding=7 --round=nearest

# List commit sizes
for i in $(git log --pretty='%h'  master..HEAD); do git-commit-size $i && git show --no-patch --oneline $i; done | sed 'N;s/\n/\t\t/'

# Statistics (stats)
git diff --stat tag1 tag2