chore: git_push_dlp 改 robocopy 增量镜像(固定 stage 复用,只复制变动文件)

This commit is contained in:
p40000043244@byd.com
2026-07-31 18:13:44 +08:00
parent e0f1db75c2
commit a458270fa7
2 changed files with 26 additions and 23 deletions
+8 -7
View File
@@ -20,11 +20,12 @@ fatal: not a git repository (or any of the parent directories): .git
## 原理 ## 原理
1. `xcopy .git``%TEMP%\git_push_dlp\<repo>-<random>\`(保护区外,授权进程 1. `robocopy /MIR .git`固定 stage 目录 `%TEMP%\git_push_dlp\<repo>\`(保护区外,
读出明文,写出不再加密)。默认通过 `/EXCLUDE` 排除 `.git\lfs`LFS 对象 授权进程读出明文,写出不再加密)。stage 目录跨运行保留:首次全量镜像,
缓存,动辄数 GB,普通提交 push 不需要)。 之后每次 push 只复制变动的文件。默认通过 `/XD lfs` 排除 `.git\lfs`LFS
对象缓存,动辄数 GB,普通提交 push 不需要)。
2. 在 stage 副本里执行 `git push` 2. 在 stage 副本里执行 `git push`
3. 回到原仓库 `git fetch` 同步远程跟踪引用,然后删除 stage 3. 回到原仓库 `git fetch` 同步远程跟踪引用。stage 目录保留不删,供下次增量复用
## 使用方法 ## 使用方法
@@ -45,9 +46,9 @@ set GIT_PUSH_DLP_WITH_LFS=1
## 排障 ## 排障
- **`[ERROR] xcopy .git failed. Insufficient disk space`**TEMP 所在盘空间不足。 - **`[ERROR] robocopy .git failed`**常见于 TEMP 所在盘空间不足。stage 目录
先清理 `%TEMP%\git_push_dlp\` 下历史失败残留的 `TestHub-*` 目录(脚本在 跨运行复用(`%TEMP%\git_push_dlp\<repo>\`),旧版本脚本留下的 `<repo>-<数字>`
xcopy 失败时不会自动清理)。仍不足时确认是否误设了 残留目录可以整体删除。仍不足时确认是否误设了
`GIT_PUSH_DLP_WITH_LFS`(全量 lfs 可能超过盘符剩余空间)。 `GIT_PUSH_DLP_WITH_LFS`(全量 lfs 可能超过盘符剩余空间)。
- **stage 在 E: 盘也报 128**:整个 E: 盘都在 DLP 拦截范围内,stage 必须落在 - **stage 在 E: 盘也报 128**:整个 E: 盘都在 DLP 拦截范围内,stage 必须落在
C:`%TEMP%` 默认位置),不要把 `TEMP` 指到 E:。 C:`%TEMP%` 默认位置),不要把 `TEMP` 指到 E:。
@@ -5,8 +5,11 @@ rem Push from a DLP-protected (transparent-encrypted) directory where
rem "git push" fails with: fatal: not a git repository rem "git push" fails with: fatal: not a git repository
rem rem
rem How it works: rem How it works:
rem 1. xcopy .git to a stage dir under %TEMP% (outside the protected zone, rem 1. Mirror .git to a fixed per-repo stage dir under %TEMP% with
rem an authorized process reads plaintext, no re-encryption outside). rem robocopy /MIR (outside the protected zone, an authorized process
rem reads plaintext, no re-encryption outside). The stage dir is kept
rem between runs, so after the first full mirror only changed files
rem are copied on subsequent pushes.
rem 2. Run "git push" from the stage dir. rem 2. Run "git push" from the stage dir.
rem 3. Run "git fetch" in the original repo to sync remote-tracking refs. rem 3. Run "git fetch" in the original repo to sync remote-tracking refs.
rem rem
@@ -16,8 +19,9 @@ rem git_push_dlp origin main = git push origin main
rem git_push_dlp upstream main:main = any normal push args rem git_push_dlp upstream main:main = any normal push args
rem rem
rem Env vars: rem Env vars:
rem GIT_PUSH_DLP_WITH_LFS=1 = also copy .git\lfs (needed only when rem GIT_PUSH_DLP_WITH_LFS=1 = also mirror .git\lfs (needed only
rem the push contains new LFS objects) rem when the push contains new LFS
rem objects)
rem ========================================================================== rem ==========================================================================
setlocal EnableExtensions EnableDelayedExpansion setlocal EnableExtensions EnableDelayedExpansion
chcp 65001 >nul chcp 65001 >nul
@@ -28,24 +32,24 @@ if not exist ".git\" (
) )
for %%I in ("%CD%") do set "REPO_NAME=%%~nxI" for %%I in ("%CD%") do set "REPO_NAME=%%~nxI"
set "STAGE=%TEMP%\git_push_dlp\%REPO_NAME%-%RANDOM%%RANDOM%" set "STAGE=%TEMP%\git_push_dlp\%REPO_NAME%"
echo [DLP] Stage dir: %STAGE% echo [DLP] Stage dir: %STAGE%
rem .git\lfs is the LFS object cache (often several GB); normal commits do rem .git\lfs is the LFS object cache (often several GB); normal commits do
rem not need it for push. Excluding it avoids xcopy disk-space failures. rem not need it for push. Excluding it avoids filling up the TEMP drive.
rem If this push contains new/changed LFS files, set GIT_PUSH_DLP_WITH_LFS=1 first. rem If this push contains new/changed LFS files, set GIT_PUSH_DLP_WITH_LFS=1 first.
set "EXCLUDE_OPT=" set "EXCLUDE_OPT=/XD lfs"
if not defined GIT_PUSH_DLP_WITH_LFS ( if defined GIT_PUSH_DLP_WITH_LFS set "EXCLUDE_OPT="
set "EXCLUDE_FILE=%TEMP%\git_push_dlp_exclude.txt" if defined GIT_PUSH_DLP_WITH_LFS (
> "!EXCLUDE_FILE!" echo \lfs\ echo [DLP] Including .git\lfs
set "EXCLUDE_OPT=/EXCLUDE:!EXCLUDE_FILE!" ) else (
echo [DLP] Excluding .git\lfs ^(set GIT_PUSH_DLP_WITH_LFS=1 to include^) echo [DLP] Excluding .git\lfs ^(set GIT_PUSH_DLP_WITH_LFS=1 to include^)
) )
xcopy /E /I /Q /H /Y %EXCLUDE_OPT% ".git" "%STAGE%\.git" >nul robocopy ".git" "%STAGE%\.git" /MIR %EXCLUDE_OPT% /NFL /NDL /NJH /NP >nul
if errorlevel 1 ( if errorlevel 8 (
echo [ERROR] xcopy .git failed. echo [ERROR] robocopy .git failed ^(exit %ERRORLEVEL%^).
exit /b 1 exit /b 1
) )
@@ -64,7 +68,6 @@ popd
if not "%EXIT_CODE%"=="0" ( if not "%EXIT_CODE%"=="0" (
echo [ERROR] push failed with exit code %EXIT_CODE% echo [ERROR] push failed with exit code %EXIT_CODE%
rmdir /s /q "%STAGE%" 2>nul
exit /b %EXIT_CODE% exit /b %EXIT_CODE%
) )
@@ -72,7 +75,6 @@ echo [DLP] Sync back: git fetch %REMOTE%
git fetch %REMOTE% git fetch %REMOTE%
set "FETCH_CODE=%ERRORLEVEL%" set "FETCH_CODE=%ERRORLEVEL%"
rmdir /s /q "%STAGE%" 2>nul
if not "%FETCH_CODE%"=="0" ( if not "%FETCH_CODE%"=="0" (
echo [WARN] push succeeded but fetch back failed with exit code %FETCH_CODE% echo [WARN] push succeeded but fetch back failed with exit code %FETCH_CODE%
exit /b %FETCH_CODE% exit /b %FETCH_CODE%