Halo to Hugo 文章迁移工具 📦

🚀 一款专为博客迁移设计的智能工具,可将 Halo 文章的 Front Matter 格式完美转换为 Hugo 兼容格式,让您的博客迁移过程更加顺畅高效!

💡 基于优秀开源项目二次开发,源自:https://github.com/ayuayue/hexo2hugo


📋 导航目录

✨ 功能特点
📚 使用指南
🔧 技术细节
⚠️ 注意事项
🐛 常见问题
💻 开发指南


✨ 功能特点

  • 🔄 格式转换:自动将 Halo 的 Front Matter 转换为 Hugo 兼容格式
  • 📅 日期处理:智能转换日期格式并添加时区信息
  • 🏷️ 标签分类:完美处理 tagscategories 字段
  • 🛡️ 安全第一:创建独立输出目录,不修改原始文件
  • 📝 内容保留:保持文章正文内容完全不变
  • ⚙️ 灵活扩展:支持自定义添加其他 Front Matter 字段

📚 使用指南

🚀 快速开始

1
2
3
# 克隆项目到本地
git clone git@github.com:meimolihan/halo_to_hugo.git
cd halo_to_hugo

详细步骤

  1. 准备测试环境 📂

    1
    2
    3
    # 创建测试目录并复制一些文章
    mkdir test
    cp ~/your-halo-blog/content/posts/*.md test/
  2. 执行转换

    1
    2
    # 运行转换工具
    go run main.go test
  3. 验证结果

    1
    2
    3
    4
    5
    # 查看转换后的文件
    ls -la newPost$(date +%s)/

    # 检查单个文件内容
    head -n 20 newPost1701319905/your-post.md
  4. 应用到正式环境 🚀

    1
    2
    3
    4
    5
    6
    7
    8
    9
    # 将转换后的文章移动到Hugo目录
    mv newPost1701319905/* ~/your-hugo-site/content/posts/

    # 针对正式目录执行
    go run main.go ~/your-hugo-site/content/posts/

    # 运行Hugo测试生成
    cd ~/your-hugo-site
    hugo server -D

🎯 生产环境部署

  1. 完整迁移流程

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    # 1. 备份原始数据(重要!)
    tar -czf halo-backup-$(date +%Y%m%d).tar.gz ~/your-halo-blog/

    # 2. 执行转换
    go run main.go ~/your-halo-blog/content/posts/

    # 3. 部署到Hugo
    mv newPost1701319905/* ~/your-hugo-site/content/posts/

    # 4. 生成静态站点
    cd ~/your-hugo-site
    hugo --minify

    # 5. 验证生成结果
    ls -la public/
  2. 增量迁移策略

    1
    2
    3
    # 只处理新增或修改的文章
    find ~/your-halo-blog/content/posts/ -name "*.md" -newer last_migration.txt | xargs -I {} cp {} ./incremental_posts/
    go run main.go ./incremental_posts/

🔧 技术细节

支持的 Front Matter 转换

Halo 字段 Hugo 字段 转换说明
title title 添加引号包裹
date date 转换为 ISO8601 格式并添加时区
excerpt description 直接映射
cover image 直接映射
tags tags 支持字符串和列表两种格式
categories categories 支持字符串和列表两种格式
permalink slug 提取最后部分作为slug

转换示例

转换前 (Halo格式):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
title: Halo to Hugo 迁移工具
id: 770a1b63-4737-4e87-a0d8-b8b38a3f7b6a
date: 2025-08-26 16:39:39
auther: admin
cover: https://example.com/image.webp
excerpt: Halo to Hugo 迁移工具:无缝转换文章 Front Matter
permalink: /archives/5uaPaEJk
categories:
- Halo
- Hugo
tags:
- blog
---

转换后 (Hugo格式):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
title: "Halo to Hugo 迁移工具"
date: 2025-08-26T16:39:39+08:00
description: "Halo to Hugo 迁移工具:无缝转换文章 Front Matter"
draft: false
weight: 0
image: "https://example.com/image.webp"
categories:
- Halo
- Hugo
tags:
- blog
slug: "5uaPaEJk"
---

📁 文件结构处理

可选操作:Hugo 标准目录结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 1. 为每篇文章创建独立目录
for %F in ("*.md") do @md "%~nF" 2>nul & move /Y "%F" "%~nF\"

# 2. 统一重命名为 index.md(Hugo标准)
for /r %F in (*.md) do @if /i not "%~nF"=="index" ren "%F" "index.md"

# 最终结构示例:
# content/
# └── posts/
# ├── post-1/
# │ └── index.md
# ├── post-2/
# │ └── index.md
# └── post-3/
# └── index.md

⚠️ 注意事项

💾 数据安全第一

  • 重要提醒:始终在操作前备份原始文件,建议使用版本控制系统
  • 测试先行:先在测试目录验证转换结果,确认无误后再应用到正式环境
  • 分批处理:对于大量文章,建议分批迁移,便于问题排查

🔍 转换前检查

  1. 文件编码:确保原始文件使用 UTF-8 编码,避免乱码问题
  2. 格式规范:确认 Halo 文章使用标准 YAML Front Matter 格式
  3. 特殊字符:检查标题和描述中是否包含需要转义的特殊字符
  4. 图片资源:验证封面图链接是否有效,是否需要迁移图床

🛠️ 自定义配置

  • 时区设置:如需修改默认时区,可调整源码中的 Asia/Shanghai
  • 字段扩展:如需转换其他 Front Matter 字段,可自行修改转换逻辑
  • 输出格式:支持调整日期格式、缩进等输出参数

📝 迁移后验证

  1. 内容完整性:随机抽查多篇文章,确认正文内容无丢失
  2. Front Matter:检查所有必要字段是否正确转换
  3. 链接有效性:测试文章永久链接是否正常跳转
  4. 分类标签:确认分类体系和标签云显示正常

🐛 常见问题

🔧 转换相关问题

Q: 转换后文章内容出现乱码怎么办?
A: 这通常是由于文件编码问题导致的。请按以下步骤解决:

1
2
3
4
5
# 检查文件编码
file -i your-post.md

# 转换编码为 UTF-8
iconv -f GBK -t UTF-8 your-post.md > your-post-utf8.md

Q: 某些特殊字段没有转换怎么办?
A: 工具目前支持常见字段转换。如需添加自定义字段,可以:

  1. 修改 convertFrontMatter 函数
  2. 添加对应的字段映射逻辑
  3. 重新编译工具

Q: 转换后的日期时区不正确怎么办?
A: 修改源码中的时区设置:

1
2
3
4
// 找到这行代码,修改为您的时区
location, _ := time.LoadLocation("Asia/Shanghai")
// 例如改为:
location, _ := time.LoadLocation("America/New_York")

🚀 使用相关问题

Q: 工具提示 “目录不存在” 错误?
A: 请检查:

  • 目录路径是否正确
  • 是否具有该目录的读取权限
  • 路径中是否包含特殊字符

Q: 转换过程中程序崩溃怎么办?
A: 这可能是由于某篇文章格式异常导致的:

  1. 查看错误信息,定位问题文件
  2. 手动修复该文件的 Front Matter 格式
  3. 重新运行转换工具

Q: 如何只转换部分文章?
A: 可以使用以下方法:

1
2
3
4
# 创建临时目录,复制需要转换的文章
mkdir temp_posts
cp /path/to/specific/posts/*.md temp_posts/
go run main.go temp_posts

📊 Hugo 集成问题

Q: 迁移后 Hugo 生成失败?
A: 检查可能的 Front Matter 问题:

1
2
3
4
5
# 使用 Hugo 检查语法
hugo --verbose

# 检查具体的错误信息
hugo server 2>&1 | grep -i error

Q: 分类和标签在 Hugo 中显示异常?
A: 确认 Hugo 配置文件中的分类设置:

1
2
3
4
# config.toml 中的相关配置
[taxonomies]
category = "categories"
tag = "tags"


💻 开发指南

🏗️ 项目结构概览

1
2
3
4
5
6
7
halo_to_hugo/
├── main.go # 主程序入口
├── go.mod # 模块定义
├── README.md # 项目说明
└── examples/ # 示例文件
├── input/ # 输入示例
└── output/ # 输出示例

🔧 核心函数解析

  1. 主转换函数 convertFrontMatter

    1
    2
    // 主要负责 Front Matter 的解析和转换
    // 支持字段映射、日期处理、标签标准化等
  2. 日期处理函数 convertDate

    1
    2
    3
    // 功能:多种日期格式解析和时区处理
    // 输入:原始日期字符串
    // 输出:ISO8601 格式的日期字符串
  3. 标签处理函数 convertToStringSlice

    1
    2
    3
    // 功能:统一 tags/categories 字段格式
    // 支持:字符串逗号分隔 → 列表转换
    // 支持:已有列表格式的标准化

🎯 扩展开发指南

添加新字段转换

1
2
3
4
5
6
7
8
9
10
11
12
func convertFrontMatter(original map[string]interface{}) map[string]interface{} {
newFrontMatter := make(map[string]interface{})

// 现有转换逻辑...

// 添加自定义字段转换
if customField, exists := original["custom_field"]; exists {
newFrontMatter["hugo_custom_field"] = customField
}

return newFrontMatter
}

修改输出格式

1
2
3
4
5
// 调整日期输出格式
func formatDate(t time.Time) string {
// 自定义格式
return t.Format("2006-01-02 15:04:05 -0700")
}

🤝 贡献指南

欢迎提交 Pull Request 和 Issue!参与开发时请注意:

  1. 代码规范:遵循 Go 语言标准代码格式
  2. 测试覆盖:新增功能请添加相应的测试用例
  3. 文档更新:修改功能时同步更新文档说明
  4. 兼容性:确保改动不影响现有的转换逻辑

🔍 调试技巧

1
2
3
4
5
6
7
8
# 启用详细日志输出
go run main.go -verbose test_posts

# 调试单篇文章
go run main.go -debug single_post.md

# 性能分析
go run main.go -profile test_posts

🎉 迁移愉快! 希望这个工具能让您的博客迁移过程更加顺利!
📮 如有任何问题或建议,欢迎在 GitHub 项目中提出 Issue 或 Pull Request!
⭐ 如果觉得工具好用,别忘了给项目点个 Star 支持一下!