Git:日常使用与安全回退¶
Git 管理文件历史和分支;GitLab 则是在服务器上托管 Git 仓库,并增加成员权限、Merge Request 和 CI/CD。日常使用 Git 时,最重要的是弄清改动目前位于哪一层,以及它是否已经推送给别人。
四个位置与三个检查命令¶
| 位置 | 保存什么 | 常用命令 |
|---|---|---|
| 工作目录 | 正在编辑、尚未暂存的文件 | git status、git diff |
| 暂存区(stage) | 下一次 commit 准备包含的内容 | git add、git diff --staged |
| 本地仓库 | 已经 commit、可能尚未上传的历史 | git log、git commit |
| 远程仓库 | GitLab 等服务器上的共享历史 | git fetch、git pull、git push |
不知道当前状态时先执行:
git status 看文件和分支状态,git diff 看未暂存变化,git diff --staged 看下一次提交实际包含什么。提交前检查差异,可以避免把密码、日志或无关修改一起提交。
基础配置与克隆¶
首次使用设置提交身份:
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
git config --global init.defaultBranch main
git config --list
从 GitLab 获取仓库:
SSH 适合长期协作。首次连接服务器时应核对主机指纹,不要为了省事关闭 SSH 主机密钥校验。使用 HTTPS 时建议使用 Personal Access Token,不要把账户密码或令牌直接写入命令和脚本。
将已有目录推到 GitLab¶
先在 GitLab 建立空项目,再在本地目录执行:
cd existing-project
git init
git branch -M main
# 先检查并完善 .gitignore
git status
git add .
git diff --staged
git commit -m "chore: initialize repository"
git remote add origin git@gitlab.example.com:group/project.git
git push -u origin main
.gitignore 应排除密钥、环境变量文件、日志、依赖缓存、构建产物和 IDE 临时文件。文件一旦进入提交历史,后来加入 .gitignore 不会自动把它从历史中移除。
常见规则示例:
日常开发流程¶
推荐每个需求或修复创建独立分支,不直接修改 main:
git switch main
git pull --ff-only origin main
git switch -c feature/add-login
# 编辑后检查并提交
git status
git diff
git add src/login.py
git diff --staged
git commit -m "feat: add login validation"
git push -u origin feature/add-login
推送后在 GitLab 创建 Merge Request,等待测试和审核通过后再合入 main。
为什么使用 git pull --ff-only¶
普通 git pull 等于先 fetch 再 merge,可能产生没有预期到的合并提交。--ff-only 只允许安全的快进;本地与远程发生分叉时会停止,让你先查看差异再决定 merge 或 rebase。
add 与 commit¶
暂存指定文件¶
git add docs/readme.md
git add src/app.py tests/test_app.py
git diff --staged
git commit -m "fix: handle empty request"
比起直接 git add .,指定文件更容易控制提交范围。
按修改块选择暂存¶
当一个文件里混有两类改动时,git add -p 可以只选择本次提交需要的代码块。
提交信息¶
一次提交只完成一个清晰目标,常见格式:
feat: add user login
fix: correct Runner tag
docs: explain Git rollback
refactor: simplify configuration loader
test: add permission tests
chore: update ignored files
不要把大范围格式化、功能开发和故障修复混在一个提交里,否则审核、定位和回退都会变困难。
分支管理¶
git branch # 查看本地分支
git branch -a # 查看本地和远程分支
git switch main # 切换分支
git switch -c feature/xxx # 创建并切换
git branch -d feature/xxx # 删除已经合并的本地分支
git push origin --delete feature/xxx # 删除远程分支
常用命名:
| 类型 | 示例 | 用途 |
|---|---|---|
| 功能 | feature/add-login |
新功能 |
| 修复 | fix/ssh-timeout |
普通问题修复 |
| 紧急修复 | hotfix/payment-error |
线上紧急故障 |
| 文档 | docs/git-handbook |
文档变更 |
fetch、pull 与 push¶
| 命令 | 做什么 | 是否改变当前文件 |
|---|---|---|
git fetch origin |
下载远程分支和提交信息 | 否 |
git pull --ff-only |
下载并将当前分支安全快进 | 是 |
git push |
上传本地提交 | 不改变本地文件 |
想先查看远程发生了什么:
远程 push 被拒绝时,不要立即强推。先 fetch,确认远程是否有同事的新提交,再选择合并或变基。
merge 与 rebase¶
merge¶
merge 保留两条分支的发展过程,适合共享分支或 GitLab Merge Request:
团队项目通常通过 GitLab MR 完成合并,以保留审核和 CI 记录。
rebase¶
rebase 将当前分支的提交重新放到新基线上,历史更线性,但会改变提交 ID:
只对自己控制的功能分支执行 rebase。已被多人使用的共享分支不要改写历史。个人分支 rebase 后若必须更新远程:
使用 --force-with-lease,不要使用裸 --force;前者会在远程出现未知新提交时拒绝覆盖。
解决冲突¶
冲突表示 Git 无法自动判断两份修改如何组合。先确认当前正在 merge 还是 rebase:
打开冲突文件,处理这些标记:
处理后继续:
如果发现合并方向不对,可以恢复到开始前:
冲突标记处理完不代表逻辑正确,还要运行测试或至少检查相关配置。
回退:先判断是否已经推送¶
尚未提交¶
| 目的 | 命令 | 结果 |
|---|---|---|
| 取消暂存但保留修改 | git restore --staged file |
文件回到工作目录 |
| 丢弃某文件未提交修改 | git restore file |
文件恢复到最近提交,修改通常无法找回 |
| 查看未跟踪文件 | git status |
先确认目标,不要直接批量清理 |
已提交但尚未推送¶
修改最近一次提交说明或补文件:
撤销最近提交但保留修改:
git reset --hard 会同时丢弃提交和工作目录改动,风险很高;执行前应确认精确目标和是否有需要保留的文件。
已经推送或合并¶
使用 revert 创建一个反向提交,不改写共享历史:
已经共享的提交不要通过 reset --hard 加强制推送来删除,否则同事的分支、MR 和 CI 记录都会混乱。
找回误删提交¶
reflog 记录本地 HEAD 的移动,可用于找回最近误删的提交,但它不是长期备份,应尽快创建救援分支。
临时保存工作¶
需要临时切换任务时:
git stash push -m "wip: investigate runner issue"
git switch main
# 返回原分支后
git switch feature/xxx
git stash list
git stash pop
stash 适合短期保存,不应替代正常提交。长期堆积的 stash 缺少清晰上下文,也无法方便地与同事共享。
cherry-pick¶
只把另一个分支中的某次提交带过来:
适合将一个独立且已经验证的修复补到发布分支。执行前确认该提交没有依赖其他未包含的改动。
标签与发布¶
使用附注标签标记正式版本:
发布记录应关联 Git tag、提交 SHA、容器镜像完整标签、变更说明和部署时间。生产镜像优先使用不可变的 commit SHA 或版本标签,不要只记录 latest。
查看历史与定位问题¶
git log --oneline --graph --all --decorate
git show <commit-id>
git diff <old-commit>..<new-commit>
git blame path/to/file
git blame 用于查找某行最后一次变更的提交入口,不应简单用于“找责任人”;应结合 commit、MR 和当时需求理解修改原因。
每天可照着做的流程¶
开始工作:main 拉取最新 → 创建 feature/fix 分支
开发过程:小步修改 → status/diff → 小步提交
团队协作:push 功能分支 → 创建 MR → CI 和审核
完成合并:更新本地 main → 删除已完成分支
正式发布:创建 tag → 构建不可变镜像 → 记录部署版本
发生错误:未共享再考虑 reset;已共享优先 revert
常见问题¶
| 现象 | 优先处理 |
|---|---|
| push 提示远程有新提交 | git fetch origin,检查差异后 merge 或 rebase,禁止直接强推 |
| pull 后出现意外 merge commit | main 分支改用 git pull --ff-only |
| 提交时漏了文件 | 未推送时 git commit --amend |
| 已推送的提交需要撤销 | git revert <commit-id> |
| 提交了密码或密钥 | 立即轮换凭据;只删除当前文件不够,还要处理历史与访问风险 |
| 分支落后 main 很久 | git fetch origin && git rebase origin/main,处理冲突后重新测试 |
| 不知道自己改了什么 | git status、git diff、git diff --staged |