Showing Posts From

Git

Shell 自动化部署脚本:git pull + pnpm build + cp

一个用于静态站点(如 Astro / Next.js)的最小化自动化部署脚本,适合 VPS 手动触发或配合 webhook 使用。 脚本 #!/bin/bash set -ecd /opt/black-no-dark git pull pnpm build cp -rf /opt/black-no-dark/dist/* /www/wwwroot/www.example.com/echo "更新成功!"各步骤说明 set -e:任何命令返回非零退出码时立即终止脚本,防止后续步骤在错误状态下继续执行。 git pull:拉取远程最新代码。若本地有未提交的修改会冲突报错,此时 set -e 会阻止继续构建。 pnpm build:构建静态产物到 dist/ 目录。构建失败(TS 错误、配置错误等)同样会终止。 cp -rf dist/* /web-root/:将新产物覆盖到 Web 服务器根目录。-r 递归,-f 强制覆盖。 使用方式 # 赋予执行权限(只需一次) chmod +x /opt/deploy.sh# 手动触发 /opt/deploy.sh# 或配合 webhook(如 github-webhook-handler)自动触发常见问题 git pull 报 "not a git repository":脚本中的 cd 路径写错,或目录没有 git init / git clone。 pnpm: command not found:部署环境没有安装 pnpm,或 PATH 不包含 pnpm 路径。解决: # 用绝对路径 /root/.local/share/pnpm/pnpm build# 或在脚本顶部加 export PATH="/root/.local/share/pnpm:$PATH"cp 覆盖时网站短暂不可用:对于零停机要求,可以先 cp 到临时目录,再 mv 替换: cp -rf dist/* /tmp/dist-new/ rsync -a --delete /tmp/dist-new/ /www/wwwroot/www.example.com/rsync 只同步差异文件,比整体 cp 更快,中断窗口更短。 扩展:加上日志和通知 #!/bin/bash set -eLOG=/var/log/deploy.log echo "[$(date '+%Y-%m-%d %H:%M:%S')] 开始部署" >> $LOGcd /opt/black-no-dark git pull >> $LOG 2>&1 pnpm build >> $LOG 2>&1 cp -rf dist/* /www/wwwroot/www.example.com/echo "[$(date '+%Y-%m-%d %H:%M:%S')] 部署成功" >> $LOG将 stdout / stderr 都重定向到日志文件,方便事后排查。

写个 Bash 自动 git pull:三种姿势和 cron 里的坑

服务器上想自动拉最新代码,写个脚本挂 cron 跑。看着就两行,实际上有几个必吃的坑。 最基础写法 #!/bin/bash cd /www/wwwroot/yourproject || exit 1 git pull|| exit 1:cd 失败就退出,不然当前目录是家目录,git pull 会执行在错误的仓库 保存为 pull.sh chmod +x pull.sh 执行 ./pull.sh更稳的写法:不依赖 cd git -C 可以直接指定仓库路径,省掉 cd 的失败风险: #!/bin/bash git -C /www/wwwroot/yourproject pull origin main同一个脚本要处理多个仓库时特别顺手。 挂 cron 时会踩的坑 */5 * * * * /www/wwwroot/scripts/pull.sh >> /var/log/pull.log 2>&1看着没问题,实际经常挂。原因: 1. SSH 密钥没加载 用户手动跑时有 ssh-agent。cron 里没有,git@github.com 直接拒绝。解法:走 HTTPS + PAT,别用 SSH 或在脚本里显式指定密钥:export GIT_SSH_COMMAND="ssh -i /root/.ssh/deploy_key -o StrictHostKeyChecking=no" git -C /www/wwwroot/yourproject pull origin main2. PATH 太窄 cron 的 PATH 只有 /usr/bin:/bin,找不到自定义安装的 git。crontab 里手动补: PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin */5 * * * * /www/wwwroot/scripts/pull.sh3. 分支不明确 裸 git pull 会走当前分支和默认 remote,可能拉到不该拉的分支。永远显式: git -C "$REPO" pull origin main处理本地修改的完整版 生产脚本上还得防几件事: #!/bin/bash set -eREPO=/www/wwwroot/yourproject BRANCH=maincd "$REPO"# 1. 如果本地有修改,暂存(避免 pull 失败) if [[ -n $(git status --porcelain) ]]; then echo "[$(date)] 本地有修改,先 stash" git stash push -m "auto-stash $(date +%s)" fi# 2. 拉最新 git fetch origin "$BRANCH" git reset --hard "origin/$BRANCH" # 直接对齐远程,别 merge# 3. 清空 stash(不还原,防止和拉下来的冲突) git stash clear注意 git reset --hard 会覆盖本地任何修改。这是刻意的——线上机器上不该有手改,任何修改都视为"意外"直接抹掉。要保守就用 git pull --ff-only。 大小写敏感的坑 服务器 Linux 大小写敏感,Windows / macOS 默认不敏感。仓库里同时存在: RiderAuditController.php RiderauditController.phpLinux 上拉下来会真的多出两个文件,Windows 上只能存一个,pull 立刻挂。 解法:清理仓库中的重名文件,用 git rm 保留一个: git rm --cached RiderauditController.php git commit -m "fix: 大小写重复" git push或者临时关掉大小写敏感(治标): git config core.ignorecase true一句话总结 git -C REPO pull origin BRANCH 是最省事的一行。挂 cron 要额外交代 PATH、SSH 密钥、分支名,生产脚本再套一层 reset --hard 防脏树。

