Skip to content

Repository files navigation

GitPic

gitpic

把本地或剪贴板里的图片传到 GitHub 仓库当图床,生成 Markdown 链接并复制到剪贴板。

简体中文 · English

菜单栏 App 和命令行是同一个东西的两个界面,同版本、共用配置和上传历史。认证只有一条路 —— gitpic auth login(浏览器授权),配置文件里不保存任何密钥

GitPic.app(macOS 菜单栏)

发布页GitPic-<版本>-macos-arm64.dmg, 打开后把 GitPic 拖到 Applications,然后解除隔离:

xattr -dr com.apple.quarantine /Applications/GitPic.app

这一步不是可选的。 App 是本机签名、未经 Apple 公证的,不解除隔离 macOS 会直接拒绝打开。 只有手动装的这一次需要 —— 之后的应用内更新会自己处理隔离属性。

从菜单里选文件上传,或上传剪贴板里的图 —— 链接直接进剪贴板,成功与失败都走 系统通知。也可以在 Finder 里选中图片按右键,点「GitPic 上传至图床」(App 没在运行会被 拉起来;不想要这一项的话,「通用」页的「系统集成」开关可以关掉它)。设置窗口有六页:通用 (开机自启动、检查更新、Finder 右键)、图床(账号、仓库、连通性测试)、上传(路径模板、链接形态、 压缩)、历史(带缩略图,一键复制)、Agent(各家 Skill 安装)、关于。

想让 GitPic 一登录就待在菜单栏里,把「通用」页的「开机自启动」打开就行 —— 它写的是 macOS 自己的登录项,所以「系统设置 ▸ 通用 ▸ 登录项与扩展」里也能看到、也能关掉,两边永远是同一个开关。

检查更新默认每天自动查一次,也可以在「通用」页或菜单栏里随时手动查。发现新版本时会显示这一版 的更新内容,旁边是一个「下载并更新」按钮 —— 由 GitPic 自己下载该版本的磁盘映像来替换。

替换前会先核对 GitHub 为该文件公布的 SHA-256,拿不到校验和就不装;而且下载、校验、复制全都发生 在退出之前,失败什么都不会改动。替换本身要先退出(没有办法替换正在运行的 bundle),装完自动重开, 隔离属性一并处理好 —— 所以更新之后不需要再敲一遍 xattr

装在 /Applications~/Applications 之外的副本会被指向发布页而不是就地替换,弹窗里会说明是哪 一种原因。

第一次用不需要开终端。 打开设置窗口 → 图床页 → 「使用 GitHub 登录」,一次性码会显示在窗口里、 浏览器自动打开;授权完成后下面的下拉框会列出你可以上传的仓库,选一个,按右上角「保存」写进配置文件。 仓库只能从这个列表里选,分支跟着仓库来(GitHub 上的默认分支,不是硬编码 main)—— 没有手填的入口, 所以拼错仓库名、或者给一个默认分支是 master 的仓库配上 main 这两种情况都不再可能。

想用终端也一样,而且只有一条命令:gitpic auth login 登录成功后会直接把可选仓库列出来让你挑。 两边共用同一份凭据和配置。

仅 Apple Silicon,需要 macOS 14+。

命令行

装了 App 就有命令行,点一下就行。 设置 ▸ 通用 ▸ 命令行 → 「安装命令行工具」。它把 App 内嵌的那份 gitpic 链接~/.local/bin/gitpic,并写好 bash、zsh、fish 三份补全。链接而不是复制,所以终端 和 App 用的是同一个文件 —— 升 App 就是升命令,两者不可能版本不一致。配置和历史也是同一份:App 里改了 仓库,终端里立刻生效,反之也一样。

同一页会说实话:链接装没装、指向哪里、以及具体哪个 shellgitpic 命中哪一个。要是 PATH 上还有另 一份 gitpic 排在前面,它会把胜出的那条路径写出来,而不是假装装好了。

它检查的是登录 shell($SHELL),而 PATH 是每个 shell 各自配置的 —— 所以如果你平时用的不是登录 shell,那一行结论对你实际敲命令的地方不成立。现在先在「配置终端」里选择 bash、zsh 或 fish, 只显示所选终端的状态和**「自动配置」**按钮,不必把其他终端也配好。安装路径、完整 PATH 诊断、 手动配置和移除操作收在默认折叠的「高级选项」里;错误和路径冲突仍直接显示:

