背景
入坑obsidian做笔记有一年多了,obsidian哪里都好,就是同步稍显麻烦,图片开了个阿里的oss,搭建了图床,算初步解决。数据同步方案折腾了一大堆,最后还是回到了git。平平淡淡才是真啊。但是每天手动提交,还得写上对笔记来说没那么重要的commit message,多少有点浪费时间。一时半会还行,时间久了还真是有些烦人。
解决方案
python + git + 批处理
GitPython
GitPython允许我们使用git命令来操作git仓库
安装
bash
pip install gitpython
封装一个GitSync
类
python
import git
class GitSync():
def __init__(self, rep_path):
log.info("rep_path:%s" % rep_path)
# 判断rep_path是否为Path对象
if not isinstance(rep_path, Path):
log.error("rep_path is not Path object")
raise Exception("rep_path is not Path object")
# 判断rep_path是否为git仓库
if not Path(rep_path).joinpath(".git").exists():
log.error("not git repository")
raise Exception("not git repository")
self.rep_path = str(rep_path)
self.repo = git.Repo(rep_path)
def check_status(self):
status = self.repo.git.status()
if "nothing to commit, working tree clean" in status:
return True
else:
return False
def auto_commit(self):
self.repo.git.add(".")
# 获取当前时间
now = datetime.now()
# 格式化时间
now = now.strftime("%Y-%m-%d %H:%M:%S")
self.repo.git.commit("-m", "auto commit at %s" % now)
self.repo.git.push()
log.info("auto commit success")
def pull(self):
# 判断拉取是否存在冲突
try:
self.repo.git.pull()
log.info("pull success")
return True
except git.exc.GitCommandError as e:
log.error(e)
log.error("pull error")
return False
def push(self):
self.repo.git.push()
log.info("push success")
为了扩展和方便使用,我们引入命令行,没有传入则使用当前路径作为git仓库
python
import argparse
if __name__ == '__main__':
# 创建一个ArgumentParser对象
parser = argparse.ArgumentParser(description="git auto commit tool")
parser.add_argument("--rep", type=str, default="", help="path of repository")
# 解析命令行参数
args = parser.parse_args()
if args.rep:
rep_path = Path(args.rep)
else:
rep_path = Path(__file__).parent.absolute()
搭配批处理
bat
D:\dev\Anaconda\pythonw.exe D:\code\gitee\obsidian\git自动提交.py
pause
这里介绍一下pythonw
pythonw
是 Python 安装过程中在 Windows 系统上安装的一个可执行文件,它的作用与 python
类似,但有一些关键的区别:
- 无控制台窗口 :当你运行
pythonw.exe
时,它不会创建一个新的控制台窗口来显示输出或错误信息。这对于 GUI 应用程序或那些你不希望用户看到控制台窗口的脚本非常有用。 - 图形界面应用程序 :
pythonw
通常用于运行没有控制台窗口的 Python GUI 应用程序。例如,使用 Tkinter 或 PyQt 等库创建的应用程序。 - 后台运行 :由于没有控制台窗口,使用
pythonw
运行的脚本适合作为后台进程运行,不会干扰用户的其他操作。 - 脚本运行 :如果你有一个 Python 脚本,你希望它在没有控制台窗口的情况下运行,你可以双击该脚本文件,或者在开始菜单中选择它,Python 会使用
pythonw
来运行它。 - 环境变量 :在 Windows 上,可以通过设置环境变量
PYTHONW_DEFAULT
来让双击.py
文件时默认使用pythonw.exe
运行。
这样我们可以将脚本放置在仓库根目录,并发送到桌面快捷方式,双击则可以自动同步并提交。如果有多台电脑,同步起来也异常方便。
完整代码
python
import argparse
import git
import logging as log
from pathlib import Path
from datetime import datetime
log.basicConfig(level=log.INFO, format='%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s')
class GitSync():
def __init__(self, rep_path):
log.info("rep_path:%s" % rep_path)
# 判断rep_path是否为Path对象
if not isinstance(rep_path, Path):
log.error("rep_path is not Path object")
raise Exception("rep_path is not Path object")
# 判断rep_path是否为git仓库
if not Path(rep_path).joinpath(".git").exists():
log.error("not git repository")
raise Exception("not git repository")
self.rep_path = str(rep_path)
self.repo = git.Repo(rep_path)
def check_status(self):
status = self.repo.git.status()
if "nothing to commit, working tree clean" in status:
return True
else:
return False
def auto_commit(self):
self.repo.git.add(".")
# 获取当前时间
now = datetime.now()
# 格式化时间
now = now.strftime("%Y-%m-%d %H:%M:%S")
self.repo.git.commit("-m", "auto commit at %s" % now)
self.repo.git.push()
log.info("auto commit success")
def pull(self):
# 判断拉取是否存在冲突
try:
self.repo.git.pull()
log.info("pull success")
return True
except git.exc.GitCommandError as e:
log.error(e)
log.error("pull error")
return False
def push(self):
self.repo.git.push()
log.info("push success")
if __name__ == '__main__':
# 创建一个ArgumentParser对象
parser = argparse.ArgumentParser(description="git auto commit tool")
parser.add_argument("--rep", type=str, default="", help="path of repository")
# 解析命令行参数
args = parser.parse_args()
if args.rep:
rep_path = Path(args.rep)
else:
rep_path = Path(__file__).parent.absolute()
sync = GitSync(rep_path)
nothing_status = sync.check_status()
if nothing_status:
log.info("nothing to commit, working tree clean")
else:
res = sync.pull()
if not res:
log.error("pull error")
raise Exception("pull error")
sync.auto_commit()