- Hide menu

Merging an Empty HFS Partition Into Active Data on macOS 10.8.5 Mountain Lion With CoreStorage


Merging an Empty HFS Partition Into Active Data on macOS 10.8.5 Mountain Lion With CoreStorage

Reclaiming space stuck on the wrong side of the partition table, with an undocumented diskutil command

ℹ  TL;DR: If you have a Mac disk with an empty partition sitting before a partition full of data, standard diskutil resizeVolume / mergePartitions can’t merge them — filesystem resize only grows forward into trailing free space, never backward. CoreStorage sidesteps this because it pools partitions logically instead of growing them in place. The undocumented diskutil coreStorage addDisk command works for this on 10.8.5 — but resizeVolume‘s “fill everything” shortcut (0) does not work on this OS version — you have to pass an explicit byte count. Full working sequence and output below.
Show more ▾

The Problem

The setup: a disk with two partitions —

diskutil list
2: Apple_HFS Untitled 1   90.8 GB   disk1s2
3: Apple_HFS Untitled 2   658.8 GB  disk1s3

disk1s2 (90.8GB) was empty. disk1s3 (658.8GB) held all the active data. The goal: reclaim the 90.8GB and end up with one combined ~750GB volume, without wiping or cloning the data partition.

The obvious approach — delete the empty partition, then grow the data partition into the freed space — doesn’t work here, and it’s worth understanding why, because the failure isn’t a bug, it’s how partition resizing is fundamentally designed to work.


Why You Can’t Just Delete-and-Expand

diskutil resizeVolume and diskutil mergePartitions both grow a partition by extending its trailing edge — moving the boundary that follows the partition further out on the disk, into space that comes after it. Neither can move a partition’s starting position. Doing that would mean physically relocating every block of an existing filesystem to a new starting offset on disk — not a metadata edit, but a full block-level move — and that’s simply not what these tools do.

That’s exactly the situation here: the empty space (90.8GB) sits before the data partition, not after it. Deleting the empty partition just leaves dead space that the data partition has no native way to absorb. This is a well-documented limitation reported independently by multiple users hitting the same “partitions in the wrong order” wall — see the Ask Different thread on this exact problem.

mergePartitions doesn’t get around this either: its own man page says whichever partition you list first keeps its data and gets grown — but “grown” still means grown forward. If the partition with your data is physically the second one, this hits the same wall dressed up in a different command.


Why CoreStorage Works Around It

CoreStorage is Apple’s logical volume manager (it’s what powers Fusion Drive and FileVault 2 under the hood). Instead of a single filesystem occupying one contiguous span of a disk, a CoreStorage Logical Volume Group (LVG) pools one or more Physical Volumes (PVs) — which can be any partitions, anywhere on the disk — into one logical address space. A Logical Volume (LV) inside that group is addressed logically, not by physical position. Because of that, two partitions can be pooled together into one usable volume regardless of which one is physically first on the disk.

This is why the fix here isn’t a resize at all — it’s converting the data partition into a CoreStorage volume, then adding the empty partition into the same pool.


The Commands (With Real Output)

Starting layout:

diskutil list
/dev/disk1
 1: EFI 209.7 MB disk1s1
 2: Apple_HFS Untitled 1 90.8 GB disk1s2
 3: Apple_HFS Untitled 2 658.8 GB disk1s3
Step 1

Convert the data partition to CoreStorage, in place

bash
$ diskutil coreStorage convert disk1s3
Started CoreStorage operation on disk1s3 Untitled 2
Resizing disk to fit Core Storage headers
Creating Core Storage Logical Volume Group
Attempting to unmount disk1s3
Switching disk1s3 to Core Storage
Waiting for Logical Volume to appear
Mounting Logical Volume
Core Storage LVG UUID: CE67A415-F191-46A9-9605-473504EDEF92
Core Storage PV UUID: 0FCE0B6A-44D2-460C-B2B5-7F835A7653E7
Core Storage LV UUID: 94DBC0B5-3101-45B9-9FDB-242285F3E9E2
Core Storage disk: disk2
Finished CoreStorage operation on disk1s3 Untitled 2

Data is preserved — this is a live, in-place conversion, not a wipe. disk1s3 becomes a CoreStorage Physical Volume, wrapped in a new Logical Volume Group, with the original filesystem now exposed as a Logical Volume at disk2.

