gitops

package
v0.5.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 12, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Overview

Package gitops 封裝所有 git 操作,根據 workspace config 決定 monorepo 或 multi-repo 模式。

Index

Constants

View Source
const ReviewPackageTruncatedMarker = "> review-package truncated"

ReviewPackageTruncatedMarker 是 review-package 變更檔全文因超過上限而截斷時, 於「Changed File Contents」段開頭放置的檔頭標註起頭字串。orchestrator 以 strings.Contains 偵測此標記記一筆截斷 log(非靜默)。

Variables

This section is empty.

Functions

func ApplyWorktreeEnv added in v0.5.0

func ApplyWorktreeEnv(env []string, root string) []string

ApplyWorktreeEnv 對「在 root 執行子程序」的環境變數注入 worktree 隔離設定。 root 非 linked worktree(主工作區、非 git 目錄)時原樣回傳,行為不變。

linked worktree 時:

  • GOLANGCI_LINT_CACHE 指向 worktree-local 目錄,避免 golangci-lint 快取殘留 sibling worktree 路徑造成跨 worktree 的 lint 誤報。GOCACHE 刻意不隔離: go build cache 是 content-addressed、與路徑無關,共享可加速 worktree build。
  • worktree 內存在可執行的 bin/4x 時(4x 自我開發情境),FOURX_BIN 覆寫為該 worktree-local binary 並把其目錄 prepend 到 PATH,讓 guard-tool hook 與 agent 手測用的都是 feature branch 剛 build 的版本,而非主工作區的舊 binary。 os/exec 對重複 env key 以最後一筆為準,故以 append 覆寫先前的 FOURX_BIN。

func Branch

func Branch(featureID string) string

Branch 回傳 feature 對應的 branch 名稱(兩種模式共用)。

func ChangedPaths added in v0.5.0

func ChangedPaths(dir string) []string

ChangedPaths 回傳 dir(一個 git 工作目錄)內 tracked+untracked 變更檔案的相對路徑清單 (git diff --name-only HEAD ∪ untrackedFiles)。只回路徑、不含行數,供只需要「哪些檔案變了」 的呼叫端(scope-violation 偵測、symlink 偵測等)共用同一份 git 偵測邏輯,取代各自重新實作 同一組指令、日後各自漂移(見 code review Finding [8])。 兩條指令各自獨立容錯,單一失敗不影響另一條已找到的變更,與 changedFilesIn 語意一致。

func CopyDirIfNewer added in v0.3.11

func CopyDirIfNewer(srcDir, dstDir string) error

CopyDirIfNewer 遞迴複製 srcDir 底下所有檔案到 dstDir,每個檔案套用 CopyFileIfNewer 的 mtime 比對語意;用於 worktree round 產物同步,讓 agent 動態產生的子目錄(如截圖) 不會因為只複製頂層檔案的白名單邏輯而被靜默丟棄。來源目錄不存在視為靜默成功。

func CopyFileIfExists

func CopyFileIfExists(src, dst string) error

CopyFileIfExists 複製檔案,來源不存在時靜默忽略(回 nil);讀寫失敗回傳 error。供外部 package 使用。

func CopyFileIfNewer

func CopyFileIfNewer(src, dst string) (copied bool, err error)

CopyFileIfNewer 僅在來源比目標新(或目標不存在)時複製,用於差量化 worktree sync, 避免每輪 final sync 與每 2 秒 live-sync 對未變更檔案重複全量複製。 回傳是否實際複製、以及錯誤;來源不存在視為靜默成功(false, nil)。 比對採 mtime-only:dst 不存在則複製;兩者皆存在時 srcInfo.ModTime().After(dstInfo.ModTime()) 才複製。

func CountFileLines added in v0.3.1

func CountFileLines(path string) int

CountFileLines 回傳檔案的行數(以 '\n' 計),讀檔失敗回 0。 末行無換行時補計 1 行,使單行無換行的檔案計為 1 而非 0。

func Dir

func Dir(root, featureID string) string

Dir 回傳 worktree 組合目錄的路徑(兩種模式共用)。

func HeadCommit added in v0.3.14

func HeadCommit(dir string) string

