GitLab中的Git使用
2025-11-12
教程合集
00

目录

Git & GitLab 实战手册(C 项目、MR 流程、冲突与回退全套)
目录
1. 环境与账号准备(一次性)
2. 新建与克隆仓库
3. 分支与协作流程(GitLab Flow 示例)
4. 常用 Git 操作清单(带命令)
5. GitLab 项目侧管控与合规设置
6. 大文件与办公文件(LFS)
7. CI/CD:模板与要点(含 C/ Python/Android 片段)
8. Issue/MR 模板与规范
9. Fork 工作流(跨部门/外部协作)
10. 常见坑与排查清单
11. 常用 .gitignore 片段
12. 一周上手路线图
13. C 项目标准目录与 Makefile(可直接用)
14. GitLab CI for C:最小与增强模板
14.1 最小可用 .gitlab-ci.yml
14.2 增强版(风格、静态检查、覆盖率)
15. MR 模板(合并请求模板)
16. 发布与回滚(Tag/Release 策略)
17. 本地质量闸:Git Hook(pre-commit)
18. 工作场景向 Git 常用命令速查 + 冲突与回退实战
基础配置与查看
增删改提交流程
分支与远端
合并、变基与挑拣
暂存临时工作(stash)
标签与发布
冲突处理(merge/rebase 双示例)
回退/撤销(四层)
19. git checkout 用法速查与对照
A. 切换/创建分支
远端分支与跟踪
B. 还原文件/目录到某个版本(不切分支)
C. 冲突场景下的 ours/theirs
D. 历史探索与“救命”
20. 将 git checkout 融入你的日常脚本
(1)从 main 开分支开发 → MR 到 develop
(2)更新 MR 分支以跟上 develop(rebase 流)
(3)不切分支,快速借文件
(4)回退与撤销(含 checkout 等价)
21. 常见陷阱与提示(与 checkout 相关)

Git & GitLab 实战手册(C 项目、MR 流程、冲突与回退全套)

  • 通用 GitLab 协作与项目治理(账号、分支、MR、CI/CD、合规、模板等);
  • 面向 C 语言项目 的目录结构、Makefile 与 GitLab CI 模板(最小与增强版);
  • 工作场景向 Git 命令速查(含冲突/回退/恢复的完整示例);
  • git checkoutgit switch / git restore 的一一对照与融入脚本。

目录


1. 环境与账号准备(一次性)

目标: 身份明确、连接稳定、权限最小化。

bash
展开代码
git --version git config --global user.name "张三" git config --global user.email "zhangsan@your.org" git config --global init.defaultBranch main # 建议:开启签名提交(如可用 GPG/SSH 签名) git config --global commit.gpgsign true

SSH Key(推荐)

bash
展开代码
ssh-keygen -t ed25519 -C "zhangsan@your.org" # 将 ~/.ssh/id_ed25519.pub 添加至 GitLab -> User Settings -> SSH Keys ssh -T git@gitlab.com # 或你们自建域名

访问令牌(HTTPS / API / CI 用)

  • GitLab → User Settings → Access Tokens 创建 PAT,scope 最小化(read_repository/write_repository)。
  • 存入密码管理器或 CI 变量,不要写进仓库。

2. 新建与克隆仓库

A)远端已有仓库 → 本地克隆

bash
展开代码
git clone git@gitlab.com:group/project.git cd project

B)本地有代码 → 推送到新仓库

bash
展开代码
cd myproject git init git remote add origin git@gitlab.com:group/project.git git add . git commit -m "chore: initial commit" git branch -M main git push -u origin main

