☰
Git日常防手抖六技:reflog、exclude、diff别名等实战技巧
2026/10/26 19:24:37 网站建设 项目流程

1. 这不是“高级命令合集”,而是日常开发中每天都在用的生存技巧

Git 的学习曲线有个特别真实的现象:刚入门时觉得add、commit、push就够用了;等项目跑起来,团队协作一上规模,突然发现每天有大量时间花在“怎么把刚才那个改错的文件撤回来”“为什么这个文件老是被我误提交”“上次我改的那个函数到底动了哪几行”“为什么每次打长命令都要敲三遍”这类琐事上。标题里列的这六项——引用日志(reflog)、忽略临时性本地修改、检查文本文件修改、命令别名、为临时提交建分支、移动提交到另一分支——根本不是什么“炫技彩蛋”,而是我在带多个跨地域团队、维护五个以上主干分支、平均每天处理 20+ 次本地操作的实战中,反复验证过、删减过、最终沉淀下来的六条“防手抖保命线”。

它们共同解决一个核心问题:如何让 Git 从一个冷冰冰的版本记录工具,变成你本地工作流的呼吸节奏本身。比如 reflog 不是让你去考古的,是当你reset --hard HEAD~3错了之后,30 秒内原路找回的保险绳;忽略临时修改不是为了偷懒,是防止.env.local或config-debug.php这类敏感/环境专属文件意外进仓库的物理隔离层;而“为临时指向的提交创建分支”,本质上是你在代码审查中途突然想验证一个补丁效果时,不用中断当前工作流就能开个沙盒的快捷键。这些技巧之所以被归为“十一”,不是因为它们排在第十一章,而是因为前十个章节教你怎么把车开起来,而这一章教你如何在暴雨夜、急弯道、没导航的情况下,不撞护栏、不熄火、还能顺手给后座乘客递杯水。如果你现在还在靠git log --oneline | head -20翻历史、靠手动复制粘贴改命令、靠删掉整个node_modules来解决冲突,那这篇就是为你写的——它不讲原理推导,只讲你明天早上打开终端第一件事该怎么做。

2. 核心技巧逐层拆解与底层逻辑还原

2.1 引用日志(reflog):Git 的本地操作黑匣子,不是历史,是操作轨迹

很多人第一次听说 reflog,是在git reset --hard后发现代码没了,慌乱中搜到“Git 恢复已删除提交”。但 reflog 的真正价值,远不止于“后悔药”。它的本质是Git 在你本地仓库中,对每一个“HEAD 移动”动作的不可篡改式快照记录。注意关键词:本地、HEAD 移动、不可篡改。它不记录文件内容变化,不记录分支合并逻辑,只忠实地记下:“X 月 X 日 X 时 X 分,HEAD 从 commit abc123 移到了 def456,原因是执行了reset --hard HEAD~1”。

为什么它比git log可靠?因为log展示的是当前分支可到达的所有提交(即 DAG 图中的可达路径),一旦你reset --hard或rebase,那些被移出路径的提交就从log里消失了;而 reflog 是独立日志,只要没执行git reflog expire(默认90天自动清理),它就永远躺在.git/logs/HEAD里,连gc都不会动它。我曾在一个客户现场遇到极端案例:某开发者误将生产环境配置 commit 推到了 develop 分支,紧急revert后又push --force覆盖了远程历史。结果第二天发现 revert 的逻辑有缺陷,需要重新基于原始错误 commit 做修复。此时git log origin/develop里早已找不到那个 commit 的任何痕迹,但git reflog show develop里清清楚楚写着:“2 days ago develop@{0}: reset: moving to HEAD~1”、“2 days ago develop@{1}: commit: [prod] accidentally pushed config”。我们直接git checkout develop@{1}拿回原始 commit,再基于它做正确修复——整个过程不到两分钟。

提示:reflog 的索引是相对的,develop@{0}是当前 develop 指向的提交,develop@{1}是上一次 develop 指向的提交。它不依赖 commit hash,所以即使你rebase后 hash 全变,@{n}依然有效。这是它作为“操作轨迹”而非“提交历史”的关键特征。

2.2 忽略临时性的本地修改:.gitignore的兄弟,.git/info/exclude

新手常混淆两个概念:.gitignore是项目级规则,会随仓库一起传播,适合忽略node_modules/、__pycache__/这类通用产物;而.git/info/exclude是纯本地、不进仓库、专为“我这次调试要改的临时文件”设计的隔离区。它的存在,就是为了解决那个经典困境:你正在调试一个数据库连接超时问题,需要临时把config/database.php里的 host 改成127.0.0.1,但你绝不想把这个改动提交——它既不是功能变更,也不是配置优化,纯粹是此刻的调试副产品。