shell 自动配置做什么 移除
zsh ~/.zshrc 里维护一个带标记的块(PATH + 补全加载) 有「移除」按钮,只删块
bash 同上,写入已有的首个登录配置文件;没有时创建 ~/.bash_profile 有「移除」按钮
fish 保存为 universal 变量,并验证新启动的 fish;不改启动文件 不自动移除已有路径

fish 配置会保留已有持久路径;重复点击不会叠加。配置时显示进度,失败原因显示在 fish 行旁。 检测超时或启动失败会显示「无法确认」,而不是误报「未配置」。

对于 bash / zsh,GitPic 只在自己那对标记之间写字,块外一个字节都不动:

# >>> gitpic >>>
...
# <<< gitpic <<<

第一次写入前会把原文件备份成 <文件>.gitpic.bak(之后的改写不会覆盖这份备份,所以它永远是「GitPic 动手之前」的那一版)。重复配置是替换而不是叠加。移除命令行工具时这些块会一起清掉。已经自己配好 PATH 的 shell 不会被加第二遍 —— 它会先看你的启动文件里有没有提到过。

不想让 app 碰你的配置文件也行:面板上仍然会把需要粘的行摆出来,手动加完全等价。

不装 App,或者用 Linux / Intel Mac / Windows / CI:从发布页 下对应平台的压缩包解压出 gitpic(CI 在 v* tag 上构建;macOS 需 xattr -d com.apple.quarantine ./gitpic),或者从源码 cargo install --path .(需要 Rust 1.88+)。 这种装法补全自己生成:gitpic completion zsh > ~/.zfunc/_gitpic,bash、fish 同理。

用法

gitpic screenshot.png            # 上传 → 打印 Markdown → 复制到剪贴板
gitpic a.png b.png               # 批量
gitpic paste                     # 上传剪贴板里的图(截图后直接用)
cat img.png | gitpic --stdin     # 扩展名按字节内容判定
gitpic list                      # 最近上传(本地历史)
gitpic auth login                # 浏览器授权登录 GitHub,登录完顺手选图床仓库
gitpic repos                     # 列出这份凭据能上传的仓库
gitpic branches                  # 列出当前仓库的分支(可加 --repo owner/name)
gitpic doctor                    # 检查认证与仓库权限
gitpic update check              # 有没有新版本,以及这一版改了什么
gitpic completion zsh            # 打印补全脚本
gitpic skill install             # 安装 AI 助手技能(见下)

gitpic photo.jpg -q -f url       # 只打印 URL
gitpic photo.jpg --json          # 结构化输出(脚本 / AI 助手)
gitpic photo.jpg --link raw      # 用 raw.githubusercontent.com 而非 jsDelivr

gitpic big.png --compress                    # 上传前压缩
gitpic big.png --compress --max-width 1600   # 缩放到宽度 <= 1600
gitpic big.jpg --compress --quality 80       # JPEG 质量

配置

gitpic config get                        # 查看全部
gitpic config set github.repo owner/name # 改一项,也可一次多项
gitpic config path                       # 配置文件在哪
gitpic config edit                       # 用 $EDITOR 打开

图床仓库是在 gitpic auth login 的最后一步选的(App 里是图床页的下拉框),之后要换就用 gitpic config set github.repo owner/name —— gitpic repos 会把可选的连默认分支一起列出来。 换仓库不会自动改 github.branch:目标仓库的默认分支不是当前配的那个时,github.branch 要一起 改,否则每次上传都会撞上一个不存在的 ref。gitpic branches 正是用来看这件事的:

$ gitpic branches --repo tarnish233/GitPic-legacy
  master
  tmp-verify-sha
  note: `main` is configured but not in this list, so every upload will fail on a ref
        that does not exist — `gitpic config set github.branch <one of the above>`

上传走的是 contents API,它不能创建分支 —— 目标分支必须已经存在。所以 github.branch 的合法取值 恰好就是这个列表,App 的图床页也把分支做成了下拉框(受保护的分支会标出来,但不会被过滤掉:受保护不等于 写不进去,规则可能允许当前账号)。

配置在 ~/.config/gitpic/config.toml(遵循 $XDG_CONFIG_HOME),历史在 ~/.local/share/gitpic/history.jsonl(遵循 $XDG_DATA_HOME)。配置里没有 token 项,所以这个 文件可以安全地纳入 dotfiles 同步 —— 但同一个目录下的 auth.toml 不行,那里面是 gitpic auth login 存的 token(见下):

