shell脚本无干扰自动更新本地所有仓库 附macOS下的自动执行方案

我有点收藏癖,平日发现好的仓库喜欢拉一个放在本地,以前用GUI工具一段时间拉一下,而且在日常开发过程中,管理多个Git仓库并保持其同步更新可能会变得繁琐,尤其是当远程仓库的URL或协议发生变化时。手动操作不仅耗时,还容易出错。因此,我们需要一个自动化解决方案,来简化这一过程。

问题

  1. 多个仓库手动更新困难:频繁切换目录并手动执行git pull,容易遗漏某些仓库。
  2. 远程仓库访问失败:远程仓库的协议或URL可能会发生变化,导致更新失败。
  3. 不必要的文件占用空间:开发过程中产生的缓存和历史文件会占用磁盘空间。

解决思路

我们可以通过编写一个自动化脚本,批量处理多个Git仓库的更新任务,同时加入对远程仓库的可访问性检查。如果HTTPS协议失败,可以自动切换到Git协议,如果仓库失效或需要登录,则跳过,而不是询问登录或等着让输出账号密码

解决方案

这个Bash脚本实现了以下功能:

  1. 批量更新Git仓库:通过遍历本地所有的.git目录,自动执行git pull更新操作,确保所有项目始终保持最新。
  2. 远程仓库状态检测:使用curl检测远程仓库的可访问性,自动处理301、302重定向,并根据状态码决定是否执行更新操作。
  3. 协议切换:如果HTTPS协议无法更新,脚本会尝试切换到Git协议,确保最大限度完成更新任务。

以下是完整的Shell脚本,它会自动查找并更新本地所有Git仓库,你在使用此脚本的时候,记得修改/dev/source/git路径:

#!/bin/bash

# 定义颜色
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m' # 无颜色

# 确保凭证永久存储在本地文件中
git config --global credential.helper store

# 切换到目标目录
cd /dev/source/git || { echo -e "${RED}无法切换到目标目录${NC}"; exit 1; }

# 查找所有的.git目录
find . -type d -name ".git" | while read -r git_dir
do
  # 切换到.git目录所在的上一级目录
  repo_dir=$(dirname "$git_dir")
  cd "$repo_dir" || { echo -e "${RED}无法进入目录: $repo_dir,跳过此仓库${NC}"; continue; }

  # 获取当前目录路径
  CURRENT_DIR=$(pwd)
  echo -e "${CYAN}当前路径: $CURRENT_DIR${NC}"

  # 检查是否存在.git目录
  if [ -d ".git" ]; then
    # 获取远程仓库URL
    remote_url=$(git config --get remote.origin.url)
    
    # 检查远程仓库是否可访问
    http_status=$(curl -I -s -o /dev/null -w "%{http_code}" "$remote_url")

    # 仅在状态码为200时进行拉取操作
    if [ "$http_status" -eq 200 ]; then
      echo -e "${GREEN}远程仓库可访问,状态码: ${http_status},开始拉取更新${NC}"
      git pull --quiet
      if [ $? -ne 0 ]; then
        echo -e "${YELLOW}HTTPS协议拉取失败,尝试使用git协议${NC}"
        git_url="${remote_url/https:\/\//git@}"
        git_url="${git_url/\//:}"
        git remote set-url origin "$git_url"
        git pull --quiet
        if [ $? -ne 0 ]; then
          echo -e "${RED}git协议拉取仍然失败,跳过此仓库${NC}"
        else
          echo -e "${GREEN}使用git协议更新成功${NC}"
        fi
      else
        echo -e "${GREEN}HTTPS协议更新成功${NC}"
      fi
    elif [ "$http_status" -eq 301 ] || [ "$http_status" -eq 302 ]; then
      # 如果状态码为301或302,则去掉URL末尾的.git再试一次
      echo -e "${YELLOW}远程仓库状态码: ${http_status},尝试去掉.git后重新获取状态${NC}"
      trimmed_url="${remote_url%.git}"
      http_status_trimmed=$(curl -I -s -o /dev/null -w "%{http_code}" "$trimmed_url")

      if [ "$http_status_trimmed" -eq 200 ]; then
        echo -e "${GREEN}去掉.git后的URL可访问,状态码: ${http_status_trimmed},开始拉取更新${NC}"
        git remote set-url origin "$trimmed_url"
        git pull --quiet
        if [ $? -ne 0 ]; then
          echo -e "${RED}发生错误,跳过此仓库${NC}"
        else
          echo -e "${GREEN}更新成功${NC}"
        fi
      else
        echo -e "${RED}去掉.git后的URL仍不可访问,状态码: ${http_status_trimmed},跳过此仓库${NC}"
      fi
    else
      echo -e "${RED}远程仓库状态码: ${http_status},跳过此仓库${NC}"
    fi
  else
    echo -e "${YELLOW}.git目录不存在,跳过此仓库${NC}"
  fi
    
  # 返回上级目录,继续处理下一个.git目录
  cd - > /dev/null || { echo -e "${RED}无法返回上级目录,脚本中止${NC}"; exit 1; }
done

exit 0 

macOS下定时运行此脚本 使用launchd定时任务
1.创建一个.plist文件来描述定时任务。使用如下内容创建net.lvtao.gitupdate.plist文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>net.lvtao.gitupdate</string>
    <key>ProgramArguments</key>
    <array>
        <string>/dev/source/git/up.sh</string>
    </array>
    <key>StartInterval</key>
    <integer>10800</integer> <!-- 每3小时执行一次,3小时=10800秒 -->
    <key>StandardOutPath</key>
    <string>/dev/source/git/log.log</string>
    <key>StandardErrorPath</key>
    <string>/dev/source/git/error.log</string>
</dict>
</plist>

2.将此文件放置在~/Library/LaunchAgents/目录下,并使用以下命令加载任务:
launchctl load ~/Library/LaunchAgents/net.lvtao.gitupdate.plist

好了,这样我们这个脚本就可以每三小时执行一次了

标签: Git

相关文章

Git导出版本之间差异文件

查看 commit id首先用 git log 查看版本库日志,找出需要导出的 commit idgit log --pretty=oneline456bcbccd91278f7fdf6bf11...

图片Base64编码

CSR生成

图片无损放大

图片占位符

Excel拆分文件