HeadCommit 回傳 dir 所在 git 工作目錄目前的 HEAD commit sha,非 git repo 或指令失敗時回空字串。

func MainWorkspaceRoot added in v0.5.1

func MainWorkspaceRoot(dir string) (string, bool)

MainWorkspaceRoot 回傳 dir 所屬 linked worktree 對應的「主工作區 root」(main working tree 根目錄)。

判定方式:委派 DetectWorktree 取得已正規化的 common dir 與 linkage 判定(避免第二份重複判定), 對 linked worktree 取其 CommonDir 的上一層即主工作區 root。dir 本身就是主工作區(git-dir == common-dir、非 linked worktree)時回傳 ok=false。

fail-open 邊界:本 API 只提供「可證明的主工作區 root」。dir 非 git repo、git 不在 PATH、或 git rev-parse 子程序失敗時,DetectWorktree 回 ok=false 或 IsLinked=false,本函式回 ok=false; 呼叫端在 ok=false 時必須維持原本放行(不得阻斷工具),僅在 ok=true 時才據以做 fail-closed deny。

func ParseNumstatCount added in v0.3.1

func ParseNumstatCount(s string) int

ParseNumstatCount 解析 numstat 的 added/deleted 欄位,binary 檔的 "-" 視為 0。

func ScopeRoot added in v0.1.13

func ScopeRoot(fallback, featureID string) string

ScopeRoot 回傳掃描 feature scope 變更時應使用的根目錄。 若 feature 的 worktree 目錄存在且確為 linked worktree,回傳其 top-level 根目錄; 否則回退到 fallback(通常為 main workspace 根),維持非 worktree 情境的既有行為。

func ScopeRoots added in v0.3.7

func ScopeRoots(fallback, featureID string) []string

ScopeRoots 回傳掃描 feature scope 變更時應使用的根目錄清單,涵蓋 multi-repo 情境。

feature 的 worktree 容器目錄(Dir(fallback, featureID))在 mono-repo 下本身就是 linked worktree;在 multi-repo 下容器目錄不是 git repo,各 sub-repo 的 linked worktree 是其子目錄(見 multiRepo.SetupWorktree)。對容器目錄整體判定 IsLinked 在 multi-repo 下會誤判為 false(git 往上層找到主 repo),故容器本身非 linked worktree 時進一步掃描子目錄,逐一判定是否為 linked worktree。

mono-repo(含非 worktree 情境)回傳結果恆為單元素 slice,與 ScopeRoot 回傳值一致, 呼叫端對其迭代等同執行一次,行為不變。

Types

type MergeResult

type MergeResult struct {
	Skipped      bool
	Conflict     bool
	Error        string
	Files        []string
	ConflictRepo string
	StateChanged bool
	FinalState   protocol.State
	// MRUrls 記錄 PushAndOpenMR 成功開出的 MR/PR URL,key 為 monorepo 固定 "."、multirepo 為 repo 名。
	MRUrls map[string]string
}

MergeResult 描述 Merge 操作的結果。

StateChanged 與 FinalState 由 MergeAndFinalize 在 merge 後填入:StateChanged 表 merge 期間 state.json 的 phase 已非 pending-review(未 finalize),FinalState 為成功 finalize 後寫入的最新 state (或 StateChanged 時偵測到的當下 state)。Merge 本身不設定這兩個欄位。

func MergeAndFinalize added in v0.2.4

func MergeAndFinalize(root string, ws *protocol.Workspace, cfg protocol.Config, featureID, featureName string) (MergeResult, error)

MergeAndFinalize 承載 CLI(cmd/4x/done.go autoMergeFeature)與 server (internal/server/server.go handlePostDone)原本各自實作的 merge+done 編排,是兩端共用的 唯一真實來源:ops.Merge(或 cfg.IssueTracker.Enabled 時改走 ops.PushAndOpenMR,done 語意 變成「已開 MR」而非「已合併」)→ 成功時重讀最新 state 確認仍為 pending-review → state.FinalizeDone → learning.CommitIfDirty。

重讀 state 是為了保留 server 的防 stale 覆寫不變式:merge 可能耗時數秒,期間 runner 或 ensureInactive 可能改過 state.json,若用 merge 前的 stale 值 finalize 會覆蓋其他欄位更新。 CLI 單程序下沒有並行 writer,重讀為 no-op,安全。

