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:
- A git repository is a chain of commits.
- A commit is recorded changes to a file, a message, a link to the parent commit and a hash
- Branches (names pointing to certain commits)
- Branch names such as
main
andday-2
- The current branch
HEAD
- Branch names such as
origin
is the default name for a remote repository (e.g. GitHub)- File states
- modified: Changed but not committed
- staged: Marked to go into next commit
- commited: Stored in local Git repository
- Two modes of interaction:
- CLI (Commandline interface) through your terminal.
- GUI (Graphical user interface) through your editor (Pycharm).
┌─────────┐ ┌───────┐ ┌──────────┐ ┌──────────┐
│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