Step 2

Add the empty partition into the same LVG

bash
$ diskutil coreStorage addDisk CE67A415-F191-46A9-9605-473504EDEF92 disk1s2
Started CoreStorage operation on disk1s2 Untitled 1
Unmounting disk1s2
Touching partition type on disk1s2
Adding disk1s2 to Logical Volume Group
Switching disk1s2 to Core Storage
Waiting for Logical Volume Group to come back online
Core Storage PV UUID: 8BBA11A2-93F3-4C87-93E5-CFC111E2A938
Finished CoreStorage operation on disk1s2 Untitled 1
⚠  addDisk is undocumented — it doesn’t appear in Apple’s diskutil man page and isn’t officially supported. Reports of its reliability across different 10.8.x point releases are genuinely mixed — broken on 10.8.2, reportedly fixed on 10.8.3, then reported broken again by other users afterward. Test on a disposable disk before trusting it with real data. It worked cleanly here on 10.8.5.

After this step, diskutil list confirms both partitions are now part of the same CoreStorage group:

diskutil list
/dev/disk1
 2: Apple_CoreStorage Untitled 1 90.8 GB disk1s2
 4: Apple_CoreStorage Untitled 2 658.8 GB disk1s3

And diskutil coreStorage list shows a single LVG with both PVs and ~90.6GB of free space sitting unused inside the pool:

diskutil coreStorage list
Logical Volume Group CE67A415-F191-46A9-9605-473504EDEF92
    Size:         749678182400 B (749.7 GB)
    Free Space:   90580946944 B (90.6 GB)
    +-< Physical Volume 0FCE0B6A... (disk1s3, 658.8 GB)
    +-< Physical Volume 8BBA11A2... (disk1s2, 90.8 GB)
    +-> Logical Volume 94DBC0B5... (Size: 658.5 GB)

The space is pooled, but the Logical Volume itself hasn’t grown yet — that’s the last step.

Step 3

Grow the Logical Volume to claim the pooled space

The diskutil coreStorage resizeVolume man page (at least as documented on more recent macOS versions) says you can pass 0 as a shorthand for “grow to fill all remaining space in the LVG.” This does not work on 10.8.5:

bash
$ diskutil coreStorage resizeVolume 94DBC0B5-3101-45B9-9FDB-242285F3E9E2 0
0 does not appear to be a valid disk size

The workaround is to calculate and pass an explicit byte count instead:

math
target size = current LV size + free LVG space
            = 658,493,243,392 B + 90,580,946,944 B
            = 749,074,190,336 B

(Deliberately left slightly under the LVG’s total 749,678,182,400 B to leave headroom for CoreStorage’s own metadata — don’t try to claim every last byte.)

bash
$ diskutil coreStorage resizeVolume 94DBC0B5-3101-45B9-9FDB-242285F3E9E2 749074190336b
Started CoreStorage operation
Checking file system
Checking Journaled HFS Plus volume
Checking extents overflow file
Checking catalog file
Checking multi-linked files
Checking catalog hierarchy
Checking extended attributes file
Checking volume bitmap
Checking volume information
The volume Untitled 2 appears to be OK
Growing Logical Volume
Resizing Core Storage Logical Volume structures
Resized Core Storage Logical Volume to 749074190336 bytes
Growing file system
Finished CoreStorage operation
✓  Success — the Logical Volume, and the filesystem living on it, both grew to absorb the pooled space, with the original data intact throughout.

Takeaways

  • If your empty space is physically before your data, plain partition resize (resizeVolume, mergePartitions) can’t reach it — this isn’t a bug, it’s inherent to how in-place filesystem growth works.
  • CoreStorage’s addDisk can pool partitions regardless of their physical order, because it’s a logical layer, not a physical resize. But it’s undocumented and unsupported — back up first, and ideally rehearse the whole sequence on a throwaway test disk before running it against real data.
  • resizeVolume‘s 0-for-“everything” shortcut, as documented on later macOS versions, does not exist on 10.8.5. Use currentSize + freeSpace in bytes instead, with the b suffix, and leave a small margin under the LVG total.

Full Session Log

The complete, unedited terminal transcript (including all diskutil list output at each stage) is available as a PDF here: resize-partition.pdf