Git 大小写文件名冲突:Windows/macOS 改名后出现重复文件

在 Windows 和默认 macOS 文件系统(大小写不敏感)上改文件名大小写,Git 不会把它识别为 rename,而是把两个文件都保留在仓库里。 症状 执行 git pull 时出现: warning: the following paths have collided (e.g. case-sensitive paths on a case-insensitive filesystem) and only one from the same colliding group is in the working tree: 'app/substation/controller/RiderAuditController.php' 'app/substation/controller/RiderauditController.php'原因 Git 内部是大小写敏感的,仓库里可以同时存在两个文件: RiderAuditController.php RiderauditController.php但 Windows(NTFS)和 macOS(APFS 默认)认为它们是同一个文件,检出时只能保留一个,发生碰撞。 通常是有人在 Windows 上直接改了文件名大小写,Git 把旧文件和新文件都提交进去了。 确认仓库状态 在任意环境执行: git ls-files | grep -i rideraudit如果输出两行就说明仓库里确实存在两个文件: app/substation/controller/RiderAuditController.php app/substation/controller/RiderauditController.php解决步骤(必须在 Linux 或 WSL2 上操作) Windows/macOS 文件系统无法同时持有两个大小写不同的文件,操作只能在大小写敏感环境中完成。 方案一:Linux 服务器(推荐) # SSH 到 Linux 服务器,确认两文件内容 diff app/substation/controller/RiderAuditController.php \ app/substation/controller/RiderauditController.php# 删除要废弃的文件(以删除大写版为例) git rm app/substation/controller/RiderAuditController.php git rm phalapi/src/rider/Model/RiderAudit.phpgit commit -m "fix: remove duplicate case-sensitive files" git push方案二:WSL2(Windows 用户) wsl cd /mnt/c/projects/your-repogit rm app/substation/controller/RiderAuditController.php git commit -m "fix: remove duplicate case-sensitive files" git pushpush 之后,Windows/macOS 成员再 git pull 就不会再有冲突。 如果两个文件内容不同 先比较差异: git diff --no-index \ app/substation/controller/RiderAuditController.php \ app/substation/controller/RiderauditController.php查看哪个是最新版本再决定保留哪个。也可以用 git log 看提交历史: git log --follow -- app/substation/controller/RiderAuditController.php git log --follow -- app/substation/controller/RiderauditController.php不推荐的绕过方式macOS 创建大小写敏感卷(APFS Case-sensitive) Windows 开启目录大小写敏感:fsutil file setCaseSensitiveInfo . enable这两种方式只解决当前机器的问题,团队里其他 Windows/macOS 开发者继续会出问题。根本解决办法是清理远程仓库中的重复文件。 PHP 框架的额外风险 PHP 的 PSR-4 自动加载依赖文件名映射,如果保留了小写文件名但代码里用的是大写类名: new Model_RiderAudit(); // 加载 RiderAudit.php在 Linux 上 autoloader 找不到文件会报 Class not found。 解决后建议全局搜索: grep -R "RiderAudit\|Rideraudit" . --include="*.php"确认所有引用和文件名一致。

git pull --rebase 报 unstaged changes 的四种处理方法

报错场景 git pull --rebase输出: error: cannot pull with rebase: You have unstaged changes. error: please commit or stash them.这是 Git 在执行 rebase 前的保护机制:工作区有未提交修改时,rebase 可能覆盖这些改动,所以拒绝继续。 先确认修改范围: git status方案一:暂存后拉取再恢复(最常用) 保留改动,暂时藏起来: git stash git pull --rebase git stash popstash pop 会把改动重新应用到工作区。如果有冲突,手动解决后 git stash drop 清掉暂存记录。 查看所有 stash: git stash list # stash@{0}: WIP on main: abc1234 last commit message恢复指定 stash(保留记录): git stash apply stash@{0}方案二:提交后再 rebase 如果改动已经完整,直接提交: git add . git commit -m "WIP: 临时提交" git pull --rebaserebase 会把这次提交放在远端最新提交之后,之后可以 git commit --amend 修改提交信息或 git rebase -i HEAD~2 整理提交记录。 方案三:丢弃本地修改 如果这些修改确定不要了: git reset --hard HEAD git pull --rebase如果还有未跟踪的文件也想清掉: git clean -fdreset --hard 和 clean -fd 都是不可逆操作,请确认后执行。方案四:开启自动 stash(推荐长期配置) 新版 Git 支持 --autostash 标志,在 rebase 前自动暂存、完成后自动恢复: git pull --rebase --autostash一次性使用;也可以永久开启: git config --global rebase.autoStash true开启后 git pull --rebase 自动执行以下流程: stash → pull --rebase → stash pop场景速查情况 推荐方案改动要保留,不想提交 stash → pull → stash pop改动完整,可以提交 commit → pull --rebase改动不需要了 reset --hard → pull日常频繁拉取 rebase.autoStash = true常见追问 stash pop 有冲突怎么办? 手动解决冲突后: git add <冲突文件> git stash drop # 清掉 stash 记录为什么不直接 git pull 而是 --rebase? git pull 默认是 fetch + merge,会产生 merge commit;--rebase 把本地提交移到远端之后,保持线性历史,更干净。 git stash 会暂存未跟踪文件吗? 默认不会。加 -u 参数: git stash -u # 包含 untracked files git stash -a # 包含 untracked + ignored files