【Treeman】Git相關
【GitLab】相關
【GitLab】gitlab-runner 執行環境種類
下面整理成表格給你(主流可用的 executor):
Executor
運作方式
優點
缺點
適用情境
設定/註冊要點
shell
直接在 Runner 主機的 shell 執行(bash / PowerShell)
最快、零容器開銷;可直接用主機已安裝工具
隔離最弱、容易「弄髒」主機;多專案易衝突
單機/內網、快速 smoke test、固定工具鏈
gitlab-runner register --executor shell;確保 gitlab-runner 使用者權限(如加入 docker 群組)與 builds_dir 可寫
docker
每個 job 以容器執行;image: 可指定環境
環境可重現、隔離佳、跨專案穩定
需管理映像;使用 Docker 需選擇掛 docker.sock 或 DinD
大多數 CI/CD 場景(前後端 build、容器化)
--executor docker --docker-image ;若 job 需 docker build:① 掛 /var/run/docker.sock,或 ② DinD:privileged=true + services: docker:dind
kubernetes
每個 job 建一個 Pod 來跑
彈性擴縮、資源/隔離/配額完善
需 K8s 叢集與維運成本
中大型團隊、尖峰負載、雲原生
--executor kubernetes;於 config.toml 設 namespace、serviceAccount、pull secrets 等
ssh
Runner 透過 SSH 登入遠端主機執行
可用現成遠端環境、無需在目標機器裝 Runner
隔離弱、擴展性差、權限管控要嚴格
特定機器/設備、臨時需求
--executor ssh;於 config.toml 填 host/user/key、路徑與環境
custom
以自訂腳本(prepare/run/cleanup)對接任意執行環境
彈性最高、可接非官方平台
需自寫與維護整套腳本,診斷較複雜
特殊平台、內部排程器
--executor custom;提供自訂 hook 腳本並測好錯誤處理
【GitLab】升級相關
升級路徑https://gitlab-com.gitlab.io/support/toolbox/upgrade-path/【GitLab】runner 使用 k8s 流程說明
一、前置條件
已有可用的 Kubernetes 叢集(kubectl/helm 可連通)
GitLab 可連到 Runner(你的 GitLab URL 例:http://10.2.11.139)
在 GitLab 介面建立 Runner(Project/Group/Instance → CI/CD → Runners → New runner),取得 Authentication Token(glrt-...)
二、建立命名空間
kubectl create namespace gitlab-runner # 放 Runner 本體
kubectl create namespace ci-jobs # job 跑的位置(也可與上面同一 ns)
三、用 Helm 裝 Runner(K8s executor)
加入 chart
helm repo add gitlab https://charts.gitlab.io
helm repo update
建一份 values.yaml
gitlabUrl: "http://10.2.11.139/"
# 新流程建議用 runnerToken(glrt-...)
runnerToken: "glrt-xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
rbac:
create: true
serviceAccount:
create: true
name: gitlab-runner
runners:
executor: kubernetes
# job 要跑在哪個 ns;不填則跟 Runner 同 ns
namespace: ci-jobs
# 預設 job 容器用什麼 image(可被 .gitlab-ci.yml 的 image 覆蓋)
image: alpine:3.20
pollTimeout: 180
# 是否允許特權容器(多數情況不需要,建議先關)
privileged: false
# 幫 job Pod 加上標籤(可選)
podLabels:
app: gitlab-ci-job
# 預設資源限制(可選)
resources:
limits:
cpu: "1"
memory: "1Gi"
requests:
cpu: "200m"
memory: "256Mi"
# Cache(可選:接 S3/MinIO;此段示意,若未啟用請刪除)
cache:
type: s3
path: "gitlab-runner"
s3ServerAddress: "minio.minio.svc.cluster.local:9000"
s3BucketName: "gitlab-ci-cache"
s3AccessKey: "minio-access"
s3SecretKey: "minio-secret"
s3Secure: false
新流程下:tags / run-untagged / locked 等屬性建議在 GitLab UI 的 Runner 設定頁調整,不再用 CLI 參數寫入。
安裝
helm upgrade --install gitlab-runner gitlab/gitlab-runner \
-n gitlab-runner -f values.yaml
驗證
kubectl -n gitlab-runner get pods
# 應看到 gitlab-runner 的 Pod(或 deployment/rs)
四、最小 .gitlab-ci.yml(驗證 K8s executor 正常)
stages: [ping]
hello:
stage: ping
image: alpine:3.20
script:
- echo "Runner: $CI_RUNNER_DESCRIPTION"
- echo "Executor: Kubernetes OK"
- cat /etc/os-release
跑起來時的 log 開頭應出現:Preparing the "kubernetes" executorK8s 裡 ci-jobs 命名空間會看到對應的 Pod(生命周期:Running → Succeeded)。
五、在 K8s executor 內建 Docker 映像(推薦用 Kaniko)
K8s executor 不建議 DinD。常見做法是用 Kaniko(rootless,無需 Docker daemon)。
在 GitLab 專案 CI Variables 設定:
CI_REGISTRY(你的 registry 位址)
CI_REGISTRY_IMAGE(目標 repo)
CI_REGISTRY_USER / CI_REGISTRY_PASSWORD(登入憑證)
Kaniko Job 範例
stages: [build]
docker-build:
stage: build
image:
name: gcr.io/kaniko-project/executor:latest
entrypoint: [""]
variables:
# registry 登入(若用 GitLab Container Registry,可改為 CI 提供的 token)
DOCKER_CONFIG: /kaniko/.docker
script:
- >
mkdir -p /kaniko/.docker &&
cat > /kaniko/.docker/config.json < Dockerfile
- >
/kaniko/executor
--context "${CI_PROJECT_DIR}"
--dockerfile "${CI_PROJECT_DIR}/Dockerfile"
--destination "${CI_REGISTRY_IMAGE}:$CI_COMMIT_SHA"
--destination "${CI_REGISTRY_IMAGE}:latest"
這個 job 會在 K8s 中跑 Kaniko,把映像打好推到 Registry,不需要 Docker daemon、也不需要 privileged。
六、(可選)Sidecar 服務示例(K8s 會幫你生多容器 Pod)
stages: [test]
pg-test:
stage: test
image: postgres:16-alpine
services:
- name: postgres:16-alpine
alias: db
variables:
POSTGRES_PASSWORD: secret
script:
- psql -h db -U postgres -c "SELECT version();"
在 K8s executor 下,services: 會轉成 同一個 Pod 的 sidecar 容器,網路互通用 alias 連線。
七、常見疑難排解
Pipeline 卡 Pending
確認 Runner 在 GitLab UI 顯示 Online、tags 是否匹配(或允許 untagged)。
Pod 起不來 / CrashLoopBackOff
kubectl -n ci-jobs describe pod 看 event / 拉不到 image / 權限問題。
需要特權容器
在 values.yaml 的 runners.privileged: true(謹慎評估安全)。
Cache/S3 連線
先用最小流程跑通,再逐一加上 cache 設定;MinIO/GCS/S3 憑證與位址要正確。
八、如果不用 Helm(純手工方式,了解即可)
部署一個 gitlab/gitlab-runner 的 Deployment
用 ConfigMap/Secret 提供 config.toml(executor = "kubernetes"、[runners.kubernetes] 參數)
綁一個 ServiceAccount + RBAC(允許建立/刪除 Pod)
但維運上 Helm chart 會簡單很多(升級/回滾/佈署差異)。
需要我幫你把 values.yaml 客製到你的環境(例如 MinIO 位址、特定節點選擇器、Pod 安全性設定、預設資源)嗎?我可以直接產一份可用的版本給你。【GitLab】CI/CD Settings 說明
✅ General pipelines
1. Public pipelines
功能:允許任何人(即使沒有專案權限)查看 Pipeline 與 Job 詳細資訊,包括 log 和 artifacts。
影響:
開啟:方便外部協作或開源專案 debug。
關閉:僅有有權限的使用者能查看。
2. Auto-cancel redundant pipelines
功能:在同一分支上,如果新的 Pipeline 啟動,會自動取消舊的 Pending / Running pipeline。
好處:減少資源浪費(例如多次 push 只保留最後一次)。
注意:取消的 pipeline 會標記為 canceled。
3. Skip outdated deployment jobs
功能:部署任務還沒執行時,如果有新的 pipeline 部署成功,舊的部署 job 就會跳過(不執行)。
應用情境:避免舊版本覆蓋新版本的部署。
4. Use separate caches for protected branches
功能:對受保護分支(protected branch)使用獨立的 CI cache。
好處:防止非受保護分支的 cache 汙染主分支的 cache(例如 main / master)。
影響:可能增加存儲空間使用。
5. CI/CD configuration file
功能:指定 .gitlab-ci.yml 檔案位置。
預設:.gitlab-ci.yml 在專案根目錄。
用途:
如果 CI 設定檔放在子目錄,可以改成 my/path/ci.yml。
適合 Monorepo 管理多個 CI 配置。
6. Git strategy
選項:
git clone:每個 job 都會全新 clone 一份 repo。
git fetch(已勾選):重複使用上一次 job 的工作目錄(workspace),若不存在才 clone。
比較:
clone:乾淨,但速度較慢。
fetch:快,但可能殘留舊檔案(需注意 job 隔離)。
7. Git shallow clone
數值:20
功能:限制 clone/fetch 的提交數(Depth)。
範例:20 代表只取最後 20 次 commit 歷史。
0 或空白 → 取全部 commit & tags。
好處:減少 clone 時間與流量。
8. Timeout
值:1h(1 小時)
功能:Job 最長允許執行時間。
到時動作:超時會被 GitLab 強制標記為 failed。
可用格式:秒數(3600)、人類可讀(1h、30m)。
我看你的設定,Git strategy 用 fetch + shallow clone 20,這樣拉程式會比較快,但如果你有需要依賴完整 commit 歷史(例如 git describe、全量 tag 檢出),要把 shallow clone 設成 0。
✅ Pipeline status
這張圖是 GitLab 專案的 CI/CD 狀態徽章(Badges)設定頁,它提供了一些可以放到 README 或網頁上的「狀態顯示圖示」,用來即時反映專案的 CI/CD 情況。
分三塊說明:
1. Pipeline status(流水線狀態)
顯示當前分支的 CI/CD Pipeline 狀態(成功、失敗、進行中等)。
會即時更新成對應的 SVG 圖示。
三種嵌入格式:
Markdown:給 README.md 用
[](http://10.2.2.3/user/k8s-deploy/-/commits/master)
HTML:可用在網站或 Wiki
AsciiDoc:給 AsciiDoc 格式文件用
2. Coverage report(測試覆蓋率)
需要在 .gitlab-ci.yml 內啟用測試覆蓋率計算(通常透過 coverage: 關鍵字解析測試輸出)。
顯示該分支最近一次 Pipeline 的測試覆蓋率百分比。
格式同上,也提供 Markdown / HTML / AsciiDoc 三種嵌入方式。
3. Latest release(最新版本)
會顯示專案的最新 Release(透過 GitLab Release 功能發佈的版本)。
如果沒有 Release,就會顯示 none(像你現在的狀態)。
格式同上,也提供三種嵌入方式。
4. 使用方式
你可以把 Markdown 格式複製到專案的 README.md,讓別人一眼看到專案的 CI/CD 狀態與測試覆蓋率。
如果有內部 Wiki、Confluence、或是外部網站,也可以用 HTML 格式嵌入。
例如放在 README.md:
# k8s-deploy
[](http://10.2.2.3/user/k8s-deploy/-/commits/master)
[](http://10.2.2.3/user/k8s-deploy/-/commits/master)
✅ Auto DevOps
你這張圖是 GitLab Auto DevOps 的設定頁面,它是 GitLab 提供的一套「自動化 CI/CD Pipeline」功能,讓專案在沒有自訂 .gitlab-ci.yml 的情況下,也能自動完成建置、測試、部署等流程。
1. Default to Auto DevOps pipeline
啟用狀態(打勾)表示如果專案 沒有 .gitlab-ci.yml,GitLab 就會自動使用 Auto DevOps 預設流程。
instance enabled表示這個功能已在 GitLab 系統層級啟用,專案可以直接用。
如果你已經在專案內放了 .gitlab-ci.yml,這個設定不會生效(因為會優先用自訂 Pipeline)。
2. 提示訊息
Add a Kubernetes cluster integration with a domain, or create an AUTO_DEVOPS_PLATFORM_TARGET CI variable.
Auto DevOps 預設會部署到 Kubernetes,所以 GitLab 建議:
整合 Kubernetes 叢集(在 GitLab CI/CD > Clusters 中設定)
或者在 CI/CD 變數中設定 AUTO_DEVOPS_PLATFORM_TARGET(指定部署平台)
3. Deployment strategy(部署策略)
三種選項:
Continuous deployment to production(持續部署到正式環境)
每次 Pipeline 成功就會自動部署到 Production。
Continuous deployment to production using timed incremental rollout(定時漸進式部署)
部署會分批釋出,逐漸更新所有節點(需要 Kubernetes 支援)。
Automatic deployment to staging, manual deployment to production(自動部署到測試環境,手動部署到正式環境)
先自動部署到 Staging 環境,Production 需要手動觸發。
4. 總結影響
如果勾選這個設定,且專案沒有 .gitlab-ci.yml,就會自動跑 GitLab 預設的 Auto DevOps 流程。
Auto DevOps 預設:
會進行 build → test → code quality → security scan → review app → deploy 等階段
預期環境是 Kubernetes
如果沒有 K8s,就需要自行設定變數(像 AUTO_DEVOPS_PLATFORM_TARGET)或調整成 Docker / VM 方式
✅ Runners
1. Runners 概念
Runner 是 GitLab CI/CD 的執行代理,用來接收並執行 pipeline job。
可以註冊在不同機器上(VM、Docker、K8s 等)。
有兩種主要分類:
Specific runners(專案專用)
Shared runners(全 GitLab 共用)
2. Specific runners
這個區塊是專屬於當前專案的 Runner。圖片中有兩個 active 的 Runner:
Runner 名稱
類型
Tag
狀態
#347 (UgMp--WG)
Docker Executor
app-docker-204
🟢 active
#343 (Mw1g8wwh)
Shell/VM Executor
app-docker-vm-204
🟢 active
Tag 作用:
.gitlab-ci.yml 中 tags: ["app-docker-204"] 會指定 job 只能由對應的 Runner 執行。
如果 job 沒有 tags,而 Runner 又設定了「不允許 untagged job」,則不會被這個 Runner 接手。
3. Runner 註冊方式
左邊「Set up a specific runner for a project」提供:
GitLab 伺服器 URL:
http://10.X.X.X/
專案 Registration Token(圖片中有一段)用 gitlab-runner register 時會用到。
4. Shared runners
當前 GitLab 沒有設定任何 Shared Runner(全域共用)。
「Enable shared runners for this project」是打開的,但因為 instance 沒有 shared runner,所以沒有作用。
5. Group runners
用於同一 GitLab group 底下多個專案共享 Runner。
目前這個專案不屬於任何 group,所以無法使用 group runner。
6. 運作重點
你有兩台 runner:
app-docker-204 → Docker executor,跑 job 時會用容器。
app-docker-vm-204 → Shell executor,直接在 VM 上跑。
兩者可以同時存在,但必須在 .gitlab-ci.yml 指定正確的 tag,否則可能出現「no runner can run the job」的錯誤。
✅ Artifacts
這張圖是 GitLab 專案的 Artifact 保留設定。
Artifacts
Artifact 是 GitLab CI/CD 在 Job 結束後產生的檔案(例如:build 結果、測試報告、壓縮檔)。
這些檔案可以被下載、或傳到後續的 Job 使用。
Keep artifacts from most recent successful jobs(已勾選 ✅)
啟用後,系統會只保留最後一次成功的 Pipeline 所產生的 artifact。
舊的 artifact 會被自動刪掉,節省儲存空間。
適合只想保留最新版本的成果(例如:最後打包的 image、最後的前端編譯檔)。
作用機制
你的 pipeline 跑成功後 → Job 產生 artifact → 存下來。
下一次成功的 pipeline 出現 → GitLab 自動刪掉前一次成功的 artifact → 只留最新的。
使用情境
適合 持續整合/持續部署(CI/CD),因為通常只需要最新的 build 產物。
不適合需要保留歷史版本(例如回溯除錯、審計)的專案,此時應該在 .gitlab-ci.yml 裡設定 expire_in 來控制保存期限。
這張圖是 GitLab CI/CD 專案層級的 Variables 設定頁面,主要是用來存放敏感資訊(例如密碼、金鑰、帳號等),在 Pipeline 中可以直接引用。
✅ Variables(變數)
1. Variables(變數)
存放的資料可以在 .gitlab-ci.yml 的 job script 中透過 $KEY 方式存取,例如 $PassWd、$UserName。
避免將敏感資料直接寫在 .gitlab-ci.yml 裡。
2. 欄位說明
欄位
說明
Type
一般都是 Variable,也可能是 File(將值存成檔案再提供給 Job)。
Key
變數名稱(例如 PassWd、UserName),在 CI/CD job 中用 $PassWd 存取。
Value
變數值(已隱藏),只有有權限的使用者才能看到。
Protected
✅ 表示這個變數只會在 Protected branch 或 Protected tag 的 pipeline 中被注入。
Masked
✅ 代表在 Job log 中會以 ***** 隱藏,防止外洩(必須符合 GitLab Mask 規則)。
Environments
變數適用的環境,例如 All、production、staging 等。
3. 圖中範例
PassWd:
Protected ✅
Masked ✅(所以在 job log 裡看不到明碼)
適用於所有環境(All)。
UserName:
Protected ✅
Masked ❌(會以明碼顯示在 job log,如果有 echo $UserName 會直接看見)。
4. 使用範例
假設你在 .gitlab-ci.yml 中要用這兩個變數:
stages:
- test
show-vars:
stage: test
script:
- echo "User: $UserName"
- echo "Password: $PassWd"
如果 Masked 是 ✅ → job log 會看到 Password: *****
如果 Masked 是 ❌ → job log 會看到明碼 Password: mypassword
在 GitLab 裡,
Protected branch(受保護分支) 和 Protected tag(受保護標籤)是用來防止重要分支或標籤被隨意修改、刪除、或由沒有權限的人 push 的安全機制。
Protected branch(受保護分支) 和 Protected tag (受保護標籤)
1. Protected branch(受保護分支)
主要特點:
只能特定角色(例如 Maintainer、Owner)push 及 merge。
一般用來保護 主要分支(例如 master、main、release)。
通常會搭配 Code Review / Merge Request 流程使用,避免直接修改。
也可以設定 誰可以直接 push、誰只能 merge。
範例情境
master 分支設為 Protected → 只有 Maintainer 能 merge 到 master。
Developer 想要改 master,必須透過 Merge Request 並經過審核。
2. Protected tag(受保護標籤)
主要特點:
限制誰可以建立或刪除特定的 Tag。
通常用來保護 版本發布標籤(例如 v1.0.0)。
避免有人隨便重建同名 Tag 導致部署混亂。
範例情境
v* 標籤設為 Protected → 只有 Maintainer 可以建立 v1.2.0 這類 Tag。
防止 Developer 私自發佈或覆蓋版本。
3. 為什麼與 CI/CD Variables 有關
當你在 GitLab CI/CD 中將變數設定為 Protected = ✅ 時:
這個變數 只會注入 到針對 Protected branch 或 Protected tag 觸發的 Pipeline。
如果在非受保護分支(例如 feature/test)觸發 Pipeline,變數不會被注入,避免敏感資料外洩。
舉例
deploy:
stage: deploy
script:
- echo $PROD_API_KEY
如果 $PROD_API_KEY 是 Protected ✅:
在 master(Protected branch) 觸發 → 可以用。
在 dev(非 Protected branch) 觸發 → 不會注入,變成空值。
這是 Protected Branch / Tag 與 CI/CD 變數注入邏輯對照表:
Pipeline 觸發來源
變數 Protected 設定
變數是否注入
說明
Protected branch(例如 master)
✅ Protected
✅ 注入
變數只對受保護分支生效,符合條件可使用
非 Protected branch(例如 feature/test)
✅ Protected
❌ 不注入
變數不會被注入,避免敏感資料外洩
Protected tag(例如 v1.0.0)
✅ Protected
✅ 注入
變數會注入到受保護標籤的 Pipeline
非 Protected tag(例如 test-1)
✅ Protected
❌ 不注入
變數不會被注入
任意 branch/tag
❌ 未 Protected
✅ 注入
不受限制,所有 Pipeline 都能用變數
💡 建議用法
部署金鑰 / 密碼 / Token → 設為 Protected ✅,避免在測試分支外洩。
測試環境參數 → 可以不 Protected ❌,讓所有分支都能測試。
✅ Pipeline triggers
你這張圖是 GitLab Pipeline Trigger 設定頁面,它的用途是建立一組 Trigger Token,讓外部系統或腳本可以直接觸發專案的 CI/CD Pipeline,而不用透過 Git push 或 Merge Request。
1. Trigger Token
這是一組唯一的金鑰(圖中 glptt-49dbb6d...)。
持有這個 Token 的人,就能用 API 或 Webhook 觸發該專案的 Pipeline。
權限等同於建立它的帳號,但只能用來觸發 Pipeline,不能直接讀取或修改程式碼。
2. 觸發方式
(1) 用 cURL
curl -X POST --fail \
-F token=YOUR_TOKEN \
-F ref=分支或tag名稱 \
http://10.10.10.10/api/v4/projects/2406/trigger/pipeline
ref:要在哪個 branch 或 tag 執行 Pipeline,例如 master 或 release-v1.0。
(2) 在 .gitlab-ci.yml 裡呼叫
script:
- "curl -X POST --fail -F token=YOUR_TOKEN -F ref=master http://10.10.10.10/api/v4/projects/2406/trigger/pipeline"
(3) 用 Webhook 直接 GET
http://10.10.10.10/api/v4/projects/2406/ref/master/trigger/pipeline?token=YOUR_TOKEN
適合用在簡單的 HTTP 呼叫(像是 Jenkins、監控系統、外部自動化工具)。
3. 傳入 Pipeline 變數
可以讓外部觸發時同時傳遞變數:
curl -X POST --fail \
-F token=YOUR_TOKEN \
-F ref=master \
-F "variables[RUN_NIGHTLY_BUILD]=true" \
http://10.10.10.10/api/v4/projects/2406/trigger/pipeline
這樣在 .gitlab-ci.yml 中可以用 $RUN_NIGHTLY_BUILD 判斷。
4. 使用場景
定時觸發:配合 cron job,每天固定時間呼叫 API。
外部事件觸發:例如其他系統部署完成後自動通知 GitLab 進行後續工作。
跨專案觸發:一個專案完成後,透過 Token 觸發另一個專案的 Pipeline。
💡 建議:
不要把 Trigger Token 放在公開的地方(例如公開 repo)。
如果 Token 洩漏,任何人都可以觸發你的 Pipeline(甚至傳遞惡意變數)。
若外部要用,最好配合 Protected Branch 來限制觸發範圍。
✅ Deploy freezes(部署凍結)
你這張圖是 GitLab 的 Deploy freezes(部署凍結)設定頁面,用來在特定時間區間禁止部署,避免在敏感時段(例如假日、系統維護時間、尖峰時段)誤發佈程式。
圖中設定解讀
Freeze start:10 1 * * *代表每天 01:10 開始凍結部署(Cron 語法:分 時 日 月 星期)。
Freeze end:10 3 * * *代表每天 03:10 結束凍結部署。
Time zone:[UTC +8] Taipei表示時間以台北時區計算。
功能運作方式
這裡的時間範圍只是定義凍結時段。
要生效,必須在 .gitlab-ci.yml 的部署 job 中加上:
deploy_job:
stage: deploy
script:
- echo "Deploying..."
rules:
- if: $CI_DEPLOY_FREEZE == "true"
when: never
- when: on_success
或使用 GitLab 內建的 deploy_freeze 規則。
凍結期間,對應的部署 job 會直接跳過,不會觸發。
使用場景
避免在系統流量高峰期誤佈署造成中斷。
避免在假日、深夜維護窗口外誤觸部署。
防止新人誤觸 Pipeline 造成上線事故。
✅ Token Access
這是 GitLab 專案設定裡的 Token Access(CI_JOB_TOKEN 存取控制) 功能,主要用來限制 CI/CD 任務中 CI_JOB_TOKEN 變數可以存取的其他專案,避免被濫用。
Limit CI_JOB_TOKEN access(開關)
預設關閉(灰色),代表 任何專案 都能被這個專案的 CI_JOB_TOKEN 存取。
開啟後(藍色),就可以指定只有被列入清單的專案能被存取。
Add an existing project to the scope
在這裡輸入 GitLab 專案路徑(例如:gitlab-org/gitlab),將其加入允許清單。
這樣 CI_JOB_TOKEN 就只能存取清單內的專案 API。
Projects that can be accessed
圖中顯示的 Live K8s Deploy 就是允許被目前專案的 CI_JOB_TOKEN 直接存取的另一個專案。
用途
跨專案存取 API在 CI/CD pipeline 中,可能需要用 curl 或 wget 呼叫其他 GitLab 專案的 API,例如下載 artifact、觸發 pipeline。
限制安全風險如果沒有啟用限制,惡意程式碼可以利用 CI_JOB_TOKEN 存取同一 GitLab instance 中所有公開或有權限的專案。
最佳實務
如果專案需要 CI_JOB_TOKEN 存取別的專案 → 開啟並只加允許的專案。
如果專案不需要跨專案存取 → 建議直接開啟限制並不加任何專案。
範例:跨專案下載 Artifact
假設專案 A 的 pipeline 要下載專案 B 的最新 build:
script:
- curl --header "JOB-TOKEN: $CI_JOB_TOKEN" \
"https://gitlab.example.com/api/v4/projects/123/jobs/artifacts/main/download?job=build" \
-o artifact.zip
如果你啟用了限制,就必須在專案 B 裡把專案 A 加進「Projects that can be accessed」清單,否則會 403 Forbidden。
【GitLab】使用ssh clone 專案
以下是在 GitLab 使用 SSH 方式 clone 專案的完整步驟,假設你的 GitLab 伺服器是公司內部或自架的,也適用:
1️⃣ 產生並設定 SSH Key
建立 SSH Key
ssh-keygen
出現檔案路徑提示時直接按 Enter (預設~/.ssh/id_rsa.pub)
登入 GitLab → 右上角 使用者頭像 → Preferences → SSH Keys。
貼上 ~/.ssh/id_rsa.pub 內容。
2️⃣ 測試連線
確認 GitLab 可透過 SSH 連線:
ssh -T git@your.gitlab.host
第一次會詢問 Are you sure you want to continue connecting (yes/no)? → 輸入 yes。
成功訊息:Welcome to GitLab, @你的帳號!
3️⃣ 取得專案的 SSH URL
在 GitLab 專案頁面:
點選 Code → Clone → 選 SSH。
範例 URL:
git@gitlab.example.com:group-name/project-name.git
4️⃣ 執行 Clone
git clone git@gitlab.example.com:group-name/project-name.git
會將程式碼拉到目前目錄下的 project-name 資料夾。
5️⃣ 常見問題排查
問題
檢查方式
Permission denied (publickey)
確認 ssh-agent 有加入金鑰:ssh-add -l
找不到 Host
檢查網路、防火牆,或在 ~/.ssh/config 加入 Host 設定
公司內網 GitLab
需確保內部 DNS 或 VPN 正確
範例 .ssh/config(可簡化命令)
Host gitlab-company
HostName gitlab.example.com
User git
IdentityFile ~/.ssh/id_ed25519
然後可用:
git clone git@gitlab-company:group-name/project-name.git
以上步驟完成後,你就能用 SSH 方式安全地 git clone GitLab 專案並進行後續開發。【GitHub】相關
【Git】Github 新增專案檔案
create a new repository on the command line
echo "# sample_proj" >> README.md
git init
git add README.md
git commit -m "first commit"
git branch -M main
git remote add origin https://github.com/treemanou/sample_proj.git
git push -u origin main
push an existing repository from the command line
git remote add origin https://github.com/treemanou/sample_proj.git
git branch -M main
git push -u origin main
【Git】解決github項目體積過大的問題
首先查找出大文件
$ git rev-list --objects --all | grep "$(git verify-pack -v .git/objects/pack/*.idx | sort -k 3 -n | tail -5 | awk '{print$1}')"
–objects:列出該提交涉及的所有文件ID。–all:所有分支的提交,相當於指定了位於/refs下的所有引用。verify-pack命令用於顯示已打包的內容,我們用它來找到那些大文件。-v(verbose)參數是打印詳細信息。
前面我們通過rev-list得到了文件名-ID的對應關係,通過verify-pack得到了最大的5個文件ID。 用後者篩選前者便能得到最大的5個文件的文件名,比如:
$ git rev-list --objects --all | grep "$(git verify-pack -v .git/objects/pack/*.idx | sort -k 3 -n | tail -5 | awk '{print$1}')" b96695fd6e62fff41723ab324368da394f3a504e package-lock.json 76ec4d5d5fd79da922b322d53fbd1298dc128dd3 node_modules/acorn/dist/acorn.mjs.map 286dc92a240dac765d81dfbda451fd19f9611e84 node_modules/ajv/dist/ajv.bundle.js d2cc86eb230313af9bbdbd3faed7f8e7c7247788 node_modules/source-map-support/node_modules/source-map/dist/source-map.min.js.map aad0620d70e16717ec338fc1d332279739e0d97c node_modules/terser/node_modules/source-map/dist/source-map.debug.js
然後我們需要刪除他們
$ git filter-branch --force --prune-empty --index-filter 'git rm -rf --cached --ignore-unmatch YOU-FILE-NAME' --tag-name-filter cat -- --all
filter-branch命令可以用來重寫Git倉庫中的提交–index-filter參數用來指定一條Bash命令,然後Git會檢出(checkout)所有的提交, 執行該命令,然後重新提交。–all參數表示我們需要重寫所有分支(或引用)。YOU-FILE-NAME 你查找出來的大文件名字
重複幾次,直到大文件全部刪除完畢。
如果你確定某一個文件夾下面都不是你需要的,那麼你可以直接刪除整個文件夾,比如:
$ git filter-branch --force --prune-empty --index-filter 'git rm -rf --cached --ignore-unmatch node_modules' --tag-name-filter cat -- --all
完成後,以強制覆蓋的方式推送你的repo, 命令如下:
$ git push --force --all
最後,雖然上面我們已經刪除了文件, 但是我們的repo裡面仍然保留了這些objects, 等待垃圾回收(GC), 所以我們要用命令徹底清除它, 並收回空間,命令如下:
$ rm -rf .git/refs/original/
$ git reflog expire --expire=now --all
$ git gc --prune=now
Enumerating objects: 116, done.
Counting objects: 100% (116/116), done.
Delta compression using up to 4 threads Compressing objects: 100% (53/53), done. Writing objects: 100% (116/116), done.
Total 116 (delta 55), reused 116 (delta 55)
$ git push --force --all
【Git】語法觀念
【Git】相關連結
github 線上教學GitHub Learning Lab
Git基本原理介绍 | Escape (escapelife.site)
Learn Git Branching (gitee.io)
Git基本原理介绍 | Escape (escapelife.site)【Git】還原相關
以下是關於 Git 還原(恢復)功能的完整說明
Git 還原功能總表
指令
還原範圍
是否會刪除暫存區
是否會刪除未追蹤檔案
適用情境
git checkout .
工作目錄
否
否
還原已追蹤檔案
git restore .
工作目錄
否
否
推薦用法,等同於 checkout .
git restore --staged
暫存區
是
否
還原 git add 的檔案
git reset
暫存區
是
否
退回 staging 區
git reset --hard HEAD
工作目錄 + 暫存區
是
是(若搭配 clean)
徹底放棄所有變更(⚠危險)
git clean -fd
未追蹤檔案/資料夾
無關
是
清空未納入 Git 管控的檔案
git revert
版本歷史
無關
否
安全回復 commit(保留紀錄)
Git 還原功能完整整理與使用說明
在日常開發中,Git 提供多種指令用來還原工作目錄、暫存區,或是回復錯誤的 commit。根據不同的需求,選擇合適的還原方式可避免資料遺失或版本混亂。
1. git checkout .
還原所有「已追蹤檔案」回到最新 commit 的狀態。
作用範圍:僅限工作目錄(Working Directory)
不會還原:未追蹤(untracked)檔案與暫存區(Staging Area)
適用情境:
編輯了多個檔案,想快速放棄變更,但未進行 git add。
2. git restore(推薦用法)
git restore 是 Git 2.23+ 提供的新指令,取代過去 checkout 的混用狀況。
範例:
git restore . # 還原所有檔案
git restore path/to/file.js # 還原單一檔案
與 git checkout . 行為一致,語意更清楚
可搭配 --staged 還原暫存區(如下)
3. git restore --staged
還原暫存區的內容,讓已 git add 的檔案退回至工作目錄狀態。
git restore --staged path/to/file.js
不會影響工作區的內容
常用於誤將檔案加入 staging 區的情況
4. git reset
還原 staging 區(暫存區),讓所有已 git add 的檔案回到修改中狀態。
git reset
與 git restore --staged 功能類似
不會更動工作目錄內容
5. git reset --hard HEAD
將 工作目錄與暫存區 都還原成最近一次提交(HEAD)的狀態。
git reset --hard HEAD
非常危險,會清除未提交的所有變更
包含 git add 過的內容也會消失
適用情境:
變更混亂,想完全清空所有未提交的東西
6. git clean -fd
清除所有「未被追蹤的檔案與資料夾」。
git clean -fd
-f:強制執行
-d:包括未追蹤的資料夾
適用情境:
清除 build 檔案或不小心留下的臨時檔案
7. git revert
對某個已提交的 commit 產生一個「反向操作的 commit」。
git revert
保留歷史紀錄
安全的還原方式,尤其在多人開發時
適用情境:
上線後發現某次 commit 有錯誤,需在版本歷史中保留修正記錄
【Git】TorotoiseGit 占用資源解決方法
【原因】 TorotoiseGit 會掃描硬碟內有git 版控資料夾的的異動,並產生相對應的圖示,有時會造成主機磁碟讀寫過高
【解決】限縮掃描範圍
任一個資料夾按右鍵->【TortoiseGit】->【setting】
Exclude paths: 將本機的每一個磁碟加入
Include paths: 將有用到git的目錄加入【Git】windows系統 warning: LF will be replaced by CRLF in
windows系統下使用git出現:warning: LF will be replaced by CRLF in
$ git add readme.txt readme.txt
warning: LF will be replaced by CRLF in learngit/readme.txt.
The file will have its original line endings in your working directory
原因是windows系統的換行符和Unix下的換行符不同,但是git會幫我們自動進行換行符的轉換,所以出現了這個warning
# 解決的方法就是,禁止自動轉換:
$git config –-global core.autocrlf false
https://noelhsiao.medium.com/%E9%81%87%E5%88%B0-warning-lf-will-be-replaced-by-crlf-in-%E8%A9%B2%E6%80%8E%E9%BA%BC%E8%A7%A3-ab9882ee07be
【Git】checkout 與 switch 比較
我來幫你整理 git switch 和 git checkout 的差異,並用表格讓你快速比較。
1️⃣ 歷史背景
git checkout 是 Git 早期就有的指令,功能很多,但語意太複雜,既可以切換分支、也可以檢出檔案,容易讓初學者混淆。
git switch(Git 2.23 之後加入)是為了讓「切換分支」這個動作更直觀而出現的,專注於分支切換,不負責檔案檢出。
2️⃣ 功能比較表
功能
git checkout
git switch
切換到已存在分支
✅ git checkout branch_name
✅ git switch branch_name
建立並切換到新分支
✅ git checkout -b new_branch
✅ git switch -c new_branch
檢出特定 commit / tag
✅ git checkout commit_hash
❌ 不支援
檢出特定檔案版本
✅ git checkout commit_hash -- file.txt
❌ 不支援
語意單純性
❌ 功能太多易混淆
✅ 專注於切換分支
推薦使用情境
老專案 / 習慣舊指令
新專案 / 想簡化操作
3️⃣ 使用範例
切換到現有分支
# 傳統方式
git checkout dev
# 新方式(推薦)
git switch dev
建立並切換到新分支
# 傳統方式
git checkout -b feature/login
# 新方式(推薦)
git switch -c feature/login
4️⃣ 為什麼官方推薦 git switch
讓指令語意更明確,不再把「檔案檢出」和「分支切換」混在一起。
搭配 git restore(處理檔案版本還原)更符合直覺:
git switch → 專注切換分支
git restore → 還原檔案內容
💡 簡單記:
切換分支 → 用 git switch
還原檔案 → 用 git restore
需要舊版本的行為 → 用 git checkout
太好了!以下是 git switch 和 git restore 如何取代舊指令 git checkout 的完整對照表,讓你更容易理解並開始使用新指令:
✅ git checkout 對照表:對應的新指令用法
原本 git checkout 用法
對應的新指令
功能說明
git checkout
git switch
切換到已存在的分支
git checkout -b
git switch -c
建立並切換到新分支
git checkout
❌(建議保留 checkout)
切換到某個 commit 狀態(暫不取代)
git checkout
git restore
還原工作區中的單一檔案
git checkout --
git restore
同上
git checkout --
git restore --source
還原某個 commit 中的檔案
git checkout .
git restore .
還原所有工作區的檔案
git checkout HEAD
git restore --source=HEAD
還原最新 commit 的某個檔案
git checkout HEAD^
❌(建議保留 checkout)
切換到上一個 commit(建議保留舊指令)
💡 建議做法
任務
建議用法
切換分支
git switch dev
建新分支並切過去
git switch -c feature/new-ui
還原單一檔案
git restore src/App.tsx
還原某 commit 的檔案
git restore --source=abc123 file.txt
還原整個工作目錄
git restore .
🚀 Git 版本要求
git switch 和 git restore 需 Git 2.23 或以上
使用 git --version 檢查目前版本
【Git】HEAD 是什麼
當然可以!HEAD 是 Git 中最核心也是最常見的概念之一,很多 Git 指令(如 reset、checkout、rebase)都與它有關。下面我會從簡單到深入,幫你完整說明:
一句話理解 HEAD 是什麼:
HEAD 是你目前所在的分支的「指標」,也就是「你現在工作的 commit」位置。
基本概念圖:
假設你有三個 commit:
A → B → C
↑
HEAD
這表示目前 HEAD 指向 commit C
如果你新增一個 commit,會變成:
A → B → C → D
↑
HEAD
HEAD 的 3 種狀態:
狀態類型
說明
HEAD → 分支名稱(正常狀態)
你在某個分支上(例如 main、dev)
HEAD → commit(detached)
你處於「分離 HEAD 狀態」(Detached HEAD)
HEAD → 其他指標
比如在 Rebase、Merge 中會指向暫存區域
✅ 常見用途說明
1. HEAD 是你目前的開發位置
當你執行:
git commit
其實 Git 是「把你的 commit 接在 HEAD 指向的 commit 後面」。
2. HEAD 是 Git 重設的基準點
git reset --hard HEAD
這表示:把你的暫存區與工作目錄都還原成目前這個 commit 的狀態。
3. HEAD^、HEAD~1:往上移動一個 commit
表示法
意思
HEAD
現在這個 commit
HEAD^
上一個 commit(parent)
HEAD~1
同 HEAD^
HEAD~2
往上兩個 commit
🚨 Detached HEAD(分離 HEAD 狀態)
當你執行:
git checkout <某個 commit 哈希>
你會進入「Detached HEAD」狀態:
A → B → C
↑
(HEAD)
你不再是在某個分支上,而是「直接指向某個 commit」。這時如果你做出 commit,它們會變成「懸空」,容易被 Git 回收(垃圾回收)。
所以如果你看到這樣的訊息:
You are in 'detached HEAD' state.
請小心:最好先建立分支來保存變更:
git checkout -b temp-branch
🧭 總結:HEAD 是 Git 的當前位置指標
功能
用途說明
表示目前 commit
所有操作(commit、reset)都以它為基礎
指向當前分支
預設情況 HEAD 是指向你當前分支
變更分支 = 移動 HEAD
切分支就是改變 HEAD 的位置
可用於版本回朔、還原
HEAD^、HEAD~2 常見於 reset、diff 等
被分離 = Detached HEAD
指向 commit 而非分支,要小心變更遺失
如果你想要我畫一張圖示 HEAD 與分支移動的流程圖,也可以說一聲,我能幫你生成視覺化版本!是否需要?
為什麼我們要「移動 HEAD」?
簡單來說:
移動 HEAD = 改變我們正在「看的版本」、「工作的版本」、或「建立新歷史的起點」。
Git 是一個版本控制系統,HEAD 就像「目前播放的時間軸指標」,移動它可以讓你做版本切換、回朔、修正、實驗開發等動作。
✅ 移動 HEAD 的常見目的(整理成表)
用途/目的
說明
🔄 切換分支或版本
改變目前正在編輯/開發的版本,比如 git switch dev(切換 HEAD 到 dev)
🧭 回朔 commit
想把 HEAD 拉回到前一版:git reset --hard HEAD^
🧪 版本測試或除錯某一版
用 git checkout 移動到某個版本試驗、測試(會進入 detached HEAD)
🧹 清除或重建 commit 歷史
用 git reset 或 rebase 改變 HEAD 來整理版本歷史
🧱 建立新的分支開發點
移動 HEAD 到 commit 後再用 git switch -c new-branch 開分支
🔥 放棄變更並回到穩定版本
移動 HEAD 到穩定 commit 位置,還原所有內容
舉幾個具體例子
1️⃣ 切換分支(背後其實是移動 HEAD)
git switch dev
📌 HEAD 從 main → dev,代表你現在工作的是 dev 的最新 commit。
2️⃣ 回到前一版(移動 HEAD 到上一個 commit)
git reset --hard HEAD^
📌 HEAD 往回一格,捨棄最近一次的提交內容(危險但有用)。
3️⃣ 想測試舊版功能(Detached HEAD 狀態)
git checkout abc1234
📌 HEAD 不再指向分支,而是指向一個 commit,你進入「Detached HEAD」狀態,可以安全看舊版本。
4️⃣ 切 HEAD + 建立新分支(從中間版本開新分支)
git checkout abc1234
git switch -c fix-login
📌 移動 HEAD 到舊版,再基於此版本開新分支,進行 hotfix。
把 HEAD 當「播放頭」的比喻
想像 Git 是個影片編輯器:
commit 是一個個時間點的「場景」
HEAD 是播放頭
你移動 HEAD,就等於跳到那一幕開始剪接
這樣你就能理解:
reset 是「退回到前一段」
rebase 是「換剪接順序」
checkout 是「跳到某個片段」
commit 是「加入新片段」
✅ 小結:為什麼要移動 HEAD?
目的
解釋
🧭 切換你正在工作的版本
因為 HEAD 代表你「現在的位置」
🔙 回到過去版本
移動 HEAD 讓你回到某個穩定 commit
🧪 實驗新東西 / 修 bug
從舊 commit 移動 HEAD,開新分支來做測試與修復
🔧 重構 Git 歷史
通過 reset 或 rebase 移動 HEAD 重寫 commit 歷史
這是個很關鍵的 Git 概念問題!當你的 HEAD 不在任何分支上,而是直接指向某個 commit,這個狀態稱為:
⚠️ Detached HEAD(分離 HEAD 狀態)
✅ 什麼是 Detached HEAD?
正常情況:
HEAD → main → C
Detached HEAD 狀況:
HEAD → C (但不是任何分支)
你直接「跳到一個 commit」,例如透過:
git checkout abc1234
或:
git switch --detach abc1234
這時你就脫離了任何分支的控制,你在 那個 commit 上自由工作,但:
🧨 所做的一切(如新增 commit)都不屬於任何分支,如果不小心離開就會「失聯」。
Detached HEAD有什麼影響?
有什麼影響?
結果
說明
✅ 可以修改檔案、做 commit
你仍然可以正常工作(只是沒有在分支上)
🧨 新的 commit 沒有分支指向
所有新 commit 是「懸空狀態」,不儲存在任何分支上
🧹 一旦切換到其他分支就可能遺失那些 commit
除非你把它們另存(例如建立新分支),否則 Git 垃圾回收後就找不回來
🧠 git status 會提示 Detached HEAD
告訴你現在是在 Detached 狀態
什麼情況會進入 Detached HEAD?
情境
指令
想要看舊版本
git checkout
從某個 commit 測試 / 編譯
git switch --detach
在 CI/CD 工具中 checkout 特定 commit
例如 GitHub Actions 的 actions/checkout@v2 預設為 Detached
你用 git reset --hard 到某個 commit
HEAD 也會臨時分離
✅ 正確處理方式:建立分支保存你做的事!
如果你在 Detached HEAD 狀態下做了 commit,請馬上建立一個分支把它們保存下來:
git switch -c fix-login-bug
這樣你的 commit 就有名字,不會被回收。
總結:Detached HEAD 是可用但有風險的模式
特性
狀態說明
可以編輯與 commit
✅ 是
commit 是否屬於分支
❌ 否
離開當前 commit 後是否會遺失
✅ 會(除非建立分支)
建議
要保留修改就馬上建立分支
【Git】每個 commit 不都是從某個分支出來的嗎?
這是個非常棒的深入問題,顯示你對 Git 的理解已經進入「底層思維模式」,我們來一一說明:
一句話解釋你提的問題:
不是每個 commit 都屬於分支,但每個分支都指向某個 commit。
這句話是 Git 的核心設計邏輯,反直覺但重要。
先理解 Git 的本質:commit 是資料庫,分支是指標
在 Git 裡:
每個 commit 是獨立、完整、不可變的「快照」
「分支」其實只是指向某個 commit 的指標(pointer)
HEAD 是你當下的游標,會指向一個「分支」或「commit」
✅ 當你做 commit 時發生了什麼?
Git 會建立一個新 commit(有一個父 commit)
HEAD 所在的分支(如 main)會更新,指向這個新的 commit
所以我們通常覺得 commit 是從分支「出來」的,但其實:
🔍 分支並不綁定在 commit 上,是 commit 被分支「指到了」。
❗Detached HEAD:從 commit 建立 commit,但不屬於分支
來看個例子:
git checkout abc1234 # 進入 detached HEAD
echo "foo" > a.txt
git add a.txt
git commit -m "detached commit"
這時你新增的 commit 並不屬於任何分支!
A --- B --- C ← main
\
D ← HEAD (沒有分支名稱指向)
如果你切走:
git switch main
那個 D commit 就被遺棄了,未來可能被 Git 垃圾回收(GC)清掉。
分支只是「指到某個 commit」的名稱
你可以用 git branch 動態為任何 commit 建立分支:
git branch recover-commit abc1234
這個 abc1234 本來不是任何分支,但現在你「取了個名字」給它,它就變成你認為的「分支」。
實際演示:證明 commit 不一定屬於分支
git init
echo "init" > a.txt
git add .
git commit -m "init commit"
git checkout HEAD^ --detach
echo "detached" > a.txt
git commit -am "detached commit"
git log --oneline --decorate
你會看到第二個 commit 沒有任何分支名稱指向它,只是個孤兒 commit。
所以回到你的問題:
❓「每個 commit 不都是從某個分支出來的嗎?」
🔸 表面上是,但實際上:
commit 是獨立存在的節點
分支是後來「指」過去的
commit 是內容,分支是參考名稱(reference)
就像硬碟上的檔案可以沒被任何資料夾引用一樣,但它依然存在(直到被清理)
類比理解
Git 概念
類比成電腦系統
commit
實際的檔案內容(在磁碟上)
分支(branch)
檔案捷徑(shortcut)
HEAD
你正在開啟的那個捷徑
detached HEAD
你直接打開某個檔案(沒從捷徑)
【Git】head, tag, commit, branch的關係
這是一個非常關鍵的 Git 理解核心:HEAD、tag、commit、branch 彼此的關係。我幫你用「定義 + 關聯圖 + 對照表 + 比喻」完整整理如下:
✅ 一張圖:理解 Git 中 HEAD、分支、Tag、Commit 的關係
HEAD
↓
┌────────┐
│ branch │──┐
└────────┘ │
↓
┌────────────────┐
│ commit │◄──┐
└────────────────┘ │
▲ │
┌─────────┴──────┐ │
│ another │ │
│ branch │ │
└─────────────────┘ │
│
┌─────────┐
│ tag │──► 同樣也指向 commit
└─────────┘
🧠 核心定義
名稱
定義說明
commit
Git 的基本單位,是一個「版本快照」,有父子連結,不會變動
branch
指向某個 commit 的「可移動指標」,像捷徑,可以新增、移動
HEAD
代表你目前工作的「游標」,通常指向一個分支(或直接指向 commit)
tag
指向某個 commit 的「不可變名稱」(常用來標記版本,如 v1.0.0)
🔗 它們的關係總結
關係
說明
branch ➝ commit
分支就是指向某個 commit 的「指標」
HEAD ➝ branch or commit
HEAD 是你「目前所在的位置」,可以指向分支或直接指向 commit(detached HEAD)
tag ➝ commit
Tag 永遠指向某個 commit,是不可變的
commit 之間
commit 是鏈狀連結(每個有一個 parent commit)
📁 類比說明(像檔案系統)
Git 概念
類比
說明
commit
檔案版本
是實際的內容快照(不可變)
branch
資料夾捷徑
可以移動、可以新建、可以切換
HEAD
滑鼠游標
你目前的編輯焦點(在哪個捷徑/檔案上)
tag
唯一標籤貼紙
永久貼在某個版本上,表示這是一個重要的版本點
📌 補充:變動性比較
元件
是否可變動
常見操作
commit
❌ 不可變
一旦建立就不會改變
branch
✅ 可變動
可以移動、刪除、重新建立
tag
✅ 可刪除(內容不可變)
可以刪除再重建,但本身是不可移動的指標
HEAD
✅ 一直在動
跟著你切換分支、commit 而變動
✅ 常見操作對應關係
操作說明
HEAD 變動
branch 變動
commit 變動
tag 變動
git switch dev
✅
❌
❌
❌
git commit
✅
✅(會跟著 HEAD 一起動)
✅(新增)
❌
git reset --hard HEAD^
✅
✅
✅(可能丟失)
❌
git tag v1.0
❌
❌
❌
✅
git checkout
✅(分離)
❌
❌
❌
git switch -c new-feature
✅
✅(新建)
❌
❌
✅ 總結一句話:
commit 是內容
branch/tag 是「名字」,用來指向某個 commit
HEAD 是「你目前在哪裡」,通常跟著分支動,也可以離開分支進入 detached 狀態
【Git】git revert 和 git checkout 差異
git revert 和 git checkout 雖然都能「回到某個 commit」,但本質上用途完全不同。以下為詳細說明與比較。
一、git revert
功能說明:
用來**「反向操作」某個已提交的 commit**。
Git 會建立一個新的 commit,內容是將指定的 commit 所做的變更還原回去。
原本的 commit 仍然會保留在歷史中。
特性:
安全,適合多人協作情境。
保留歷史紀錄。
可選擇 revert 多個 commit(可搭配 -n 進行批次處理)。
使用情境:
已經 push 到遠端,但發現某個 commit 有誤,需要「撤銷」那次變更,但不想刪除歷史。
緊急修復 bug,並希望讓其他人看見這次的「撤銷行為」。
範例:
git revert a1b2c3d
會產生一個新的 commit,把 a1b2c3d 的內容還原。
二、git checkout (或 git switch --detach )
功能說明:
將當前工作目錄切換到某個過去的 commit(進入 detached HEAD 狀態)。
不會建立新的 commit,純粹只是瀏覽某個歷史狀態。
如果在此狀態下修改檔案並 commit,會產生「無分支」的 commit(容易遺失)。
特性:
不會變動歷史,也不會建立新 commit。
適合測試、比較、build 老版本。
使用情境:
想檢查過去某次版本的內容、debug、測試、build。
需要比較不同版本的行為。
範例:
git checkout a1b2c3d
# 或推薦用法(Git 2.23+)
git switch --detach a1b2c3d
三、兩者比較表
指令
動作類型
是否建立新 commit
是否修改歷史
是否可安全推送遠端
常見用途
git revert
建立反向 commit
✅ 是
❌ 否
✅ 是
撤銷已推送的錯誤 commit
git checkout
切換版本
❌ 否
❌ 否
⚠️ 不適合推送 detached commit
查看歷史、測試、debug
四、補充說明:若想基於某個舊 commit 建立新分支
git checkout -b new-branch a1b2c3d
這樣可以保留該版本的狀態,並在其上繼續開發,而不會讓 HEAD 處於 detached 狀態。
如果你有實際情境(例如:某個 commit 上錯 production,或想回復某功能),可以提供情況,我能幫你判斷該用 revert 還是 checkout 或其他方案。【Git】常用指令
Git 進階指令速查表(實戰版)
類別
指令
說明
常見情境
Merge
git merge branch
合併 branch
feature 合併到 main
Rebase
git rebase branch
重排 commit
整理 commit 歷史
Rebase
git rebase -i HEAD~3
互動式 rebase
squash commit
Cherry-pick
git cherry-pick
套用指定 commit
hotfix
Revert
git revert
回復某 commit
線上 rollback
Reflog
git reflog
查看 HEAD 歷史
找回被 reset 的 commit
Rebase vs Merge
操作
指令
結果
merge
git merge main
保留 merge commit
rebase
git rebase main
重新排列 commit
Merge
A---B---C main
\
D---E feature
\
F (merge)
Rebase
A---B---C main
\
D'---E' feature
📌 結論
操作
使用情境
merge
保留歷史
rebase
整理 commit
Interactive Rebase(整理 commit)
git rebase -i HEAD~3
會出現
pick a1b2 commit1
pick c3d4 commit2
pick e5f6 commit3
可修改為
pick a1b2 commit1
squash c3d4 commit2
squash e5f6 commit3
結果:
commit1 + commit2 + commit3
變成一個 commit
常用於:
PR 整理 commit
Cherry-pick(套用某 commit)
git cherry-pick
用途:
情境
範例
hotfix
從 dev 複製到 main
patch
套用某 bug fix
例如:
dev
A--B--C--D
main
A--B
git cherry-pick D
結果
main
A--B--D
Revert(安全 rollback)
git revert
Git 會產生一個 反向 commit
例如:
A--B--C
revert B
A--B--C--D
↑
undo B
📌 適合
production rollback
Reflog(救命指令)
查看 HEAD 歷史
git reflog
例如
a1b2 HEAD@{0}: reset: moving to HEAD~1
c3d4 HEAD@{1}: commit: fix bug
恢復:
git reset --hard c3d4
很多工程師不知道:
Git 幾乎不會真的丟資料
reflog 都能救回
Detached HEAD
發生情況
git checkout
Git 會顯示
You are in 'detached HEAD' state
代表:
HEAD 沒有 branch
解法
建立 branch:
git checkout -b new-branch
Clean(清除未追蹤檔案)
查看將刪除
git clean -n
刪除
git clean -fd
常用於:
CI pipeline
重新 build
Force Push
git push -f
⚠️ 危險
可能覆蓋他人 commit
安全方式:
git push --force-with-lease
這會檢查遠端是否被更新。
Reset / Restore / Checkout 差異
指令
影響範圍
reset
commit + staging
restore
working tree
checkout
branch 或檔案
Git 三層結構(核心概念)
Git 有三個區域:
Working Directory
↓
Staging Area (Index)
↓
Repository (Commit)
對應指令:
操作
指令
working → staging
git add
staging → repo
git commit
repo → working
git checkout
repo → staging
git reset
DevOps 常用 Git 重置流程
很多 CI pipeline 會用:
git fetch origin
git reset --hard origin/main
git clean -fd
作用:
確保 workspace 乾淨
Git Flow(常見分支策略)
常見 branch:
main
develop
feature/*
hotfix/*
release/*
流程:
feature -> develop
develop -> release
release -> main
hotfix -> main
Git Debug 指令
指令
用途
git blame file
查看誰修改
git bisect
找 bug commit
git show
查看 commit
git diff commit1 commit2
比較 commit
工程師最強 Git 指令 TOP 10
指令
用途
git log --oneline --graph
查看歷史
git reflog
救 commit
git rebase -i
整理 commit
git cherry-pick
套 commit
git revert
rollback
git clean -fd
清 workspace
git reset --hard
重置
git stash
暫存
git blame
找修改人
git bisect
找 bug
💡 給你一個小建議
如果你常用 Git(你目前 DevOps / CI / Jenkins workflow 看起來是這樣),最推薦記住 這 6 個核心指令:
git log --oneline --graph
git reflog
git rebase -i
git cherry-pick
git reset --hard
git clean -fd
這份會非常接近 資深工程師 Git 操作指南。【Git】茶包射手