[github]
owner  = "your-name"
repo   = "img"
branch = "main"

[upload]
path_template = "images/{year}/{month}/{hash8}-{name}.{ext}"
format        = "md"    # md | html | url —— `--format` 的默认值
link_kind     = "cdn"   # cdn (jsDelivr) | raw —— `--link` 的默认值
dedup         = true
auto_copy     = true    # 上传后写剪贴板;App 也遵守(`--json` / `--quiet` 从不写)
compress      = false
max_width     = 0       # 0 = 不缩放
quality       = 82      # 压缩时的 JPEG 质量(1-100)

path_template 占位符:{year} {month} {day} {hash} {hash16} {hash8} {name} {ext}

上传目标也可以用环境变量覆盖(不含凭据):GITPIC_REPOGITPIC_OWNERGITPIC_BRANCHGITPIC_LINK。优先级是命令行参数 > 环境变量 > 配置文件

键名是严格校验的:写错的键或段(dedupe[uplaod])会报 CONFIG_INVALID 并指出被拒的那个 键,而不是静默忽略。这种情况下 gitpic config path / config edit 仍然可用,用来把文件改回来。

凭据

gitpic auth login              # 浏览器授权(GitHub device flow)
gitpic auth status             # 现在这枚凭据是谁的
gitpic auth logout             # 删掉
gitpic repos                   # 这枚凭据能往哪些仓库上传
gitpic branches                # 当前仓库有哪些分支

只有这一条路。 token 存在 ~/.config/gitpic/auth.toml,权限 0600,和 config.toml 分开放 —— 后者会被 gitpic config get 整份打印、被 config edit 丢进 $EDITOR,不是放密钥的地方。

gitpic auth login 走 GitHub 的 device flow:打印一个一次性代码,你在 https://github.com/login/device 输进去,完事。全程没有 client secret,也没有任何需要你手工搬运 的密钥。

授权时会请求 public_repo scope —— 只对你的公开仓库有写权限。这是能干成 gitpic 这件事的最 窄 scope,因为 GitHub 没有"只给某一个仓库"这种 OAuth scope;而它也够了:link_kind = "cdn" 指向的 jsDelivr 只服务公开仓库。

图床仓库必须是公开仓库。GitPic 输出的是不携带 GitHub 凭据的可分享链接:jsDelivr 不服务私有仓库, 静态 raw.githubusercontent.com 地址也不会替访问者认证。即使扩大 OAuth scope 能把文件写进私有仓库, 上传也会在首个 PUT 前拒绝,避免留下“提交成功、链接 404”的结果。

gitpic auth login 登录成功后会直接把这枚凭据能上传的仓库列出来让你选,选中的那个连默认分支一起 落盘 —— 不用再跑第二条命令。gitpic repos 是之后想再看一眼时用的(带默认分支、是否私有、能不能写;选择器只提供 公开且可写的仓库),gitpic branches 则是看某个仓库有哪些分支。

想指向自己注册的 OAuth App 就设 GITPIC_CLIENT_ID,或 gitpic auth login --client-id <id>;scope 同样可以用 GITPIC_SCOPE 覆盖。

为什么不用 GitHub App?GitHub App 的权限更窄 —— 可以只给某一个仓库 Contents: write,比 public_repo 精确得多。它输在流程上:GitHub App 的 user token 只能访问 App 被安装过的仓库, 而 device flow 不会顺带完成安装。那意味着每个用户都得先在终端授权、再去浏览器把 App 装到自己账号上 并勾选仓库。"登录完立刻就有一个列表可选"比"更紧的授权但一半人走不完"更值。

