Merge (m*) β
Merge commands in Hug integrate changes from one branch into another using different strategies suited to different workflows. Hug defaults to squash merging (hug m) for clean, linear history on shared branches, while offering alternatives like standard merges (hug mkeep) and fast-forward-only (hug mff) for specific scenarios. All merge commands are prefixed with m for "merge."
Mnemonic Legend
- Bold letters in command names show the initials that build each command
- Safety icons used below: β safe/preview-only Β· β οΈ destructive/history-rewriting Β· π requires caution or confirmation
On This Page β
Related Commands
See Rebase (r*) for alternative history-rewriting strategies See HEAD Operations (h*) for undoing commits after a merge See Branching (b*) for creating and managing branches before merging See WIP Workflow for parking work safely before merging
Quick Reference β
| Command | Memory Hook | Summary |
|---|---|---|
hug m <branch> | Merge (squash) | Squash-merge branch into current (stages changes, you commit) |
hug mkeep <branch> | Merge Keep commit | Standard merge with merge commit (preserves branch history) |
hug mff <branch> or hug mff <branch> <target> | Merge Fast-Forward only | Fast-forward merge or move branch pointer (fails if not ff) |
hug ma | Merge Abort | Abort merge in progress (escape from conflicts) |
Understanding Merge Strategies β
Before diving into commands, it helps to understand the three strategies:
Original State:
main: A ββ B ββ C
feature: D ββ E
After `hug m feature` (Squash):
main: A ββ B ββ C ββ F (F = squashed D+E, you commit)
After `hug mkeep feature` (Standard):
main: A ββ B ββ C βββββββ
\ M (merge commit)
D ββββββ E βββ/
After `hug mff feature` (Fast-Forward):
main: A ββ B ββ C ββ D ββ E (C must be ancestor of E)Commands β
hug m <branch-name> β
Description: Performs a squash merge, combining all commits from
<branch-name>into a single set of changes and staging them in your current branch. You must then runhug cto create a clean, single commit. This keeps the target branch's history linear and readable.Best for: Feature branches being merged to main/develop where you want clean, atomic commits in the primary branch history.
Example:
shell# On main, merge feature with clean history hug m feature/auth-redesign hug c "Add authentication redesign" # Your commit message becomes the official one # Clean history: main now has a single commit for the whole feature hug l # Shows: "Add authentication redesign" as one commit, not 8 scattered onesSafety: β Safe; you review and commit the squashed changes manually. Original feature branch remains untouched.
When to use:
- Merging feature branches to main/develop
- You want clean, atomic commits in primary history
- The feature branch has many small or WIP commits
- Working in a team with shared main branch
When NOT to use:
- You need to preserve the branch's commit history
- Multiple people are working on the same feature branch (use
hug mkeepinstead) - You want to track when the merge happened (use
hug mkeepinstead)
hug mkeep <branch-name> β
Description: Performs a standard merge with the
--no-ffflag, which always creates an explicit merge commit even if a fast-forward would be possible. This preserves the feature branch's entire commit history and records the merge event in the history.Best for: Team workflows where you want to keep branch history and track merges explicitly.
Example:
shell# On main, merge feature preserving all commits hug mkeep feature/api-refactor # History shows: # - The refactor commits from the feature branch # - A merge commit linking them back to main # - Preserves when/how the feature was integratedSafety: π Requires caution; conflicts may occur if both branches modified the same files. The merge commit creates permanent history.
When to use:
- Team workflows where history is important for auditing
- Multiple people contributed to the branch and should be credited
- You want to explicitly record "when" the merge happened
- Working on shared branches (not squashing)
When NOT to use:
- You want clean, linear history on main
- The branch has many WIP or temporary commits
- You prefer atomic, logical commits in the history
hug mff <branch-name> β
Description: Performs a fast-forward merge only. This simply advances your current branch pointer to match
<branch-name>, creating no merge commit. This only works if your current branch is a direct ancestor of<branch-name>(i.e., no divergence).Best for: Keeping branches aligned without merge commits, or ensuring no unexpected merges happen.
Two-arg form:
hug mff <branch> <target>moves the<branch>pointer to<target>without switching to it. This only works as a fast-forward by default; use--forceto allow arbitrary moves.Examples:
shell# Fast-forward main to feature without switching branches hug mff main feature # Force-move main to a specific tag hug mff main v1.0.0 --force # Preview without executing hug mff main feature --dry-runExample:
shell# Fast-forward works (main is ancestor of feature) hug b feature hug mff main # Fails if main diverged from feature # Safe: knows exactly what happenedβno surprise merge commitsSafety: β Safe and predictable; fails loudly if merge would be needed (preventing surprise merges).
When to use:
- You want the safety of "fail if merge is needed"
- Updating branches in sync (e.g., feature to latest main)
- You explicitly don't want merge commits
- Enforcing a linear, no-merge-commit workflow
When NOT to use:
- Merging diverged branches (use
hug morhug mkeep) - You want to record a merge event
- Merging diverged branches (use
hug ma β
Description: Aborts a merge that's in progress (usually due to conflicts). Returns your working directory and staging area to the state before the merge started. This is your escape route if a merge becomes complicated.
Best for: Getting out of a confusing merge without losing work.
Example:
shell# Merge starts with conflicts hug m feature/complex-branch # β CONFLICT (content): Merge conflict in file.js # Realize this is too complicated right now hug ma # Back to pre-merge state, no changes lost hug sl # Status shows cleanSafety: β Completely safe; restores repo to pre-merge state.
When to use:
- Merge resulted in conflicts you're not ready to resolve
- Want to pause and resolve differently
- Merge would take more effort than expected
Merge Conflicts β
If your merge results in conflicts, Hug will pause and show you which files conflict. You have two options:
Option 1: Resolve conflicts manually
# Edit conflicting files (look for <<<< ==== >>>> markers)
hug s # View conflict status
# ... edit files ...
hug a . # Stage resolved files
git commit # Complete the mergeOption 2: Abort and try a different approach
hug ma # Back out of the merge
hug rb branch-name # Try rebasing instead (rewrites history)
# or
hug h back # Undo commits and try a different merge strategyConflict Prevention
Before merging, check if branches have diverged:
hug lol # See what commits are ahead/behind
hug sl # Check if you have uncommitted changesScenarios β
Merging a Feature to Main (Clean History) β
You completed a feature on a separate branch and want to integrate it into main with a clean commit:
# On feature branch with 8 commits
hug b feature/new-ui
hug l # Shows 8 small, WIP commits
# Switch to main and squash-merge
hug b main
hug m feature/new-ui # Combines all 8 into staged changes
hug c "Add new UI component" # Single clean commit
# Result: main has ONE commit with all the changes
# The 8 original commits are still on feature branch, not in main's history
hug l # Shows clean historyPreserving Feature Branch History (Team Workflow) β
Multiple team members worked on a feature, and you want to preserve everyone's contributions:
# Feature branch has 8 commits from different authors
hug b feature/api-refactor
hug l # Shows: [Alice] Add endpoints [Bob] Fix auth [Carol] Tests
# Merge to main preserving history
hug b main
hug mkeep feature/api-refactor # Creates merge commit, preserves all 8 commits
# Result: main shows all contributions AND the merge event
# Each person's commits are visible in history
hug lEnsuring No Divergence (Safe Update) β
You want to update a feature branch with the latest from main, but ensure it's a simple fast-forward:
# Feature is behind main
hug b feature/hotfix
hug mff main # β Fails: main diverged from feature
# Conflict would require mergeβsafely fails instead
# Safe option: rebase or reword
hug rb main # Rebase feature onto main
# or
hug m main # Squash main into feature (not common)Aborting a Complicated Merge β
A merge resulted in many conflicts, and you decide it's too complex right now:
hug b main
hug m feature/complex # Merge starts...
# β Many conflicts in critical files
# Too complex, abort
hug ma # Back to pre-merge state
# Try again later or with a different approach
hug b feature/complex
# ... fix some issues ...
hug b main
hug m feature/complex # Try merge againTips β
Squash by default: Use
hug mfor most feature merges to keep main clean. Usehug mkeeponly when history matters to your team.Check before merge: Always run
hug lolbefore merging to see what you're about to integrate. Runhug slto ensure your working tree is clean.Preview with
--dry-run: While Hug's merge doesn't have dry-run mode, you can check what would merge by running:shellhug lol <branch-name> # See all commits that would merge git diff --stat HEAD..branch-name # See file changes summaryPrefer squash for linear history: Teams that prefer clean, atomic commits on main use
hug malmost exclusively. Usehug mkeeponly for major milestone merges you want to record as events.Fast-forward as a safety check: Use
hug mffwhen you want to ensure no merge is needed (fail-safe). If it fails, you know divergence happened and can decide how to handle it.Combine with branch deletion: After successful merge, clean up with:
shellhug bdel feature-name # Delete local feature branch # or hug bdelr origin/feature-name # Delete remote feature branchMerge conflicts are normal: If you get conflicts, don't panic. They just mean both branches changed the same parts. Resolve manually or abort with
hug ma.