|
root / skills / mercurial-sync-and-merge
mercurial-sync-and-merge Plain Text 160 lines 4.8 KB
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
---
name: mercurial-sync-and-merge
description: Use when pulling changes from a remote, updating to a different revision, dealing with multiple heads, or resolving merge conflicts in a Mercurial repo.
---

# Mercurial sync and merge

## When this applies

Use when:
- Pulling changes from a remote.
- Updating the working directory to a different revision.
- The repo has multiple heads on the same branch.
- Resolving merge conflicts.

Do not use for:
- Local commit hygiene → see `mercurial-basics`.
- Moving or deleting bookmarks → see `mercurial-bookmarks-and-prs`.
- Amending after a merge → see `mercurial-history-rewriting`.

## Pull then update

```sh
hg pull         # fetch new changesets, do not touch the working dir
hg update       # update working dir to tip of the active branch/bookmark
```

Combined:

```sh
hg pull -u      # pull then update in one step (most common)
```

If a pull brings in changesets that create a new head on the same branch (someone else committed in parallel), `hg update` will move to the new tip *only if* the working dir is at the previous tip. Otherwise it warns about multiple heads.

## Multiple heads

A "head" is a changeset with no children on the same branch. Normal repos have one head per branch. Two parallel commits → two heads.

See them:

```sh
hg heads                       # all heads
hg heads default               # heads on the default branch
```

Resolution options:

1. **Merge them** — combine the two lines:

   ```sh
   hg update -r <head A>
   hg merge <head B>
   # resolve any conflicts (see below)
   hg commit -m "merge: combine parallel work"
   ```

2. **Rebase your work onto the other head** (preferred for personal feature work):

   ```sh
   # If your work is the new head and the other is upstream:
   hg update -r <upstream head>
   # then for each of your local commits, replay using rebase or amend
   ```

   Note: vanilla Mercurial without the `rebase` extension can't `hg rebase` directly. Either enable `rebase` in `~/.hgrc` (`[extensions] rebase = `) or fall back to merge.

For Isurus today: merge is the safe default; rebase is not part of the v1 workflow.

## Merging two heads

```sh
hg update -r <target>                              # check out the changeset to merge INTO
hg merge -r <source> --tool internal:merge        # bring source into the working dir
# files with conflicts are listed in the output
```

**Always pass `--tool internal:merge`** when running `hg merge` from a Claude Code session. The user's `~/.hgrc` may default to `vimdiff`, `kdiff3`, or another interactive tool, none of which work in a non-TTY context — the merge will hang or error. `internal:merge` writes conflict markers (`<<<<<<<` / `=======` / `>>>>>>>`) into the file and returns control immediately, which is exactly what the resolution flow below assumes.

## Conflict resolution

After `hg merge`, files in conflict are marked. Inspect them:

```sh
hg resolve --list              # 'U' = unresolved, 'R' = resolved
```

Edit each unresolved file. Conflict markers look like:

```
<<<<<<< local
your version
=======
their version
>>>>>>> other
```

Remove the markers, keep the correct content, save. Then mark resolved:

```sh
hg resolve --mark path/to/file
```

Or after editing all of them:

```sh
hg resolve --mark --all
```

Verify nothing remains:

```sh
hg resolve --list              # should print nothing
```

Re-run a merge tool on a specific file (e.g., to retry):

```sh
hg resolve --tool internal:merge3 path/to/file
```

### Shortcuts when one side wins

If the user explicitly picks one side ("keep ours", "take theirs") rather than wanting a hand-merge, use the appropriate `internal:` resolver — it both resolves and marks in one step, no manual editing needed:

```sh
hg resolve --tool internal:local path/to/file     # keep working-dir version
hg resolve --tool internal:other path/to/file     # take incoming version
```

Then verify with `hg resolve --list` and proceed to commit.

Once all files are resolved:

```sh
hg commit -m "merge: combine X and Y"
```

A merge commit has two parents. `hg log --graph` (or `hg log -G`) shows the merge visually.

## Aborting a merge

If you started a merge and want to back out:

```sh
hg update -C -r <pre-merge revision>
```

`-C` means clean — discard the in-progress merge state. Verify the working dir is clean afterward with `hg status`.

## Common pitfalls

- **`hg pull` without `-u`:** changesets are in the repo but the working dir is unchanged. You're working against stale code without realizing.
- **Two parents after merge with no commit:** if you `hg merge` and then run other commands, the working dir has two parents until you `hg commit`. Until then, `hg parents` shows both.
- **Conflict markers committed:** if you `hg commit` without removing all `<<<<<<<`/`=======`/`>>>>>>>` markers, you commit broken files. Always grep before commit:

  ```sh
  grep -r '<<<<<<<' .
  ```