結果以回傳值的組合表達,讓 CLI 與 server 各自決定後續:

  • (MergeResult{Conflict:true}, nil) → merge 衝突,未 finalize,呼叫端維持 pending-review
  • (MergeResult{Error:!=""}, nil) → 非衝突 merge 錯誤,未 finalize,呼叫端警告並維持 pending-review
  • (MergeResult{StateChanged:true}, nil) → merge 後 phase 已非 pending-review,未 finalize(server 回 409)
  • (result, err) err!=nil → 重讀 state 或 finalize 真正失敗(fatal,server 回 500)
  • (MergeResult{FinalState:done}, nil) → 成功 finalize 為 done,Skipped 表非 worktree 模式, 或 issue_tracker.enabled 時 PushAndOpenMR 判定 worktree 存在但無 committed 變更可開 MR

並行鎖(server 的 mergeMu)由呼叫端負責包住本函式;CLI 單程序無需鎖,本函式不持鎖。

type Ops

type Ops interface {
	SetupWorktree(featureID string, featureRepos []string) (wtRoot string, err error)
	Commit(wtRoot, featureID, msg string) error
	Merge(featureID, featureName string) MergeResult
	// PushAndOpenMR 取代 Merge,push feature branch 並對有 committed 變更的 repo 開 MR/PR,
	// 供 issue_tracker.enabled 時的 `4x done` 使用(見 MergeAndFinalize)。
	PushAndOpenMR(featureID, featureName string) MergeResult
	Cleanup(featureID string) error
	DetectChangedRepos(featureID string) []string
	DetectChangedFiles(featureID string) []protocol.ChangedFile
	CaptureBaseline(featureID string, featureRepos []string) error
	IsMultiRepo() bool
	// GenerateReviewPackage 回傳 baseCommit..HEAD 的 commits/file-stat/full-diff 彙整 markdown,
	// 供 orchestrator 在 coding/amending → reviewing 轉換時預算寫成 review-package.md,
	// 讓 reviewer/deep-reviewer 讀檔取代自跑 git diff。baseCommit 或 diff 產出皆為空時回傳 error,
	// 呼叫端應 fallback 跳過寫檔,讓 role 走 template 既有的自跑 git diff 路徑。
	GenerateReviewPackage(featureID, baseCommit string) (string, error)
}

Ops 封裝所有 git 操作,根據 workspace config 決定 monorepo 或 multi-repo 模式。

func New

func New(root string, ws *protocol.Workspace, cfg protocol.Config) Ops

New 根據 workspace config 建立對應的 Ops 實作。

type WorktreeInfo added in v0.1.13

type WorktreeInfo struct {
	// Root 是該目錄所屬 worktree 的 top-level 根目錄(git rev-parse --show-toplevel)。
	Root string
	// IsLinked 為 true 表示這是 git worktree add 產生的 linked worktree;
	// false 表示主工作區(main working tree)。
	IsLinked bool
	// CommonDir 是已正規化(絕對 + EvalSymlinks)的 git common dir(linked worktree 指向
	// 主工作區的 .git)。dir 非 git repo 時為空字串。MainWorkspaceRoot 以此推導主工作區 root,
	// 避免重複一份 linkage 判定。
	CommonDir string
}

WorktreeInfo 描述某個目錄所屬的 git worktree 狀態。

func DetectWorktree added in v0.1.13

func DetectWorktree(dir string) (WorktreeInfo, bool)

DetectWorktree 偵測 dir 所屬的 git worktree,回傳其 top-level 根目錄與是否為 linked worktree。

scope 檢查在 worktree 隔離模式下,git 操作的根目錄會被解析到 main workspace, 導致誤把 main 的未提交變更算進 feature 的 changed repos。此 helper 讓呼叫端能 把 git 操作限定在 worktree 自身的根目錄。

判定方式:以 git rev-parse --git-dir 與 --git-common-dir 是否相異判定是否為 linked worktree(linked worktree 的 git-dir 指向 <common>/.git/worktrees/<name>,與 common dir 不同)。dir 不在 git repo 內時回傳 ok=false。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL