How do I move all lines matching a pattern to the top or bottom of a file?
Answer
:g/pattern/m 0
Explanation
The :global command combined with :move lets you restructure a file by relocating all lines that match a pattern. This is invaluable for reorganizing imports, grouping related definitions, or pulling TODOs and FIXMEs to the top of a file for review.
How it works
:g/pattern/— iterates over every line matchingpatternm 0— moves the current line to after line 0 (i.e., the top of the file)- Each matching line is moved in order, so the last match ends up on line 1. The result is that all matching lines appear at the top in their original relative order
- Use
m $to move matching lines to the bottom instead
Example
Given a file with scattered TODO comments:
func init() {
// TODO: add validation
func process() {
// TODO: handle errors
func cleanup() {
// TODO: add logging
Running :g/TODO/m 0 produces:
// TODO: add validation
// TODO: handle errors
// TODO: add logging
func init() {
func process() {
func cleanup() {
Tips
- Combine with
:v(inverse global) to move non-matching lines instead::v/pattern/m $ - Use a range to limit scope:
:10,50g/import/m 9moves imports in lines 10-50 to just before line 10 - Pair with
:sortafter moving for alphabetical ordering::g/^import/m 0then:1,/^[^i]/sort - A single undo (
u) reverses the entire operation since:gbatches all moves