雖然儘量避免,但偶爾還是需要管理大量的 Excel 或 Excel VBA 的情況,您是否有過這樣的經驗呢?
如果是 App Script,還有幾種管理的方法可供選擇。
不過,對於 Excel 和 Excel VBA,似乎沒有太多的管理方式,最終常常會找到雲端上的某個硬碟來存放。
經過一番思考,我認為最好的管理方式還是使用 Git,因此撰寫了這篇文章。
將 Excel 和 Excel VBA 使用 Git 管理,最終會變成二進位管理。
為了尋找解決方案,從 Chart GPT
獲得了推薦 Git XL
,但發現更新停滯,使用上讓人感到不安。
所以總的來說,Excel 本身似乎無法脫離二進位管理。。。這就是我的結論。
我希望至少妥善管理 VBA 部分。因此查找資訊後,找到以下的文章。
透過 Excel 的 commit 時機,提取出 VBA 的部分,並將其混入現有的 commit 中。
這聽起來「不錯」,於是我馬上就挑戰了一下。
使用的工具是 Python,並且僅用到 pre-commit
和 oletools
這兩個函式庫。
這兩者在 2025.09
現在的版本中,都得到了妥善的維護。
以下是 pre-commit
的 YAML 配置檔。
# .pre-commit-config.yaml
repos:
- repo: local
hooks:
- id: extract-vba-macros
name: 從 Excel 檔案中提取 VBA 巨集
entry: uv run python .githooks/pre-commit.py
language: system
files: \.(xlsb|xls|xlsm|xla|xlt|xlam)$
pass_filenames: false
always_run: false
以下是提交時觸發的原始程式碼。
# .githooks/pre-commit.py
import os
import shutil
import sys
import subprocess
from oletools.olevba3 import VBA_Parser
EXCEL_FILE_EXTENSIONS = ('xlsb', 'xls', 'xlsm', 'xla', 'xlt', 'xlam')
KEEP_NAME = False
VBA_ROOT_PATH = 'src.vba'
def get_staged_excel_files() -> list[str]:
try:
result = subprocess.run(
['git', 'diff', '--cached', '--name-only', '-z'],
capture_output=True,
text=True,
check=True
)
# git diff --cached --name-only -z 取得的檔案名是以 null 字符(\0) 分隔
# 例如: "src.vba/轉換工具/Sheet1.cls\0src.vba/轉換工具/Module1.bas\0"
# 因此,我們獲取以 null 字符(\0) 隔開的檔案名,排除空字串,取得檔案名
staged_files = result.stdout.strip().split('\0') if result.stdout.strip() else []
staged_files = [f for f in staged_files if f] # 排除空字串
# 取得 Excel 檔案(排除臨時檔案)
excel_files = [
f for f in staged_files
if f.endswith(EXCEL_FILE_EXTENSIONS) and os.path.exists(f) and not os.path.basename(f).startswith('~$')
]
return excel_files
except subprocess.CalledProcessError:
# 如果 git 命令失敗,回退到掃描所有檔案
return []
def parse_excel_file(excel_file: str) -> bool:
excel_filename = os.path.splitext(os.path.basename(excel_file))[0]
vba_file_dir = os.path.join(VBA_ROOT_PATH, excel_filename)
try:
vba_parser = VBA_Parser(excel_file)
if not vba_parser.detect_vba_macros():
print(f"{excel_file} 中沒有發現 VBA 巨集")
return True
vba_modules = vba_parser.extract_all_macros()
if not vba_modules:
print(f"{excel_file} 中未提取到 VBA 模組")
return True
print(f"正在從 {excel_file} 中提取 VBA 巨集...")
for _, _, filename, content in vba_modules:
lines = content.split('\r\n') if '\r\n' in content else content.split('\n')
if not lines:
continue
filtered_content = []
for line in lines:
if line.startswith('Attribute') and 'VB_' in line:
if 'VB_Name' in line and KEEP_NAME:
filtered_content.append(line)
else:
filtered_content.append(line)
if filtered_content and filtered_content[-1] == '':
filtered_content.pop()
non_empty_lines = [line for line in filtered_content if line.strip()]
if non_empty_lines:
if not os.path.exists(vba_file_dir):
os.makedirs(vba_file_dir)
output_file = os.path.join(vba_file_dir, filename)
with open(output_file, 'w', encoding='utf-8') as f:
f.write('\n'.join(filtered_content))
print(f" → 提取完成: {output_file}")
# 將提取出的 VBA 檔案加入階段
subprocess.run(['git', 'add', output_file], check=False)
vba_parser.close()
return True
except Exception as e:
print(f"處理 {excel_file} 時發生錯誤: {e}")
return False
def clean_old_vba_files(staged_excel_files: list[str]) -> None:
excel_file_names = [
os.path.splitext(os.path.basename(excel_file))[0]
for excel_file in staged_excel_files
]
for excel_filename in excel_file_names:
vba_file_dir = os.path.join(VBA_ROOT_PATH, excel_filename)
if not os.path.exists(vba_file_dir):
try:
print(f"移除舊的 VBA 目錄: {vba_file_dir}")
shutil.rmtree(vba_file_dir)
except Exception as e:
print(f"移除舊的 VBA 目錄時發生錯誤: {e}")
def main():
staged_excel_files = get_staged_excel_files()
if not staged_excel_files:
print("未找到任何 Excel 檔案。")
return 0
clean_old_vba_files(staged_excel_files)
success = True
for excel_file in staged_excel_files:
if not parse_excel_file(excel_file):
success = False
if success:
print("VBA 巨集提取成功完成。")
return 0
else:
print("有些檔案處理失敗。")
return 1
if __name__ == '__main__':
sys.exit(main())
可惜的是,對於 Excel 仍然需要持續進行二進位管理,但對於 VBA,已經可以脫離 Excel,使用 Git 來進行源碼管理。
至少,相較於「儲存在某個雲端上」,此管理方式算是好一些的選擇。
對於非工程師來說,Excel 和 Excel VBA 是非常方便的工具,容易產生大量的檔案。
然而,對於管理者來說,Excel 和 Excel VBA 是難以管理的,盡可能地應該避免使用這些工具。
特別是當 Excel 和 Excel VBA 作為系統使用的一部分時,能夠盡可能地與源碼一起管理會是最理想的。
此次針對 Excel 和 Excel VBA 的管理方式,進行了一番研究和嘗試。