软件开发新手入门五大核心技能之版本控制工具(五)
第七章 Git 高级技巧与实用配置
当你在项目里越用越顺手,总会碰到一些“常规操作不够用”的场景——比如不想跟踪某个文件、临时想切分支但工作区没收拾干净、或者嫌命令太长想偷个懒。这些时候,Git 的进阶功能就派上用场了。
7.1 .gitignore —— 忽略不需要跟踪的文件
项目根目录下放一个 .gitignore 文件,里面写清楚哪些文件或目录 Git 应该直接无视。这东西几乎每个项目都得配,不然一不小心把编译产物、依赖包或本地配置给提交上去,够头疼的。

常见需要忽略的内容:
- 编译产物:
*.class、*.o、*.exe - 依赖目录:
node_modules/、vendor/、__pycache__/ - 环境配置文件:
.env、*.local - IDE 配置:
.idea/、.vscode/、*.swp - 日志文件:
*.log - 系统文件:
.DS_Store、Thumbs.db
一个典型的 .gitignore 示例:
# 忽略所有 .log 文件
*.log
# 但跟踪这个特定的 .log 文件(例外规则)
!important.log
# 忽略 build 目录下的所有内容
build/
# 忽略根目录下的 temp 文件
/temp
# 忽略 doc 下所有 .txt 文件,但保留 notes.txt
doc/*.txt
!doc/notes.txt
# 忽略所有以 ~ 结尾的文件
*~
# 忽略 node_modules 目录
node_modules/
# 忽略环境变量文件
.env
.env.local
如果想看看当前哪些文件被忽略了,用这条命令:
git status --ignored
7.2 贮藏(Stash) —— 临时保存工作区
正改到一半,突然要切换到其他分支修个紧急 bug,又舍不得提交那半成品代码?git stash 就是干这个的。它能把工作区和暂存区的修改存到一个“堆栈”里,让工作区恢复干净,等切回来再恢复。
# 贮藏当前修改(包括暂存区和工作区)
git stash
# 贮藏时添加描述
git stash push -m "WIP: login feature"
# 查看贮藏列表
git stash list
# 应用最近的贮藏(保留贮藏记录)
git stash apply
# 应用特定贮藏
git stash apply stash@{1}
# 应用并删除贮藏
git stash pop
# 删除贮藏
git stash drop stash@{0}
# 清空所有贮藏
git stash clear
# 从贮藏创建分支(如果贮藏的改动跟当前分支冲突了,用这招)
git stash branch new-branch stash@{0}
7.3 别名(Alias) —— 自定义命令
Git 的命令有时候确实长得有点过分。比如每次想看个漂亮的日志图,都得敲一长串 log --oneline --graph --decorate --all。别名就是用来解决这个问题的:把长命令映射成短单词,省时省力。
# 配置别名
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.st status
git config --global alias.lg "log --oneline --graph --decorate --all"
git config --global alias.unstage "reset HEAD --"
git config --global alias.last "log -1 HEAD"
git config --global alias.tree "log --graph --pretty=oneline --abbrev-commit"
# 使用别名
git st # 代替 git status
git lg # 精美的日志图
git unstage file
git last
7.4 子模块 —— 管理外部依赖
当一个项目依赖另一个 Git 仓库(比如某个第三方库),而且你想把这个库直接作为项目的一个子目录来管理,子模块是最干净的做法。它让你把外部仓库的某个固定版本嵌进来,同时又保持了各自独立的提交历史。
# 添加子模块
git submodule add https://github.com/jquery/jquery.git libs/jquery
# 克隆包含子模块的仓库(需要额外拉取)
git clone --recursive
# 或在已克隆的仓库中初始化子模块
git submodule init
git submodule update
# 更新子模块到最新
git submodule update --remote
# 查看子模块状态
git submodule status
7.5 搜索与调试
代码写久了,难免要追查某行代码是谁改的、或者某个 bug 是哪个提交引入的。Git 提供了一整套搜索和调试工具。
# 按文本搜索历史(查找哪次提交引入了某行代码)
git grep "函数名" $(git rev-list --all)
# 使用 blame 查看每一行最后修改者
git blame hello.py
# 二分查找定位引入 bug 的提交(git bisect)
git bisect start
git bisect bad # 当前版本有 bug
git bisect good v1.0 # v1.0 没有 bug
# Git 会切换到一个中间提交,测试后标记
git bisect good # 如果这个版本正常
git bisect bad # 如果这个版本有 bug
# 重复直到找到第一个 bad 提交
git bisect reset # 退出二分模式
第八章 常见工作流与协作模式
一个人用 Git 怎么折腾都行,但一旦团队协作,就得商量好一套“玩法”。不同的团队规模、项目类型,适合不同的工作流。
8.1 集中式工作流(类似 SVN)
所有人直接往中央仓库的 master 分支推送。简单直接,适合两三个人临时搭伙的小项目。缺点也很明显:一旦两个人同时改了同一个文件,冲突随时可能爆发。
8.2 功能分支工作流(Feature Branch Workflow)
每个新功能、每个修复都在单独的分支上开发,开发完再合并回主分支。这是最普遍的做法,既能隔离风险,又能让代码审查有条不紊。
# 开发新功能
git checkout -b feature-awesome
# ... 开发,多次提交
git push -u origin feature-awesome
# 创建 Pull Request / Merge Request
# 代码审查通过后合并
git checkout master
git pull
git merge --no-ff feature-awesome
git push
git branch -d feature-awesome
8.3 Git Flow(经典分支模型)
如果你所在的项目有严格的发布周期,Git Flow 几乎是行业标准。它定义了两种长期分支:master(生产环境代码)和 develop(开发主线),外加三种临时分支:feature/*、release/*、hotfix/*。
# 初始化 Git Flow(需要安装 git-flow)
git flow init
# 开始新功能
git flow feature start login
# 完成功能(合并到 develop)
git flow feature finish login
# 开始发布
git flow release start 1.0.0
# 更新版本号、文档
git flow release finish 1.0.0
8.4 GitHub Flow(简化版)
GitHub 自己推崇的极简流程:master 分支始终保持可部署状态,新功能从 master 拉分支,开发完提 PR,合并后立即部署。没有 develop 分支,没有 release 分支,干净利落,特别适合持续部署的团队。
8.5 Fork & Pull Request(开源协作)
这是开源项目的标准姿势:你 Fork 原仓库到自己账户,克隆自己的 Fork,修改后推送,然后向原仓库提交 Pull Request。原仓库维护者审核代码、合并。
# 添加上游仓库(原项目)
git remote add upstream https://github.com/original/repo.git
# 获取上游更新
git fetch upstream
# 将上游 master 合并到本地 master
git checkout master
git merge upstream/master
# 推送同步到自己的 fork
git push origin master
第九章 常见问题与解决方案
遇到问题别慌,Git 的设计大多数情况都能“兜底”。下面这几个坑几乎每个开发者都会踩到。
9.1 如何撤销已经 push 的提交?
分两种情况:如果你能接受改写历史(比如只有你一个人在用这个分支),用 reset 强制推送;如果已经多人协作,用 revert 生成一个反向提交,不破坏历史。
# 方法1:回退本地并强制推送(会改写历史)
git reset --hard HEAD~1
git push --force-with-lease origin master
# 方法2:使用 git revert 创建反向提交(安全,不破坏历史)
git revert HEAD # 撤销最近一次提交,生成新提交
git push origin master
9.2 忘记添加某个文件到上一次提交
简单:把文件加进来,然后用 --amend 补进上次提交,连注释都不用改。
git add forgotten.txt
git commit --amend --no-edit
9.3 提交信息写错了(未 push)
git commit --amend -m "新的正确信息"
9.4 误删分支,如何恢复?
分支虽然被删了,但提交记录还在 reflog 里。找到最后一次提交的哈希,重新建分支即可。
# 找到被删除分支的最后一次提交哈希
git reflog
# 基于该哈希创建新分支
git branch recovered-branch
9.5 如何合并某个分支的特定提交(cherry-pick)?
有时候你只想把另一个分支上的某一次改动拉过来,而不是整个分支的合并。用 git cherry-pick。
# 切换到目标分支
git checkout master
# 将 feature 分支上的某次提交应用到当前分支
git cherry-pick
9.6 如何清空工作区所有未跟踪文件?
临时文件、构建产物堆了一堆,想一次性清理干净?git clean 就是干这个的,但操作前最好先用 -n 预览一下。
# 查看哪些文件会被删除(dry-run)
git clean -n
# 删除未跟踪文件
git clean -f
# 同时删除未跟踪目录
git clean -fd
# 删除 .gitignore 忽略的文件也删(危险)
git clean -x
第十章 图形化工具与 IDE 集成
命令行是基本功,但图形化界面能帮你更直观地理解 Git 的内部逻辑。尤其对于刚接触分支、合并操作的新手,可视化工具能瞬间看明白发生了什么。
10.1 常用 GUI 客户端
- :Git 自带,运行
Git GUI
git gui即可。 - :查看历史用
GitK
gitk。 - (Windows/Mac,免费)
Sourcetree
- (跨平台,功能强大)
GitKraken
- (简洁够用)
GitHub Desktop
- :内置 Git 支持,点击即可提交、推送、分支管理,而且对冲突解决支持得很好。
VS Code
10.2 VS Code 内置 Git 常用操作
在 VS Code 左侧的“源代码管理”面板里,你能看到所有更改、暂存文件、输入提交信息、推送一气呵成。分支切换直接点击左下角当前分支名称。查看差异、解决冲突都有友好的内联界面。
综合实战:基于 Git 的协作模拟
光说不练假把式。假设你和同事合作开发一个 Web 项目,你负责“用户注册”,同事负责“用户登录”。下面是一套完整的协作流程——从克隆到合并,再到后续迭代。
# 第一天:克隆项目
git clone https://github.com/company/webapp.git
cd webapp
# 创建你的功能分支
git checkout -b feature-register
# 添加注册功能文件
echo "" > register.html
git add register.html
git commit -m "feat: 添加注册页面基础结构"
# 同事也创建了他的分支
git checkout -b feature-login # 在他的电脑上
# 你继续完善注册功能
echo "后端验证逻辑" >> register.html
git commit -am "feat: 注册表单后端验证"
# 同事提交他的工作
echo "登录框" > login.html
git add login.html
git commit -m "feat: 添加登录页面"
# 同事推送他的分支
git push origin feature-login
# 你推送你的分支
git push origin feature-register
# 在 GitHub/GitLab 上分别创建 Pull Request 到 main 分支
# 代码审查后,合并两个 PR
# 第二天,你需要基于最新的 main 继续工作
git checkout main
git pull origin main # 获取别人合并后的最新代码
# 删除本地已合并的功能分支
git branch -d feature-register
# 创建新的功能分支
git checkout -b feature-profile
就这样,一个典型的 Git 协作循环就完整走了一遍。从一开始的各自开发,到推送、提 PR、审查合并,再到拉取最新代码继续下一个功能——整个链条环环相扣。熟练之后,你会发现这一切都变成了肌肉记忆。