服务器上想自动拉最新代码,写个脚本挂 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 main
2. 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.sh
3. 分支不明确
裸 git pull 会走当前分支和默认 remote,可能拉到不该拉的分支。永远显式:
git -C "$REPO" pull origin main
处理本地修改的完整版
生产脚本上还得防几件事:
#!/bin/bash
set -e
REPO=/www/wwwroot/yourproject
BRANCH=main
cd "$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.php
Linux 上拉下来会真的多出两个文件,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 防脏树。