规范: 项目可见性设为 Private;保护 main/release/* 分支(见 §5)。


3. 分支与协作流程(GitLab Flow 示例)

分支角色建议

  • main:受保护(禁止直接 push,只能 MR 合并),稳定/生产。
  • develop:集成分支(建议也受保护,MR 合并)。
  • feature/*fix/*:个人/任务分支,短期存在。

起分支 → 提交 → 推送 → 发起 MR

bash
展开代码
# 从最新主线切出功能分支 git checkout main git pull git checkout -b feature/invoice-import # 开发与提交(建议采用 Conventional Commits) git add src/invoice_parser.py git commit -m "feat(invoice): add excel importer with validation" git push -u origin feature/invoice-import

在 GitLab 发起 MR

  • 目标:developmain;填写描述、关联 Issue、勾选“删除源分支”;至少 1–2 人审核。

保持分支更新(Rebase 保持整洁)

bash
展开代码
git fetch origin git rebase origin/main # 在 feature 分支上 # 若有冲突:修复 -> git add -> git rebase --continue git push --force-with-lease

4. 常用 Git 操作清单(带命令)

查看状态/差异/历史

bash
展开代码
git status git diff git diff --staged git log --oneline --graph --decorate --all git show <commit> git blame path/to/file

暂存/提交/修正

bash
展开代码
git add src/a.c include/a.h git commit -m "feat(parser): add tokenizer with error codes" git commit --amend # 修正上一条提交(未共享时用)

撤销暂存/工作区修改

bash
展开代码
git restore --staged src/a.c git restore src/a.c

忽略文件并清理历史中的已跟踪项

展开代码
# .gitignore /build/ *.o *.a *.so
bash
展开代码
git rm -r --cached build git commit -m "chore: apply .gitignore to build artifacts"

5. GitLab 项目侧管控与合规设置

保护主线与审批

  • Settings → Repository → Protected branches:保护 maindevelop(禁止直接 push / 必须 MR)。
  • Settings → General → Merge request approvals:设置最少审批人数(如 1–2)。
  • Merge requests:勾选 Pipelines must succeed;可选 Rebase before mergeOnly fast-forward

CODEOWNERS(强制特定路径由特定人审核)

展开代码
# 根目录新增 CODEOWNERS docs/** @finance-reviewer src/budget/** @lead-dev @qa

安全

  • 开启 2FA;把密钥放到 CI/CD Variables,勾选 Masked/Protected

6. 大文件与办公文件(LFS)

bash
展开代码
git lfs install git lfs track "*.xlsx" git add .gitattributes git add data/report.xlsx git commit -m "chore(data): add LFS-tracked report" git push

LFS 有存储/带宽成本;敏感信息建议脱敏或放对象存储,仅在仓库放引用。


7. CI/CD:模板与要点(含 C/ Python/Android 片段)

通用要点

  • Settings → CI/CD → Variables 管理密钥,重要变量设 Protected
  • MR 勾选 Pipelines must succeed
  • 部署用 environmentsmanual 步骤做受控发布。

Python 最小模板(可根据需要取用)

yaml
展开代码
stages: [test, build] default: image: python:3.11 cache: paths: [ .cache/pip ] before_script: - pip install -U pip - pip install -r requirements.txt variables: PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip" test: stage: test script: - pytest -q artifacts: when: always reports: junit: junit.xml build: stage: build script: - python setup.py sdist bdist_wheel artifacts: paths: - dist/ rules: - if: '$CI_COMMIT_BRANCH == "main"'

Android/Java 片段(示意)

yaml
展开代码
image: gradle:8-jdk17 stages: [build] build: stage: build script: - gradle assembleDebug artifacts: paths: [ app/build/outputs/apk/debug/ ]

C 项目 CI 请见 §14(最小与增强模板)。


8. Issue/MR 模板与规范

提交信息(Conventional Commits)

  • feat: 新增发票导入校验
  • fix: 修复汇总口径浮点精度问题
  • chore(ci): 拆分测试与构建阶段

MR 模板(.gitlab/merge_request_templates/默认.md

md
展开代码
### 变更内容 - ### 关联 Issue - Closes # ### 风险与影响 - 数据库/接口变更? - 是否需要回滚方案? ### 校验清单 - [ ] 本地自测通过 - [ ] 单元测试通过 - [ ] 更新了文档/变更说明

Issue 模板(.gitlab/issue_templates/缺陷.md

md
展开代码
### 现象 ### 期望 ### 复现步骤 ### 截图/日志 ### 影响范围

9. Fork 工作流(跨部门/外部协作)

bash
展开代码
# 在 GitLab 上 fork 主仓库 git clone git@gitlab.com:you/project-fork.git git remote add upstream git@gitlab.com:group/project.git # 同步主仓 git fetch upstream git checkout main git merge upstream/main git push origin main # 在 fork 内开发并向主仓发 MR

10. 常见坑与排查清单

  • 直接推 main? 保护分支 + MR 审批。
  • 混入大文件或密钥? git rm --cached + 立刻轮换密钥;必要时历史清理(慎重)。
  • 长期不更新导致巨型冲突? 小步推进,频繁 rebase origin/main
  • CI 变量泄露? 变量上勾选 Masked/Protected,日志勿 echo
  • 二进制导致仓库膨胀? LFS 或制品仓/对象存储。
  • 多人改同一文件? CODEOWNERS + 模块边界。

11. 常用 .gitignore 片段

gitignore
展开代码
# OS / IDE .DS_Store Thumbs.db .idea/ .vscode/ # C/C++ 构建 /build/ *.o *.a *.so *.dll *.dylib # 覆盖率 *.gcda *.gcno *.gcov /build/coverage* /build/coverage_html/ # 其他 dist/ node_modules/

12. 一周上手路线图

  • Day 1:SSH/PAT、克隆/推送、分支与 MR。
  • Day 2:冲突解决(rebase/merge)、标签与 Release。
  • Day 3:项目保护、审批与 CODEOWNERS。
  • Day 4:CI 基础(测试→构建→制品)。
  • Day 5:变量与部署、环境与回滚策略。
  • Day 6–7:清理历史、LFS、Fork 协作、规范化模板落地。

13. C 项目标准目录与 Makefile(可直接用)

展开代码
project/ ├─ include/ # 头文件 │ └─ project.h ├─ src/ # 源文件 │ ├─ project.c │ └─ utils.c ├─ tests/ # 简单单元测试(main 方式或引入 CMocka/Unity) │ └─ test_project.c ├─ build/ # 编译输出(由 Makefile 生成) ├─ Makefile ├─ .gitignore └─ .clang-format # 代码风格可选

示例 Makefile(GCC)

makefile
展开代码
CC ?= gcc CFLAGS ?= -O2 -Wall -Wextra -Werror -std=c11 -Iinclude LDFLAGS ?= SRC := $(wildcard src/*.c) OBJ := $(patsubst src/%.c,build/%.o,$(SRC)) BIN := build/app TEST_SRC := $(wildcard tests/*.c) TEST_BIN := build/test_app .PHONY: all clean test format lint coverage all: $(BIN) build/%.o: src/%.c | build $(CC) $(CFLAGS) -c $< -o $@ $(BIN): $(OBJ) | build $(CC) $(OBJ) -o $@ $(LDFLAGS) build: mkdir -p build clean: rm -rf build # 简单测试:把 tests/*.c 和 src 需要的对象一起链接 test: $(OBJ) | build $(CC) $(CFLAGS) $(TEST_SRC) $(OBJ) -o $(TEST_BIN) $(LDFLAGS) $(TEST_BIN) # 代码格式:需要安装 clang-format format: clang-format -i $(SRC) $(TEST_SRC) $(wildcard include/*.h) # 静态检查:需要安装 cppcheck lint: cppcheck --enable=all --inconclusive --std=c11 --inline-suppr \ -Iinclude src tests # 覆盖率(可选):需要 gcov/lcov coverage: CFLAGS += --coverage coverage: LDFLAGS += --coverage coverage: clean test lcov --capture --directory . --output-file build/coverage.info genhtml build/coverage.info --output-directory build/coverage_html

14. GitLab CI for C:最小与增强模板

14.1 最小可用 .gitlab-ci.yml

MR 必须通过构建与测试;main 上额外打包制品。

yaml
展开代码
stages: [build, test, package] variables: GIT_STRATEGY: fetch build: stage: build image: gcc:13 script: - make clean - make all artifacts: paths: [ "build/app" ] rules: - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' - if: '$CI_COMMIT_BRANCH == "main"' - if: '$CI_COMMIT_BRANCH == "develop"' test: stage: test image: gcc:13 script: - make test needs: [build] rules: - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' - if: '$CI_COMMIT_BRANCH == "main"' - if: '$CI_COMMIT_BRANCH == "develop"' package: stage: package image: alpine:3.20 script: - mkdir -p dist && cp build/app dist/ - tar -czf dist/app-${CI_COMMIT_SHORT_SHA}.tar.gz dist/app artifacts: paths: [ "dist/app-*.tar.gz" ] expire_in: 7 days rules: - if: '$CI_COMMIT_BRANCH == "main"'

14.2 增强版(风格、静态检查、覆盖率)

yaml
展开代码
stages: [format, lint, build, test, coverage, package] format: stage: format image: alpine:3.20 before_script: - apk add --no-cache clang-extra-tools script: - make format # 若要强制格式一致,可开启: # git diff --exit-code || (echo "Run make format"; exit 1) rules: - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' lint: stage: lint image: alpine:3.20 before_script: - apk add --no-cache cppcheck script: - make lint rules: - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' build: stage: build image: gcc:13 script: - make clean - make all artifacts: paths: [ "build/app" ] rules: - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' - if: '$CI_COMMIT_BRANCH == "main"' - if: '$CI_COMMIT_BRANCH == "develop"' test: stage: test image: gcc:13 script: - make test needs: [build] rules: - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' - if: '$CI_COMMIT_BRANCH == "main"' - if: '$CI_COMMIT_BRANCH == "develop"' coverage: stage: coverage image: alpine:3.20 before_script: - apk add --no-cache lcov script: - make coverage - lcov --list build/coverage.info | tail -n +1 artifacts: when: always paths: [ "build/coverage.info", "build/coverage_html" ] reports: coverage_report: coverage_format: cobertura path: build/coverage.info rules: - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' - if: '$CI_COMMIT_BRANCH == "main"' - if: '$CI_COMMIT_BRANCH == "develop"' package: stage: package image: alpine:3.20 script: - mkdir -p dist && cp build/app dist/ - tar -czf dist/app-${CI_COMMIT_SHORT_SHA}.tar.gz dist/app artifacts: paths: [ "dist/app-*.tar.gz" ] expire_in: 14 days rules: - if: '$CI_COMMIT_BRANCH == "main"'

若仅在受保护分支允许部署密钥,请将发布 Job 限制在 main 并相应设置变量为 Protected


15. MR 模板(合并请求模板)

文件:.gitlab/merge_request_templates/默认.md

md
展开代码
### 变更内容 - ### 关联 Issue - Closes # ### 影响面与风险 - 接口/ABI/配置变更? - 性能/内存占用变化? ### 校验清单 - [ ] 本地 `make test` 通过 - [ ] clang-format 已执行 - [ ] CI build/test/coverage 通过 - [ ] 评审意见已处理

16. 发布与回滚(Tag/Release 策略)

bash
展开代码
# 确保 develop → main 的 MR 已合并且 CI 全绿 git checkout main git pull # 打标签 git tag -a v1.2.0 -m "release: v1.2.0" git push origin v1.2.0 # 在 GitLab Releases 页面基于 v1.2.0 生成说明并附制品

回滚:优先 git revert 生成反向提交;避免修改公共分支历史。


17. 本地质量闸:Git Hook(pre-commit)

.git/hooks/pre-commit(记得 chmod +x .git/hooks/pre-commit

bash
展开代码
#!/usr/bin/env bash set -e echo "[pre-commit] clang-format & cppcheck & unit tests" make format make lint make -s test

18. 工作场景向 Git 常用命令速查 + 冲突与回退实战

基础配置与查看

bash
展开代码
git config --global user.name "你的名字" git config --global user.email "you@your.org" git config --global core.editor "vim" # 或 code --wait git config --global init.defaultBranch main

状态/差异/历史

bash
展开代码
git status git diff git diff --staged git log --oneline --graph --decorate --all git show <commit> git blame path/to/file.c

增删改提交流程

选择性暂存与提交

bash
展开代码
git add -p # 按块选择更干净 git commit -m "feat(parser): add tokenizer with error codes" git commit --amend # 修正上一提交(未共享时)

撤销暂存/工作区修改

bash
展开代码
git restore --staged src/a.c git restore src/a.c # 丢弃工作区改动(危险)

忽略文件

gitignore
展开代码
/build/ *.o *.a *.so
bash
展开代码
git rm -r --cached build git commit -m "chore: apply .gitignore to build artifacts"

分支与远端

新建/切换/删除

bash
展开代码
git switch -c feature/log-rotate git switch main git branch -d feature/log-rotate git branch -D feature/log-rotate

远端同步

bash
展开代码
git remote -v git fetch origin git pull --rebase git push -u origin feature/x git push --force-with-lease

合并、变基与挑拣

合并

bash
展开代码
git switch develop git merge feature/x git merge --no-ff feature/x

变基

bash
展开代码
git switch feature/x git fetch origin git rebase origin/develop # 冲突:修复 -> git add -> git rebase --continue

挑拣提交

bash
展开代码
git switch release/1.2 git cherry-pick <commitA> <commitB>

暂存临时工作(stash)

bash
展开代码
git stash push -m "WIP: refactor io layer" git stash list git stash show -p stash@{0} git stash pop git stash apply stash@{1}

标签与发布

bash
展开代码
git tag -a v1.2.0 -m "release: v1.2.0" git push origin v1.2.0 git show v1.2.0

冲突处理(merge/rebase 双示例)

典型冲突标记

text
展开代码
<<<<<<< HEAD int parse(const char* s) { return 0; } ======= int parse(const char* s) { return errno; } >>>>>>> feature/errno

A:在 merge 中解决冲突

bash
展开代码
git switch develop git merge feature/errno # 冲突产生 git status # 编辑冲突文件 -> git add src/parser.c git commit # 或 git merge --continue

B:在 rebase 中解决冲突

bash
展开代码
git switch feature/errno git rebase origin/develop # 冲突 git status # 编辑 -> git add 冲突文件 git rebase --continue # 放弃变基: git rebase --abort

辅助

bash
展开代码
git diff --merge git checkout --theirs src/a.c # 选对方版本(冲突状态) git checkout --ours src/a.c # 选本方版本(冲突状态)

回退/撤销(四层)

层 1:工作区/索引

bash
展开代码
git restore path/to/file.c git restore --staged path/to/file.c

层 2:撤销最近提交但保留改动

bash
展开代码
git reset --soft HEAD~1 git reset HEAD~1 # mixed(默认):改动回到工作区

层 3:生成反向提交(安全,公共分支推荐)

bash
展开代码
git revert <bad-commit> git revert <A>..<B> git revert -m 1 <merge-commit>

层 4:硬重置(破坏性,仅私有分支)

bash
展开代码
git reset --hard HEAD~2 git push --force-with-lease

后悔药:reflog 恢复

bash
展开代码
git reflog git reset --hard <sha> # 或先拉个分支保存: git switch -c rescued <sha>

误提交敏感文件

bash
展开代码
git rm --cached secrets.txt echo "secrets.txt" >> .gitignore git commit -m "security: remove secrets from repo and ignore" # 立刻轮换密钥;如需历史清理,评估后使用 filter-repo 并与团队确认

历史整理(交互式变基)

bash
展开代码
git rebase -i HEAD~5 # pick -> squash/fixup 清理 WIP

审查前自检

bash
展开代码
make -s all && make -s test clang-format -i $(git ls-files '*.c' '*.h') git diff --check git diff origin/develop...HEAD git log origin/develop..HEAD --oneline

速查清单

  • 看状态:git status
  • 看差异:git diff / git diff --staged
  • 提交:git add -pgit commit -m "…"
  • 改最后一次:git commit --amend
  • 切/建分支:git switch <name> / git switch -c <name>
  • 同步:git fetchgit pull --rebasegit push
  • 合并:git merge --no-ff feature/x
  • 变基:git rebase origin/develop
  • 暂存工作:git stash push -m "…" / git stash pop
  • 回退安全:git revert <commit>
  • 回退激进:git reset --soft/mixed/hard <ref>
  • 救命:git reflog
  • 打标签:git tag -a vX.Y.Z -m "…" && git push origin vX.Y.Z

19. git checkout 用法速查与对照

Git ≥2.23 把“切分支”和“还原文件”拆成了 git switch / git restore。很多团队仍在用 git checkout,这里给出 两套写法对照

A. 切换/创建分支

bash
展开代码
git checkout develop # 切换到已存在分支 git switch develop git checkout -b feature/parser-refactor # 新建并切换 git switch -c feature/parser-refactor git checkout - # 回到上一个分支 git switch -

远端分支与跟踪

bash
展开代码
git checkout -t origin/develop git switch -c develop --track origin/develop git checkout --detach origin/main # 分离 HEAD 查看远端 main # 返回:git checkout develop

B. 还原文件/目录到某个版本(不切分支)

bash
展开代码
git checkout -- src/parser.c # 还原到索引版本 git restore src/parser.c git checkout HEAD -- src/parser.c # 还原到 HEAD git restore --source=HEAD src/parser.c git checkout main -- include/parser.h # 从其他分支取文件 git checkout 3f2a7c9 -- src/io.c git restore --source=main -- include/parser.h git restore --source=3f2a7c9 -- src/io.c

TIP:-- 避免与分支名混淆。git checkout -- . 会把所有已跟踪文件恢复到索引(谨慎)。

C. 冲突场景下的 ours/theirs

bash
展开代码
git checkout --theirs src/parser.c git checkout --ours src/parser.c git add src/parser.c # merge: git merge --continue # rebase: git rebase --continue

语义:merge 时 ours=当前分支、theirs=被合并分支;rebase 时 ours=你的提交、theirs=目标基线。

D. 历史探索与“救命”

bash
展开代码
git checkout 3f2a7c9 # 暂时回到历史(分离 HEAD) git checkout -b hotfix/from-3f2a7c9 # 拉分支保存 git reflog git checkout -b rescue @{-1} # 基于上一次位置开分支

20. 将 git checkout 融入你的日常脚本

(1)从 main 开分支开发 → MR 到 develop

bash
展开代码
git checkout main git pull origin main git checkout -b feature/parser-refactor git add src/parser.c include/parser.h git commit -m "feat(parser): refactor tokenizer and error handling" git push -u origin feature/parser-refactor # 在 GitLab 发起 MR(target=develop)

(2)更新 MR 分支以跟上 develop(rebase 流)

bash
展开代码
git fetch origin git checkout feature/parser-refactor git rebase origin/develop # 冲突:可用 git checkout --ours/--theirs 定向取版本 git add <冲突文件> git rebase --continue git push --force-with-lease

(3)不切分支,快速借文件

bash
展开代码
git checkout main -- include/common.h git commit -m "chore: sync common.h from main"

(4)回退与撤销(含 checkout 等价)

bash
展开代码
git checkout -- src/a.c # 撤销工作区某文件改动 git reset --soft HEAD~1 # 撤销最近提交但保留改动 git revert <bad-commit> # 公共分支安全回退 git checkout -b backup-before-hard-reset git reset --hard HEAD~2

21. 常见陷阱与提示(与 checkout 相关)

  • 忘记 --git checkout foo 可能被当成切分支;还原文件请写 git checkout -- foo
  • 谨慎 git checkout .:会把所有已跟踪文件恢复到索引;若索引不正确,会覆盖你的正确改动。
  • 公共/受保护分支禁止改历史amend/rebase/reset --hard 仅限私有分支;公共分支用 revert
  • ours/theirs 切换心中有数:merge 与 rebase 语义不同。

本文作者:冬月

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!