- 显示最近创建的笔记,可以考虑是否要发布到博客
- 频繁发布前 修改 '.vscode\settings.json' 下
- '"noteSync.enableNoteSync": true, -> "noteSync.enableNoteSync": false,'
输入
- 开始时间 (
--since
): 定义“最近”的时间起点,例如"2025-01-01"
。 - 过滤地址/路径 (
path_filter
): 限定笔记文件所在的目录,例如note/docs/备忘/
或note/docs/备忘
。 - 文件状态 (
--diff-filter=A
): 仅查找新增 (Added) 的文件。
git log 方式
方案一:Git Bash/Shell 命令行方式
这种方式简洁高效,但需要解决编码乱码和路径去重的问题。
- 基础 Git 命令(查找新增文件路径):
git log --since="2025-01-01" --name-status --pretty=format:'' \
| grep -E '^A' \
| awk '{print $2}' \
| grep -E '^(note|docs|备忘)/' \
| sort -u
-
不支持 powershell
-
编码配置
-
为了解决 Git Bash/Shell 下中文路径或内容乱码问题:
git config --global core.quotepath false
git config --global i18n.commitencoding utf-8
git config --global i18n.logencoding utf-8
export LESSCHARSET=utf-8 # 针对 git log 等分页显示工具
git log --since="2025-01-01" --name-status --pretty=format:"COMMIT_TIME:%cd" --date=format:"%Y-%m-%d %H:%M:%S" |
Where-Object { $_ -match '^(COMMIT_TIME:|A\s+note\\docs)' } |
ForEach-Object {
if ($_ -match '^COMMIT_TIME:(.*)') {
$script:commitTime = $matches[1].Trim() # 记录当前提交时间
} else {
$filePath = ($_ -split '\s+', 2)[1] # 提取文件路径(兼容空格)
"$commitTime`t$filePath" # 时间+制表符+路径
}
} |
Group-Object -Property { $_ -split '\t' | Select-Object -Last 1 } | # 按路径去重
ForEach-Object { $_.Group[0] } |
Sort-Object # 按时间排序
- 乱码 git log 后输出的应该是 utf8, 和后面的 windows 命令有关系导致不显示了。放弃。
- 考虑到换环境,不想每次都重复这种操作,那么考虑做成环境设置脚本,既然都脚本了,不如 python 搞定。
Python 脚本方式
- 还是乱码,又不想改默认环境,干脆换成 python 脚本
import subprocess
import re
from datetime import datetime
# 移除了 os, time 模块,因为不再需要文件系统操作
def decode_octal(data_str):
"""解码 Git 输出中的八进制编码。"""
def byte_creator(match):
octal_str = match.group(1)
decimal_val = int(octal_str, 8)
# 使用 latin-1 编码桥接,确保单字节字符正确返回
return bytes([decimal_val]).decode('latin-1')
intermediate_str = re.sub(r'\\(\d{3})', byte_creator, data_str)
final_bytes = intermediate_str.encode('latin-1')
# 最终使用 UTF-8 解码为中文
return final_bytes.decode('utf-8', errors='replace')
def get_git_info(since_date="2025-01-01", path_filter=None):
"""执行 Git 命令,获取指定日期至今的新增文件及其首次提交时间。"""
# 1. 运行 Git 命令获取新增文件列表、提交哈希和日期
GIT_FORMAT = '%H|%ad' # 格式:[哈希]|[作者日期]
try:
result = subprocess.run(
[
"git", "log", f"--since={since_date}",
"--diff-filter=A", "--name-status",
f"--pretty=format:{GIT_FORMAT}", "--date=format:%Y-%m-%d %H:%M:%S"
],
check=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
output_data = result.stdout.decode('utf-8', errors='replace').strip()
except subprocess.CalledProcessError as e:
# 解码错误信息并打印
print(f"Git 命令执行失败:{e.stderr.decode('utf-8', errors='replace')}")
return []
except FileNotFoundError:
print("错误:未找到 Git 命令,请确保 Git 已安装并添加到系统环境变量")
return []
# 2. 解析输出,提取信息,并处理去重和过滤
file_info_map = {} # { 文件路径:{git_time, hash, status} }
current_hash = None
current_time = None
for line in output_data.split('\n'):
line = line.strip()
# 检查是否是提交信息行
if '|' in line and re.match(r'^[0-9a-f]{40}\|', line):
parts = line.split('|', 1)
current_hash = parts[0]
current_time = parts[1].strip()
continue
# 检查是否是文件状态行 (如 A\tpath/to/file)
if len(line) > 2 and line[1].isspace():
status = line[0]
file_path_encoded = line[2:].strip()
file_path = decode_octal(file_path_encoded)
# 仅处理新增文件 ('A')
if status != 'A':
continue
# 过滤功能:跳过不匹配路径的文件
# 注意:如果 path_filter 是 None 或空字符串,则不进行过滤
if path_filter and path_filter in file_path:
pass # 路径匹配,继续
elif path_filter:
continue # 路径不匹配,跳过
# 记录文件的首次提交信息 (由于 git log 默认是新的在前,第一次遇到即为最早记录)
if file_path not in file_info_map:
file_info_map[file_path] = {
"status": status,
"git_time": current_time,
"commit_hash": current_hash,
"path": file_path
}
# 3. 整理和排序结果
final_list = list(file_info_map.values())
# 按 Git 首次提交时间排序
return sorted(final_list, key=lambda x: x['git_time'])
# ------------------- 主执行逻辑 -------------------
if __name__ == "__main__":
# --- 配置项 ---
target_date = "2025-02-13" # 查询起始日期
# 路径过滤器:设置您想要包含的地址片段。
# 例如:如果要查找 'note/docs' 目录下的文件,设置为 'note/docs'
# 如果不需要过滤,设置为 None 或空字符串。
path_filter = "note/docs/备忘"
# -------------
print(f"正在查询 {target_date} 至今的 Git 新增文件。..")
if path_filter:
print(f"应用地址过滤器:'{path_filter}'")
new_files = get_git_info(target_date, path_filter)
if new_files:
print(f"\n 共找到 {len(new_files)} 个新增文件(去重后):")
print("-" * 65)
# 打印表头
print(f"{'No.':<4}{'状态':<4}{'Git 首次提交时间':<22}{'文件路径'}")
print("-" * 65)
for idx, file_info in enumerate(new_files, 1):
print(f"{idx:<4}{file_info['status']:<4}{file_info['git_time']:<22}{file_info['path']}")
print("-" * 65)
else:
print(f"\n 未找到 {target_date} 至今的新增文件,或所有文件已被过滤器排除。")
方案二:读 md 文件的 header
既然都读 python 文件了,那干脆读 md 文件的 header 信息,直接读取创建时间
- 写一个 python 脚本
- 读取指定文件夹下的所有 md 文件
- 过滤 header 中 date 数据小于输入时间的文件
- 排序由远到近输出到控制台
import os
import frontmatter # 新增导入
from datetime import datetime
# --- 配置区 ---
# 1. 待扫描的根文件夹路径
TARGET_DIR = "note\docs\备忘"
# 2. 筛选日期阈值(只保留日期晚于此时间的笔记)
FILTER_DATE_STR = "2025-04-20"
# ----------------
def parse_md_header_date(filepath: str) -> datetime | None:
"""
使用 'frontmatter' 库读取 Markdown 文件,提取并返回 date 字段的 datetime 对象。
"""
try:
post = frontmatter.load(filepath)
if 'date' not in post.metadata:
print(f"警告:文件 {filepath} 缺少 'date' 字段。")
return None
date_value = post.metadata['date']
# 检查是否已经是 datetime 对象(由 YAML 解析器自动处理)
if isinstance(date_value, datetime):
return date_value
# 否则,尝试将字符串转换为 datetime 对象
date_str = str(date_value).strip()
try:
return datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S')
except ValueError:
try:
return datetime.strptime(date_str, '%Y-%m-%d')
except ValueError:
print(f"警告:文件 {filepath} 的 date 格式无法识别:'{date_str}'")
return None
except FileNotFoundError:
print(f"错误:文件未找到 {filepath}")
return None
except frontmatter.FrontmatterError as e:
# 当文件开头没有合法的 '---' 区块时会抛出此错误
# print(f"警告:文件 {filepath} 无法解析 YAML Front Matter: {e}")
return None
except Exception as e:
print(f"处理文件 {filepath} 时发生未知错误: {e}")
return None
def main():
"""主执行逻辑:扫描、筛选、排序并输出结果。"""
# 处理 TARGET_DIR 路径并获取绝对路径
absolute_target_dir = os.path.abspath(TARGET_DIR)
# 检查文件夹是否存在
if not os.path.isdir(absolute_target_dir):
print(f"错误:目标文件夹 '{TARGET_DIR}' (绝对路径: {absolute_target_dir}) 不存在。")
return
try:
# 将输入的筛选时间字符串转换为 datetime 对象
filter_date = datetime.strptime(FILTER_DATE_STR.split()[0], '%Y-%m-%d')
except ValueError:
print(f"错误:输入的筛选日期格式 '{FILTER_DATE_STR}' 无效。请使用 YYYY-MM-DD 格式。")
return
print(f"--- 笔记筛选工具 ---")
print(f"原始目标目录: {TARGET_DIR}")
print(f"**绝对路径**: {absolute_target_dir}")
print(f"筛选时间阈值 (晚于): {filter_date.strftime('%Y-%m-%d')}")
print("-" * 30)
filtered_notes = []
for root, _, files in os.walk(absolute_target_dir):
for filename in files:
if filename.endswith(('.md', '.markdown')):
filepath = os.path.join(root, filename)
# 使用优化的解析函数
note_date = parse_md_header_date(filepath)
if note_date and note_date > filter_date:
filtered_notes.append((note_date, filepath))
# 排序:按日期由远到近(升序)排序
filtered_notes.sort(key=lambda x: x[0])
# 输出结果
if filtered_notes:
print(f"\n✅ 找到 {len(filtered_notes)} 篇符合条件的笔记(日期晚于 {filter_date.strftime('%Y-%m-%d')}):")
print("-" * 60)
print(f"{'No.':<4}{'文件日期':<22}{'文件相对路径'}")
print("-" * 60)
for idx, (note_date, filepath) in enumerate(filtered_notes, 1):
relative_path = os.path.relpath(filepath, absolute_target_dir)
print(f"{idx:<4}{note_date.strftime('%Y-%m-%d'):<12}{relative_path}")
print("-" * 60)
else:
print("\n❌ 未找到符合条件的笔记。")
if __name__ == "__main__":
main()