Blog
Mert Özen's blog posts on software development, backend, frontend, and DevOps.
Undoing Changes in Git, Part 2: git revert
Safe undo in shared history: the inverse commit of git revert, choosing between reset and revert, reverting a merge commit with -m 1, reverting the revert before merging a branch again, several commits with --no-commit and conflicts during a revert.
Undoing Changes in Git, Part 1: git restore and git reset
Undoing files in the working tree and index with git restore and bringing them back from history with --source; what the --soft, --mixed and --hard modes of git reset do to HEAD, the index and the working tree, getting back with ORIG_HEAD, and the old checkout/reset forms.
Teamwork with Git: Branching Strategies, Rulesets and Conventional Commits
Starting from a force push that wipes a teammate's commit, we compare GitHub flow, Git flow and trunk-based development; branch protection versus rulesets, server-side protection with receive.denyNonFastForwards, CODEOWNERS and Conventional Commits.
Pull Requests on GitHub: GitHub Flow, Reviews and Merge Methods
Branch, commit, push and pull request: the six steps of GitHub flow, draft PRs, answering review with new pushes, how the merge commit, squash and rebase methods shape history, the branch-deletion trap after a squash, and keeping a fork in sync with upstream.
Connecting to GitHub: HTTPS, Personal Access Tokens and SSH
From creating a repo on GitHub to the first push: why passwords stopped working in 2021, fine-grained versus classic personal access tokens, how credential helpers work, ed25519 SSH keys, gh auth login and transfer.credentialsInUrl, which catches tokens embedded in URLs.
Understanding Git Pull: fetch, merge, rebase and Divergent Branches
We see with real output that git pull is fetch plus merge or rebase, the "divergent branches" error on diverged branches since Git 2.33.1, the --no-rebase, --rebase and --ff-only options, the choice between pull.rebase and pull.ff, pull.autostash from Git 2.51 and fetch --prune.
Git Remote and Clone: origin, fetch, push and Upstream
We see with real output what a remote is, git remote add, push -u and the upstream setting with a local bare repo standing in for GitHub, remote-tracking branches like origin/main, what git clone does, the split between fetch and merge, sharing a new branch, git remote show/rename and a rejected push.
Resolving Git Conflicts: Markers, merge --abort and zdiff3
We see with real output why conflicts happen, how to read the markers, how to inspect the state with git status, git log --merge and git ls-files -u, resolving step by step, git merge --abort, merge.conflictStyle zdiff3, --ours/--theirs, mergetool and rerere, with a short note on git add --resolved in Git 2.56.
Git Merge: Fast-forward, Three-way Merge and the Merge Commit
We see with real output the difference between fast-forward and three-way merge, the role of the common ancestor (git merge-base), the inside of a two-parent merge commit, the --no-ff and --ff-only options, the ort strategy that has been the default since Git 2.34, and cleaning up branches after a merge.
Git Branch: A Movable Pointer, HEAD and git switch
We see with real output that a branch is a 41-byte file holding a single commit hash, how HEAD works, listing, renaming and deleting with git branch, moving around with git switch and switch -c, getting into and out of detached HEAD, and the old use of git checkout.
Comparing Changes with Git diff
We see with real output which comparison git diff makes between the working tree, the index and HEAD, how to read diff output, summary views like --stat, --name-only and --word-diff, diffs between commits, and the difference between two dots and three dots (--merge-base).
Looking at Git History: git log, git show, git blame and Aliases
We move around history with git log's --oneline, --graph, --stat, -p, --format, --author, --since, --grep and --follow options and see the difference between -S and -G on a line whose price changed. We inspect a single commit and an old file version with git show, trace lines with git blame -L and shorten long commands with aliases.