Blog
Mert Özen's blog posts on software development, backend, frontend, and DevOps.
Git Interactive Rebase and Squash: Tidying History Before a PR
We turn a messy feature branch into three clean commits with git rebase -i: the todo list, pick, reword, edit, squash, fixup, drop and reordering, the commit --fixup plus --autosquash flow, how it differs from GitHub's squash merge, and the experimental git history reword in Git 2.54.
Git rebase: Rewriting History and Pushing It Safely
We compare merge and rebase in the same scenario: why rebase rewrites commits with new hashes, conflicts during a rebase and the flipped HEAD, pull --rebase, the golden rule, pushing a rebased branch with --force-with-lease and --force-if-includes, and --update-refs for stacked branches.
Git cherry-pick: Moving a Single Commit to Another Branch
We carry a hotfix from main to a release branch with git cherry-pick: why the new commit gets a new hash, author versus committer, leaving a trail with -x, picking a range of commits, --continue/--abort/--skip during a conflict, finding equivalent commits with git cherry and when cherry-pick becomes a smell.
Git Stash: Setting Unfinished Work Aside
Saving unfinished work with git stash: -u for untracked files, named entries, list and show, apply versus pop, --staged and --index, the stash.index setting, conflicts during a pop, stash branch and the stash export/import commands from Git 2.51.
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.