.git/info/exclude的威力在于其“绝对本地性”。它位于每个克隆副本的.git/目录下,永远不会被git add、git commit或git push触及。你往里面加一行config/database.php,下次git status就彻底看不见这个文件的修改,git diff也不会显示它,git add .更不会把它带上。更重要的是,它支持和.gitignore完全一致的语法(通配符、取反!、注释#),你可以把它当成个人开发环境的“免打扰模式开关”。我习惯在新项目初始化后,立刻在.git/info/exclude里加上:

# 本地调试专用 .env.local config/debug-*.php *.log .DS_Store

这样,无论团队里谁改了.env模板,我的.env.local永远安静如鸡。它不像git update-index --skip-worktree那样需要记忆复杂命令,也不像git stash那样有状态管理成本,就是一行配置,永久生效。

2.3 检查对文本文件的修改:git diff的七种武器,不是只有--word-diff

当同事说“我只改了一个变量名”,而你git diff看到满屏红色绿色,怀疑人生时,你需要的不是更宽的显示器,而是git diff的精准打击模式。git diff默认展示的是“按行”差异,但文本文件的语义单位其实是“词”甚至“符号”。--word-diff是入门级武器,它把差异粒度缩小到单词级别,比如const MAX_RETRY = 3;改成const MAX_RETRY = 5;,diff 会高亮3和5,而不是整行。但这还不够。

真正的高手会组合使用:

  • git diff --word-diff-regex='[a-zA-Z0-9_]+|[^[:space:]]':自定义“词”的定义。默认 regex 把=当作分隔符,导致MAX_RETRY = 3被切成MAX_RETRY和3两部分。这个自定义 regex 明确告诉 Git:“词”是字母数字下划线组合,或任意非空白字符(即=、{、}都算独立“词”),这样=就不会被切开,语义更准。
  • git diff --ignore-space-change:忽略空格数量变化。前端同学改 HTML,把<div class="a b">拆成多行写,空格多了,diff却疯狂报红。加这个参数,Git 只关心标签和属性名是否变,不关心缩进。
  • git diff --ignore-all-space:更激进,连空格位置都忽略。适合对比被不同编辑器格式化过的 JSON。
  • git diff --no-index file1 file2:对比两个完全不在 Git 管理下的文件。比如你本地有个config-prod.json,想和线上拉下来的config-prod.json.bak对比,不用先git add,直接git diff --no-index。
  • git diff --color-words:在终端里用颜色高亮“词”级差异,比--word-diff更直观,尤其适合快速扫读。

我每天必用的是git diff --word-diff-regex='[a-zA-Z0-9_]+|[^[:space:]]' --ignore-space-change,把它 alias 成gdw(见后文),审 PR 时一眼锁定真实业务逻辑变更,过滤掉 80% 的噪音。

2.4 Git 命令别名:把 12 个按键压缩成 3 个,且永不遗忘

git status -sb(简短格式 + 分支信息)是我每天敲 20 次的命令,但它要按 15 个键(g-i-t-空格-s-t-a-t-u-s-空格--s-b)。而git co -b feature/login创建并切换分支,要按 18 个键。这些高频操作,如果每次都要完整输入,不仅慢,而且极易因手滑输错checkout成checkou导致报错。Git 别名(alias)就是你的键盘宏。

关键在于:别名不是简单的字符串替换,而是可以嵌入 shell 逻辑的脚本载体。比如:

# 最基础的缩写 co = checkout br = branch ci = commit st = status # 带参数的智能别名 # gd <file>:只显示指定文件的 word-diff gd = "!f() { git diff --word-diff-regex='[a-zA-Z0-9_]+|[^[:space:]]' --ignore-space-change \"$@\"; }; f" # gcam:commit all modified, with auto-generated message gcam = "!f() { git add -u && git commit -m \"chore: update $(git status -s | grep '^ M' | cut -d' ' -f3 | xargs | sed 's/ /, /g')\"; }; f" # gbv:列出所有本地分支,并标出当前分支(*号) gbv = "!f() { git for-each-ref --format='%(if:equals=HEAD)%(refname:short)%(then)* %(else) %(end)%(refname:short) %(committerdate:relative)' refs/heads/; }; f"

看gcam这个别名:!f() { ... }; f是 shell 函数定义语法,$@代表所有传入参数。它先git add -u(只添加已跟踪文件的修改),再生成一条 commit message,message 里自动提取所有被修改的文件名(git status -s | grep '^ M'找出修改行,cut -d' ' -f3取第三列文件名,xargs | sed把它们串成逗号分隔列表)。这样,你只需gcam,就完成“暂存所有修改+生成描述性消息”的全流程,且消息内容是真实的、可追溯的。

注意:别名定义在~/.gitconfig的[alias]段下,全局生效。不要用git config --global alias.xxx逐条添加,容易遗漏和混乱。直接编辑文件,结构清晰,备份方便。

2.5 为临时指向的提交创建分支:git switch -c <branch> <commit>,比checkout -b更安全

场景很常见:你在main分支上,看到一个 PR 的 commita1b2c3d很有意思,想拉下来本地跑一下测试,但又不想污染当前工作区。传统做法是git checkout -b temp-test a1b2c3d,但这里有个隐藏风险:checkout命令在旧版 Git 中,如果目标 commit 不在任何分支上,它会进入“分离 HEAD”状态,而-b参数在这种状态下可能行为异常(尤其在 Windows 上)。更现代、更明确的方式是git switch(Git 2.23+ 引入),它是checkout的语义拆分版:switch专管分支切换,restore专管文件恢复。

git switch -c temp-test a1b2c3d的含义是:“创建一个名为temp-test的新分支,让它指向 commita1b2c3d,然后立即切换过去”。它强制要求你明确指定“创建分支”(-c)和“目标提交”(a1b2c3d)两个动作,杜绝了歧义。执行后,temp-test分支诞生,HEAD 稳稳地落在a1b2c3d上,你可以放心npm test、python manage.py runserver,所有操作都在这个干净的分支里。测试完,git switch main回去,git branch -d temp-test删除即可,全程无副作用。

我把它 alias 成gtc(go-to-commit),配合git log --oneline -n 20使用,形成“看日志 -> 复制 hash -> gtc ”的三步闪电流程。比checkout少一个思维负担:你不需要判断当前是“在分支上”还是“在 detached HEAD”,switch总是按你字面意思执行。

2.6 将提交移动到另一分支:git cherry-pick与git rebase --onto的抉择

“把 A 分支上的某个提交,挪到 B 分支上”——这句话听起来简单,实操中陷阱密布。核心在于:你要的到底是“复制”还是“迁移”?

  • git cherry-pick <commit>是复制:它把<commit>的变更内容(patch)应用到当前分支,生成一个全新的、hash 不同的提交。适合场景:A 分支有个 bugfix,B 分支也需要,但 A 和 B 已经分叉很久,直接 merge 会带入大量无关变更。cherry-pick就像复印机,只印你需要的那一页。

  • git rebase --onto <new-base> <old-base> <branch>是迁移:它把<branch>分支上,从<old-base>(不含)到<branch>tip(含)之间的所有提交,整体“拔”起来,重新安放到<new-base>之上。适合场景:你在feature/login分支上开发了 5 个提交,但后来发现它们应该基于develop而不是main,这时rebase --onto develop main feature/login就能把这 5 个提交整体迁移到develop顶端。

关键区别在于cherry-pick操作单个提交,rebase --onto操作提交序列。但rebase --onto的参数顺序极其反直觉(--onto new-base old-base branch),极易输错。我总结了一个口诀:“--onto后跟‘要去哪’,中间是‘从哪起’,最后是‘搬谁’”。比如git rebase --onto develop main feature/login,意思是“把feature/login分支上,从main(不含)之后的所有提交,搬到develop上面去”。

实操心得:永远先用git log --oneline <old-base>..<branch>确认要迁移的提交范围,再执行rebase --onto。执行前git branch backup-before-rebase创建备份分支,以防万一。rebase是重写历史,没有后悔键。

3. 实操过程与核心环节实现

3.1 reflog 的完整恢复流程:从“完了”到“搞定”的 4 步

假设你执行了git reset --hard HEAD~2,删掉了最近两次提交,现在git log里只剩三天前的记录。别慌,reflog 是你的锚点。

步骤 1:定位丢失的提交

# 查看 HEAD 的 reflog,找到 reset 前的状态 git reflog show HEAD # 输出类似: # a1b2c3d HEAD@{0}: reset: moving to HEAD~2 # d4e5f6g HEAD@{1}: commit: fix user login timeout # h7i8j9k HEAD@{2}: commit: add password strength validation # ... # 你需要的是 HEAD@{1} 或 HEAD@{2},即 reset 前的提交

步骤 2:验证提交内容(可选但强烈推荐)

# 检出 HEAD@{1} 到临时目录,确认是你要的 git checkout HEAD@{1} -- . # 此时工作区恢复了 HEAD@{1} 的全部文件 # 用 IDE 或 `git status` 确认无误 # 如果不对,`git checkout main` 回来,再试 HEAD@{2}

步骤 3:创建新分支或重置当前分支

# 方案 A:创建新分支保留原状(最安全) git switch -c recovery-branch HEAD@{1} # 方案 B:直接重置当前分支(如果确定要覆盖) git reset --hard HEAD@{1} # 此时 `git log` 会重新显示那两个提交

步骤 4:推送(如果已推送到远程)

# 如果之前 `git push` 过,现在 `reset --hard` 后需要 force push git push --force-with-lease origin main # `--force-with-lease` 比 `--force` 安全:它会检查远程分支是否被别人更新过,如果被更新,会拒绝 force,避免覆盖他人工作

注意:reflog默认只记录 90 天,长期未操作的仓库可能已过期。所以git reflog expire --expire=never --all可以永久保存(不推荐,磁盘空间有限),更务实的做法是:养成git switch -c backup-$(date +%Y%m%d) HEAD的习惯,每天开工前一键备份当前状态。我把它 alias 成gbk,每天早上gbk,心里踏实。

3.2.git/info/exclude的配置与验证:三行代码建立信任

配置.git/info/exclude不是写完就完事,必须验证它是否真的生效。

步骤 1:创建并编辑文件

# 进入项目根目录 cd /path/to/your/project # 编辑本地排除文件 nano .git/info/exclude # 添加内容(示例) .env.local config/*.debug.php *.tmp

步骤 2:制造一个被排除的文件

# 创建一个 .env.local 文件 echo "DB_HOST=127.0.0.1" > .env.local # 创建一个 debug 配置 echo "<?php return ['debug' => true]; ?>" > config/app.debug.php

步骤 3:验证git status是否忽略

# 执行 status,观察输出 git status # 正确输出应为: # On branch main # Your branch is up to date with 'origin/main'. # nothing to commit, working tree clean # 即使你刚创建了 .env.local 和 app.debug.php,它们也不会出现在 untracked files 列表里 # 对比:如果删掉 .git/info/exclude 里的对应行,再执行 git status,它们就会出现

步骤 4:验证git add是否无效

# 尝试强制添加(测试边界) git add .env.local # 此时不会报错,但 `git status` 仍显示 clean,且 `git commit` 不会包含它 # `git ls-files --others --exclude-standard` 可以列出所有被忽略的未跟踪文件,确认它们在列表中

实操心得:.git/info/exclude的规则优先级高于.gitignore,但低于git update-index --skip-worktree。如果一个文件同时被exclude和skip-worktree标记,skip-worktree生效。所以,对于绝对不能提交的敏感文件(如私钥),用skip-worktree;对于只是“这次调试用”的临时文件,用exclude。两者不冲突,可共存。

3.3git diff高级组合技:一份配置,三种场景

我把最常用的git diff组合封装成三个别名,覆盖 95% 的日常需求:

别名 1:gdw—— 精准词级差异(审 PR 专用)

# ~/.gitconfig [alias] gdw = "!f() { git diff --word-diff-regex='[a-zA-Z0-9_]+|[^[:space:]]' --ignore-space-change --color-words \"$@\"; }; f"
  • 使用场景:Code Review 时,快速扫描 PR 修改。gdw HEAD~1对比上一个 commit,gdw origin/main对比远程 main。
  • 效果:函数名、变量名、数字、符号(==,!=,{,})都独立高亮,空格缩进变化被忽略,一眼看出逻辑变更。

别名 2:gdf—— 文件级差异摘要(快速定位)

gdf = "!f() { git diff --name-only --diff-filter=AMR \"$@\" | head -20; }; f"
  • 使用场景:git pull后,想知道这次更新改了哪些文件,但不想看详细 diff。gdf origin/main列出所有被修改/新增/重命名的文件名,最多 20 行。
  • 效果:输出类似src/utils/date.js,package.json,README.md,帮你快速聚焦到关键文件。

别名 3:gdc—— 提交间内容差异(追溯 Bug)

gdc = "!f() { git diff \"$1\" \"$2\" --word-diff-regex='[a-zA-Z0-9_]+|[^[:space:]]' --ignore-space-change; }; f"
  • 使用场景:线上发现一个 Bug,怀疑是某次发布引入的。git log --oneline v1.2.0..v1.3.0找出两个版本间的 commit,然后gdc v1.2.0 v1.3.0直接对比这两个 tag 的全部内容变更。
  • 效果:跳过中间所有 commit,直接看到“从 v1.2.0 到 v1.3.0,代码库到底变了什么”,极大缩短排查路径。

注意:所有别名中的--word-diff-regex都经过实测,在 JavaScript、PHP、Python、HTML、CSS 中表现稳定。正则[a-zA-Z0-9_]+|[^[:space:]]的含义是:匹配连续的字母数字下划线(即标识符),或者任意一个非空白字符(即运算符、括号、分号等)。这样,user.name === 'admin'会被拆成user、.、name、===、'admin'七个“词”,每个词独立高亮,语义清晰。

3.4 别名系统的构建与维护:从零开始的 10 分钟搭建

别名系统不是一蹴而就的,它应该随着你的工作流进化。以下是我在新机器上搭建的标准化流程:

步骤 1:初始化基础别名(5 分钟)

# 创建 ~/.gitconfig(如果不存在) touch ~/.gitconfig # 写入基础框架 cat >> ~/.gitconfig << 'EOF' [alias] # 基础缩写 co = checkout br = branch ci = commit st = status lg = log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative # lg 是图形化日志,带颜色和相对时间,一目了然 EOF

步骤 2:添加高频生产力别名(3 分钟)

# 追加到 ~/.gitconfig cat >> ~/.gitconfig << 'EOF' # 高频操作 gdw = "!f() { git diff --word-diff-regex='[a-zA-Z0-9_]+|[^[:space:]]' --ignore-space-change --color-words \"$@\"; }; f" gdf = "!f() { git diff --name-only --diff-filter=AMR \"$@\" | head -20; }; f" gtc = "!f() { git switch -c \"temp-$(date +%s)\" \"$1\"; }; f" # gtc 创建临时分支,名字带时间戳,避免重名 gbk = "!f() { git switch -c \"backup-$(date +%Y%m%d-%H%M%S)\" HEAD; }; f" # gbk 创建带完整时间戳的备份分支 EOF

步骤 3:验证与同步(2 分钟)

# 重新加载配置(或新开终端) git config --list | grep alias # 应该看到所有 alias 都在列表中 # 同步到其他机器(如果用 dotfiles 管理) # cp ~/.gitconfig ~/dotfiles/gitconfig # git -C ~/dotfiles add gitconfig && git -C ~/dotfiles commit -m "update git aliases" && git -C ~/dotfiles push

实操心得:别名名尽量用小写字母和短横线,避免下划线(某些 shell 有兼容性问题)。别名值用双引号包裹,内部$@用双引号确保参数传递正确。定期git config --get-regexp alias检查别名是否生效,比git help -a更直接。

3.5git switch创建临时分支的完整链路

git switch -c <branch> <commit>看似简单,但结合 reflog,能形成强大工作流。

场景:在 Code Review 中发现一个可疑 commit

# 1. 查看 PR 的提交历史 git log --oneline origin/main..origin/pr-123 -n 10 # 输出:a1b2c3d fix: handle null pointer in payment service # d4e5f6g feat: add webhook retry logic # 2. 想单独测试 a1b2c3d git switch -c pr123-fix-test a1b2c3d # 3. 此时已在新分支,运行测试 npm test # 或 python -m pytest tests/test_payment.py # 4. 测试通过,想把这个 fix 合并到 main git switch main git cherry-pick a1b2c3d # 生成新 commit,hash 不同,但内容一致 # 5. 清理临时分支 git branch -d pr123-fix-test

进阶:用 reflog + switch 快速回溯

# 你昨天在某个分支上做了实验,今天忘了分支名 git reflog --date=iso | grep "switch:" # 输出:2023-10-05 14:23:01 +0800 HEAD@{0}: switch: from feature/user-profile # 2023-10-04 09:15:22 +0800 HEAD@{1}: switch: from temp-test-1696400122 # 发现 `temp-test-1696400122` 是你昨天建的,直接切回去 git switch temp-test-1696400122

注意:git switch创建的分支,和git branch创建的分支完全一样,没有任何特殊标记。它的优势在于命令语义清晰,且switch命令本身不会触发任何危险操作(如checkout在 detached HEAD 下可能意外修改文件)。

3.6cherry-pick与rebase --onto的实操对比

用一个具体例子说明何时用哪个。

初始状态:

  • main分支:A-B-C-D
  • feature/login分支:A-B-C-D-E-F-G(基于 main 开发)

需求:提交E是一个重要的安全修复,需要尽快上线到main,但F和G是未完成的功能,不能上。

方案 1:cherry-pick(推荐)

git switch main git cherry-pick E # main 变成 A-B-C-D-E'(E' 是 E 的副本,hash 不同) # 安全修复上线,F/G 未引入,完美

方案 2:rebase --onto(错误选择)

git rebase --onto main C feature/login # 这会把 `feature/login` 上 C 之后的提交(E,F,G)全部搬到 main 之后 # 结果:main 变成 A-B-C-D-E'-F'-G',把未完成功能也带上了! # 这违背了需求

正确使用rebase --onto的场景:需求:feature/login分支其实应该基于develop(而不是main)开发,因为develop包含了最新的 API 兼容层。

操作:

# 查看分支关系 git log --oneline main # A-B-C-D git log --oneline develop # A-B-C-D-X-Y-Z # 确认 feature/login 是从 D 开始的 git log --oneline main..feature/login # E-F-G # 执行 onto:把 feature/login 上 main(D)之后的提交,搬到 develop(Z)之后 git rebase --onto develop main feature/login # 结果:feature/login 变成 X-Y-Z-E'-F'-G',完美对接 develop

关键口诀:cherry-pick用于“摘一个果子”,rebase --onto用于“换一棵树”。前者单点,后者批量;前者复制,后者迁移。

4. 常见问题与排查技巧实录

4.1 reflog 相关问题:为什么我的 reflog 里没有想要的记录?

问题现象:执行git reflog,输出为空,或找不到前几天的操作记录。

排查思路:

  1. 确认 reflog 是否启用:git config --get core.logAllRefUpdates。如果输出false,reflog 被禁用。修复:git config --local core.logAllRefUpdates true(当前仓库)或git config --global core.logAllRefUpdates true(全局)。
  2. 检查过期时间:git config --get gc.reflogExpire。默认90.days.ago,如果操作超过 90 天,已被git gc清理。修复:git reflog expire --expire=never --all(慎用,占磁盘)。
  3. 确认操作对象:git reflog默认显示HEAD的日志。如果你在feature分支上操作,但git reflog没反应,试试git reflog show feature,查看该分支的 reflog。
  4. 检查是否在 bare 仓库:bare 仓库(如远程服务器上的)默认不开启 reflog。本地克隆的仓库都是 non-bare,无需担心。

独家技巧:git reflog --all可以显示所有引用(HEAD、所有分支、所有 remote)的日志,有时HEAD@{n}找不到,但在main@{m}里能找到相同提交。

4.2.git/info/exclude失效:文件依然出现在git status中

问题现象:在.git/info/exclude里加了*.log,但app.log依然在git status的 untracked 列表里。

排查步骤:

  1. 确认文件未被git add过:git ls-files --cached app.log。如果输出app.log,说明它已被 Git 跟踪,.git/info/exclude对已跟踪文件无效。解决:git rm --cached app.log(从暂存区移除,保留工作区文件),再git status就会忽略它。
  2. 检查.gitignore冲突:.gitignore里是否有!*.log这样的取反规则?取反规则优先级高于exclude。解决:检查.gitignore,删除或注释掉冲突行。
  3. 确认路径正确:exclude中的路径是相对于.git/info/exclude文件所在目录(即项目根目录)的。如果app.log在logs/子目录下,exclude里要写logs/*.log,而不是*.log。
  4. 检查 Git 版本:极老版本 Git(< 1.7.0)可能不支持.git/info/exclude。升级 Git 即可。

实操心得:用git check-ignore -v app.log命令可以精确追踪一个文件被哪个规则忽略。它会输出类似.git/info/exclude:1:*.log:app.log,明确告诉你规则来源和行号,是排查忽略失效的终极武器。

4.3git diff颜色不显示或乱码

问题现象:git diff输出是黑白的,或中文显示为M-oM-?M-?。

解决方案:

  • 颜色不显示:git config --global color.ui auto。auto表示终端支持颜色时才启用。如果终端确实支持(如 iTerm2、Windows Terminal),但依然不显示,检查TERM环境变量:echo $TERM,应为xterm-256color或类似。修复:export TERM=xterm-256color加到~/.bashrc。
  • 中文乱码:Git 默认用 UTF-8,

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询