> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pebchip.top/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Git Workflow Reference: Merge, Rebase, and Best Practices

> Practical Git reference covering merge vs rebase strategies, tagging releases, cloning private repos, and common workflow patterns for teams.

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.

```bash theme={null}
# Switch to the branch you want to merge INTO
git checkout main

# Merge the feature branch
git merge feature/my-feature

# The result: a new merge commit with two parents
```

**`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.

```bash theme={null}
# Rebase your feature branch onto the current main
git checkout feature/my-feature
git rebase main

# Then fast-forward merge (no merge commit needed)
git checkout main
git merge feature/my-feature
```

### 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.

```bash theme={null}
# Rebase the last 3 commits interactively
git rebase -i HEAD~3

# In the editor, change 'pick' to:
# 'squash' (s) - combine with previous commit
# 'reword' (r) - edit the commit message
# 'drop' (d) - remove the commit entirely
```

### Pros and Cons

| Property                | Merge                                             | Rebase                                                          |
| ----------------------- | ------------------------------------------------- | --------------------------------------------------------------- |
| Preserves history       | Yes — exact record of when branches diverged      | No — rewrites commit SHAs                                       |
| Linear history          | No — merge commits create a graph                 | Yes — clean, straight line                                      |
| Safe on shared branches | Yes                                               | **No** — never rebase commits already pushed to a shared branch |
| Conflict handling       | Resolve once in the merge commit                  | Resolve once per replayed commit                                |
| Best for                | Long-lived shared branches, clear release history | Feature branches before opening a PR, local cleanup             |

<Warning>
  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.
</Warning>

### 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:

```bash theme={null}
# 1. Always start from an up-to-date main
git checkout main
git pull

# 2. Create a descriptive feature branch
git checkout -b feature/add-flight-status-endpoint

# 3. Make changes and commit frequently
git add .
git commit -m "feat: add flight status endpoint with IATA code validation"

# 4. Stay current with main by rebasing (local only)
git fetch origin
git rebase origin/main

# 5. Push and open a pull request
git push -u origin feature/add-flight-status-endpoint
```

### 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:

```
<type>(<scope>): <short summary>

<optional body explaining WHY, not what>

<optional footer: BREAKING CHANGE, closes #123>
```

Common types: `feat` (new feature), `fix` (bug fix), `refactor`, `test`, `docs`, `chore` (build scripts, dependencies), `perf`.

```bash theme={null}
# Good examples
git commit -m "feat(api): add rate limiting middleware using token bucket algorithm"
git commit -m "fix(db): handle nil pointer when flight record has no departure time"
git commit -m "perf(cache): prefetch top 100 routes on startup to reduce cold-start latency"

# Bad examples (avoid)
git commit -m "fix stuff"
git commit -m "wip"
git commit -m "changes"
```

## 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.

```bash theme={null}
git tag v1.0-lw
```

**Annotated tag** — a full Git object with tagger name, email, date, and message. Recommended for releases because the metadata is preserved in the repository.

```bash theme={null}
git tag -a v1.0 -m "Release v1.0: initial production deployment"
```

### Semantic Versioning

Tag releases following [Semantic Versioning](https://semver.org/): `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

```bash theme={null}
# View commit history
git log --pretty=oneline

# a4c3f21 (HEAD -> main) feat: add webhook support
# 8b2d109 fix: correct timezone handling in departure times
# 3f9a0e2 feat: initial flight status endpoint

# Tag an earlier commit
git tag -a v0.9.0 8b2d109 -m "Pre-release: fix timezone bug"
```

### Pushing and Managing Tags

`git push` does not push tags by default.

```bash theme={null}
# Push a single tag
git push origin v1.0

# Push all local tags not yet on remote
git push origin --tags

# List all tags (optionally filtered)
git tag
git tag -l "v1.*"

# View tag details
git show v1.0

# Delete a local tag
git tag -d v1.0-lw

# Delete a remote tag
git push origin --delete v1.0-lw
# Or equivalently:
git push origin :refs/tags/v1.0-lw
```

## Working with Remote Repos

### Cloning

```bash theme={null}
# Clone a public repository
git clone https://github.com/flightaware/piaware.git

# Clone a private repository (prompted for username and password/token)
git clone https://git.example.com/org/private-repo.git
# Username for 'https://git.example.com': your-username
# Password for '...': your-personal-access-token
```

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

```bash theme={null}
# git fetch: download remote changes but do NOT merge them
# Safe to run any time — does not touch your working tree
git fetch origin

# See what changed
git log HEAD..origin/main --oneline

# git pull: fetch + merge (or fetch + rebase if configured)
git pull
# Equivalent to: git fetch && git merge origin/main

# Pull with rebase instead of merge (preferred by many teams)
git pull --rebase
# Or set as default:
git config --global pull.rebase true
```

### Dealing with Conflicts

```bash theme={null}
# After a merge or rebase hits a conflict:

# 1. See which files have conflicts
git status

# 2. Open each conflicted file, resolve the conflict markers:
#    <<<<<<< HEAD
#    your version
#    =======
#    their version
#    >>>>>>> feature/other-branch

# 3. Stage the resolved files
git add path/to/resolved-file.go

# 4. Continue the merge or rebase
git merge --continue
# or
git rebase --continue

# To abort and return to the pre-conflict state:
git merge --abort
git rebase --abort
```

## Useful Commands

### Cherry-Pick

Apply a specific commit from another branch onto the current branch without merging the entire branch.

```bash theme={null}
# Apply commit abc1234 to the current branch
git cherry-pick abc1234

# Cherry-pick a range of commits
git cherry-pick abc1234^..def5678
```

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.

```bash theme={null}
# Save current changes to the stash
git stash

# List all stashes
git stash list
# stash@{0}: WIP on feature/xyz: a4c3f21 feat: add webhook support

# Restore the most recent stash
git stash pop

# Apply a specific stash without removing it from the list
git stash apply stash@{1}

# Stash with a descriptive message
git stash push -m "half-done rate limiter refactor"
```

### Reset vs. Revert

| Command                    | What It Does                                                         | Rewrites History? | Safe on Shared Branches? |
| -------------------------- | -------------------------------------------------------------------- | ----------------- | ------------------------ |
| `git reset --soft HEAD~1`  | Move branch pointer back one commit; changes go back to staging area | Yes               | No                       |
| `git reset --mixed HEAD~1` | Move branch pointer back; changes go to working directory (unstaged) | Yes               | No                       |
| `git reset --hard HEAD~1`  | Move branch pointer back; **discard changes entirely**               | Yes               | No                       |
| `git revert <commit>`      | Create a new commit that undoes the specified commit                 | No                | Yes                      |

```bash theme={null}
# Undo the last commit but keep the changes staged
git reset --soft HEAD~1

# Undo the last commit and unstage changes (working directory intact)
git reset --mixed HEAD~1

# Permanently discard the last commit and all its changes
# WARNING: unrecoverable without reflog
git reset --hard HEAD~1

# Safely undo a commit that is already on main (creates a new commit)
git revert a4c3f21
```

<Note>
  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.
</Note>