以下三条路都已经删掉了,不是"不推荐":

  • gh auth token。两个来源就是两个身份:装了 gh 的机器上,一次上传算在谁头上取决于某个文件 在不在,而每个凭据错误都有两种解释要讲。它还让 gh 成了事实上的依赖 —— 而这件事 gitpic 现在自己 一条命令就做完了。
  • 粘贴 token(--with-token。手工搬运的 token 会留在 shell history、scrollback、聊天记录里, 而且它让 AI 助手可以要求用户"把 token 贴进对话"。device flow 不需要任何密钥经过人手。
  • GITPIC_TOKEN 和配置里的 github.token。环境变量里的凭据会漏进进程列表和 CI 日志;配置文件 里的会被 gitpic config get 打印出来。配置里还留着 token 行的话会报 CONFIG_INVALID —— 删掉它。

只剩一个来源,也就没有"来源"可报了:doctorauth status 都不再有 token_source 字段。

退出码与 --json

0 成功 · 1 其他错误 · 2 参数错误 · 3 缺少设置 · 4 认证失败 · 5 网络错误 · 6 本地 文件不存在 · 7 权限不足 · 8 远端资源不存在 · 9 请求过于频繁 · 10 配置文件无法使用。

3 是"还没配"(跑 gitpic auth login,或 gitpic config set github.repo owner/name),10 是 "配了但文件有问题"(跑 gitpic config edit)—— 处理方式不同,所以分开两个码。

--json 在每个子命令上都返回带 ok 的信封,失败也一样,三个例外:gitpic auth login --json流式的 —— 每行一个带 event 字段的完整 JSON 对象(code 带一次性码,最后一行一定是 doneerror),因为一次性码必须在"等浏览器"之前就发出去,而一个信封只能写一次。这是 App 能把登录做进设置 窗口的原因,也是唯一一处不遵守"一次调用一个信封"的地方,所以脚本和 AI 助手不该调它。另外 gitpic completion <shell> 忽略 --json、照打 shell 脚本;gitpic config edit 则在 --json直接拒掉USAGE)—— 它要把 stdout 交给编辑器,没法同时是一份 JSON。要读配置用 gitpic config get --json,要改用 gitpic config set。编辑器取 $VISUAL、再取 $EDITOR, 带参数的写法(EDITOR="code --wait")也能用。参数解析错误在 --json 下同样是 { "ok": false, "error": … }

AI 助手技能

gitpic 自带一份 Agent Skill,告诉 Claude Code、Codex 等助手怎么 调用它。技能文档编进了二进制,所以装上的版本永远和你正在跑的 gitpic 一致。

使用 GitPic.app 时也可以打开「设置 ▸ Agent」,分别管理 Claude Code、Codex 与通用 Agent:查看各自 是未安装、有差异还是已是最新,并单独安装或更新;替换一份有差异的 SKILL.md 前,App 会先确认。

gitpic skill install                 # 从检测到的助手里选
gitpic skill install --agent codex   # 或指定一家
gitpic skill install --agent generic # 通用 Agent(~/.agent/skills)
gitpic skill install --dir DIR       # 或指定任意 skills 目录
gitpic skill install --agent codex --force # 检查后替换有差异的文件
gitpic skill print                   # 打到 stdout

自动检测 ~/.claude/skills~/.codex/skills~/.agent/skills(分别尊重 CLAUDE_CONFIG_DIRCODEX_HOMEAGENT_HOME),写入前先问。脚本和 CI 里请加 --yes--agent--dir —— 没有终端时它会报错而不是替你猜。已有 SKILL.md 内容不同时,CLI 会保留原文件并报错;检查后只有显式传入 --force 才会替换。App 会在确认对话框之后代为传入。

也可以作为插件装:

/plugin marketplace add tarnish233/gitpic      # Claude Code
/plugin install gitpic@gitpic
codex plugin marketplace add tarnish233/gitpic  # Codex
codex plugin add gitpic@gitpic

给助手的两条约定:调用时始终带 --json;上传命令加 --no-copy--no-copy 只对上传路径 (gitpic <文件>--stdinpaste)有意义,其余子命令会把它当 USAGE(退出码 2)拒掉 —— gitpic doctor --json --no-copy 是会失败的。

gitpic doctor 在任一检查失败时返回非零退出码,但脚本仍应解析 JSON 里的 config_oktoken_validrepo_writable:不健康的报告会带上与其他子命令同形的 error 对象,所以"分支不 存在"(8)和"没有写权限"(7)从 stdout 就能分开,不必依赖退出码 —— 一旦管进 jq,退出码就变成 jq 自己的了。

token_validrepo_writable 有三种取值:truefalse,以及没查过时的 null。 两个 GitHub 检查只在 config_ok 为真时才发,所以"已经 gitpic auth login、还没挑仓库" 的机器上它们是 null —— 之前报 false,那是在替一份根本没人看过的凭据下结论,而 gitpic auth status 在同一台机器上说它是好的。

更新日志

中文更新日志;英文版见 CHANGELOG.md

许可证

MIT

About

GitHub 图床命令行工具:上传本地或剪贴板图片,生成 Markdown 链接,并提供适合脚本与 AI 助手调用的 JSON 模式。

Topics

Resources

Stars

22 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages