Skip to main content
Git is the one tool you use in every project, and knowing it deeply saves you from costly mistakes and speeds up your daily work. This reference covers the decisions engineers face most often: when to merge vs. rebase, how to tag releases, how to collaborate safely on shared branches, and which commands to reach for in common situations. All examples use the command line — the most portable interface across environments.

Merge vs. Rebase

Both git merge and git rebase integrate changes from one branch into another, but they produce different history shapes and require different precautions.

How They Differ

git merge creates a new merge commit that has two parents — the tip of your current branch and the tip of the branch you are merging. The branch history is preserved exactly as it happened. You can see when a feature branch diverged, what happened on main in the meantime, and exactly where the two lines of work came together.
git rebase takes the commits from your branch and replays them one by one on top of the target branch, as if you had started your work from the current tip of that branch. The result is a perfectly linear history — no merge commits, no fork-and-join shape — but the commit SHAs change because the commits are rewritten.

Interactive Rebase

Interactive rebase (-i) lets you rewrite commits on your branch before sharing them — squash trivial “fix typo” commits, reorder commits for logical clarity, or split a large commit into smaller ones.

Pros and Cons

Never rebase commits that you have already pushed to a shared remote branch. When you rebase, you rewrite commit history. Other developers who pulled your original commits will have divergent histories and will face painful conflict resolution. Rebase only commits that exist solely in your local repository or in a personal fork branch that nobody else has based work on.

When to Use Each

  • Use merge for integrating main into a long-lived feature branch when you want an honest record of the merge point, or when merging pull requests on GitHub/GitLab (the PR merge creates a documented integration point).
  • Use rebase to update a local feature branch with the latest main before opening a PR, and to clean up messy commit history (squash fixups) before the PR is reviewed.

Common Workflow

The feature branch workflow is the standard for teams using pull requests:

Commit Message Best Practices

Good commit messages make git log useful for debugging and git bisect effective for tracking regressions. Follow the Conventional Commits format:
Common types: feat (new feature), fix (bug fix), refactor, test, docs, chore (build scripts, dependencies), perf.

Tags

Tags mark specific commits as significant — typically releases. Unlike branches, tags do not move as new commits are added.

Creating Tags

Git supports two tag types: Lightweight tag — just a named pointer to a commit. No metadata.
Annotated tag — a full Git object with tagger name, email, date, and message. Recommended for releases because the metadata is preserved in the repository.

Semantic Versioning

Tag releases following Semantic Versioning: vMAJOR.MINOR.PATCH
  • PATCH (v1.0.1): Backwards-compatible bug fixes.
  • MINOR (v1.1.0): New backwards-compatible features.
  • MAJOR (v2.0.0): Breaking changes.

Tagging a Past Commit

Pushing and Managing Tags

git push does not push tags by default.

Working with Remote Repos

Cloning

For private repositories, use a personal access token (PAT) rather than your account password. Most platforms (GitHub, GitLab, Gitea) support PATs with fine-grained scope control.

Fetch vs. Pull

Dealing with Conflicts

Useful Commands

Cherry-Pick

Apply a specific commit from another branch onto the current branch without merging the entire branch.
Useful when a bug fix on a feature branch needs to go to main immediately without waiting for the full PR.

Stash

Temporarily save uncommitted changes so you can switch branches without committing half-done work.

Reset vs. Revert

Use git revert when undoing commits that are already on a shared branch. Use git reset only on commits that are purely local. git reflog can recover commits deleted by --hard reset, but only for 30 days and only locally.