【Treeman】Git相關
- 【GitLab】相關
- 【GitLab】gitlab-runner 執行環境種類
- 【GitLab】升級相關
- 【GitLab】runner 使用 k8s 流程說明
- 【GitLab】CI/CD Settings 說明
- 【GitLab】使用ssh clone 專案
- 【GitHub】相關
- 【Git】語法觀念
- 【Git】相關連結
- 【Git】還原相關
- 【Git】TorotoiseGit 占用資源解決方法
- 【Git】windows系統 warning: LF will be replaced by CRLF in
- 【Git】checkout 與 switch 比較
- 【Git】HEAD 是什麼
- 【Git】每個 commit 不都是從某個分支出來的嗎?
- 【Git】head, tag, commit, branch的關係
- 【Git】git revert <commit> 和 git checkout <commit> 差異
- 【Git】常用指令
- 【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 <base>;若 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" executor
K8s 裡 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 <<EOF
{
"auths": {
"${CI_REGISTRY}": {
"auth": "$(printf "%s:%s" "$CI_REGISTRY_USER" "$CI_REGISTRY_PASSWORD" | base64 -w0)"
}
}
}
EOF
- echo -e 'FROM alpine:3.20\nCMD ["echo","kaniko build OK"]' > 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 <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
<a href="http://10.2.2.3/user/k8s-deploy/-/commits/master"> <img alt="pipeline status" src="http://10.2.11.139/srou/live-k8s-deploy/badges/master/pipeline.svg" /> </a> -
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】語法觀念
【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> |
版本歷史 | 無關 | 否 | 安全回復 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_hash>
-
保留歷史紀錄
-
安全的還原方式,尤其在多人開發時
適用情境:
-
上線後發現某次 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
【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 <branch> |
git switch <branch> |
切換到已存在的分支 |
git checkout -b <new-branch> |
git switch -c <new-branch> |
建立並切換到新分支 |
git checkout <commit> |
❌(建議保留 checkout) |
切換到某個 commit 狀態(暫不取代) |
git checkout <file> |
git restore <file> |
還原工作區中的單一檔案 |
git checkout -- <file> |
git restore <file> |
同上 |
git checkout <commit> -- <file> |
git restore --source <commit> <file> |
還原某個 commit 中的檔案 |
git checkout . |
git restore . |
還原所有工作區的檔案 |
git checkout HEAD <file> |
git restore --source=HEAD <file> |
還原最新 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 <commit> 移動到某個版本試驗、測試(會進入 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-hash> |
| 從某個 commit 測試 / 編譯 | git switch --detach <commit> |
| 在 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 <commit> |
✅(分離) | ❌ | ❌ | ❌ |
git switch -c new-feature |
✅ | ✅(新建) | ❌ | ❌ |
✅ 總結一句話:
commit 是內容
branch/tag 是「名字」,用來指向某個 commit
HEAD 是「你目前在哪裡」,通常跟著分支動,也可以離開分支進入 detached 狀態
【Git】git revert <commit> 和 git checkout <commit> 差異
git revert <commit> 和 git checkout <commit> 雖然都能「回到某個 commit」,但本質上用途完全不同。以下為詳細說明與比較。
一、git revert <commit>
功能說明:
-
用來**「反向操作」某個已提交的 commit**。
-
Git 會建立一個新的 commit,內容是將指定的 commit 所做的變更還原回去。
-
原本的 commit 仍然會保留在歷史中。
特性:
-
安全,適合多人協作情境。
-
保留歷史紀錄。
-
可選擇 revert 多個 commit(可搭配
-n進行批次處理)。
使用情境:
-
已經 push 到遠端,但發現某個 commit 有誤,需要「撤銷」那次變更,但不想刪除歷史。
-
緊急修復 bug,並希望讓其他人看見這次的「撤銷行為」。
範例:
git revert a1b2c3d
會產生一個新的 commit,把 a1b2c3d 的內容還原。
二、git checkout <commit>(或 git switch --detach <commit>)
功能說明:
-
將當前工作目錄切換到某個過去的 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 | ✅ 是 | ❌ 否 | ✅ 是 | 撤銷已推送的錯誤 commit |
git checkout <commit> |
切換版本 | ❌ 否 | ❌ 否 | ⚠️ 不適合推送 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> |
套用指定 commit | hotfix |
| Revert | git revert <commit> |
回復某 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 <commit-id>
用途:
| 情境 | 範例 |
|---|---|
| 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 <commit>
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 <commit-id>
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 操作指南。
