ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Git实战指南:核心原理、常用操作与报错排查全攻略

Git实战指南:核心原理、常用操作与报错排查全攻略 我从第一次用Git到把它变成每天最顺手的工具中间踩过不少莫名其妙的坑。最开始的印象就是命令行窗口里一堆看不懂的报错什么fatal: not a git repository、failed to push some refs甚至有一次合并分支把同事的代码弄丢了靠reflog才救回来。这篇博文就围绕Git基本操作展开从安装、配置、提交、分支、远端协作到常见问题排查把每一步为什么要这么做、实际怎么操作、有哪些坑都按我自己的经验讲一遍。适合刚接触Git的新手也适合用了一两年但遇到问题还全靠搜索引擎的开发者。看完你能把日常80%的Git操作理顺遇到报错也知道先去查什么。1. 内容整体设计与思路拆解1.1 Git到底在解决什么问题很多人学Git之前都经历过没有版本控制的痛苦。写毕业论文的时候文件夹里塞满论文_最终版.doc、论文_打死也不改版.doc、论文_最终版2.doc每次改动都复制一份新文件生怕哪次改坏了回不去。多人协作更崩溃两个人同时改同一个文件最后只能通过聊天工具互传“我改好了你覆盖一下”结果覆盖掉了对方的工作成果。Git解决的就是这个问题它给文件的每一次变化都拍一张快照记录改动的人、时间和内容差异并且允许你在任意历史节点之间自由穿梭、分叉、合并。关键的是Git的快照机制和传统的“增量备份”不一样。Git内部用三类对象来管理数据blob对应文件内容tree对应目录结构commit对应一次提交的快照。每次提交Git把整个项目当时的状态保存下来而不是只保存“改了哪些文件”。所以Git的提交本质上是一个链式结构每个commit都指向父提交形成了一个DAG有向无环图。这也是为什么Git切换分支、回退版本特别快——它只是移动指针不需要对比文件算出补丁。理解这个模型之后你会发现很多Git命令其实是在操作三类东西提交节点、分支指针、暂存区内容。后续所有操作都围绕这三样展开。1.2 为什么选择Git而不是SVN在Git流行之前SVN是主流。两者的核心差异在于架构SVN是集中式版本控制所有历史记录都存在中央服务器上提交代码必须联网Git是分布式版本控制每个人本地都有一份完整的仓库历史提交动作在本地完成不需要连接服务器。集中式和分布式带来的体验差别非常大。用SVN的时候哪怕只是想看一个月前的某一行代码只要断网或者服务器挂了你什么都干不了。Git则完全不受影响飞机上、地铁里都能提交、看历史、建分支——这些操作全部在本地完成联网只是为了push和pull。还有一个被很多人忽略的优势分支成本。SVN创建分支本质上是把目录复制一份成本高、合并麻烦Git创建分支只是创建一个指针只需要几十毫秒。这个差异决定了工作流的不同。Git能把“每修一个bug就建一个分支”变成日常习惯因为开销实在太小了。如果你所在的项目现在还在用SVN迁移到Git之后最大的变化不是命令变了而是协作模式变了每个人都有一个完整仓库不会因为中央服务器故障而阻塞开发代码评审、持续集成也能更好地和分支模型配合。1.3 学习路径怎么设计最合理我发现初学者最容易犯的错误是拿着命令列表死记硬背今天记git checkout -b明天记git reset --hard全背下来但不知道这些命令在解决什么问题遇到报错依然不会处理。我的建议是先建立心智模型再按“本地操作 - 远端协作 - 问题排查”的顺序学习。第一步是理解三个区域工作区你正在编辑的目录、暂存区准备提交的文件清单、版本库已经提交的历史快照。git add是把工作区的改动放进暂存区git commit是把暂存区内容固化成版本库里的一个新提交。日常95%的命令都是在调整这三个区域之间的状态。第二步熟练本地操作初始化仓库、提交、查看历史、建分支、合并分支、回退。这些操作不依赖任何服务器可以随时练习也不会给别人造成困扰。第三步再学远端协作clone、push、pull、解决冲突。有了本地基础你才知道push失败时为什么要先pull才知道origin/main这种远程跟踪分支的含义。第四步是积累排错经验把常见报错整理成自己的速查表遇到问题能快速定位是配置问题、网络问题还是操作顺序问题。这部分的经验会写在后面的章节里。2. 环境准备安装与初始化配置2.1 不同操作系统下的安装方式Windows用户最省事的方式是去Git官网下载安装包一路点Next装完。但有三个选项要特别注意不要无脑默认。第一个是“调整PATH环境变量”默认选项是“Git from the command line and also from 3rd-party software”这个保持默认就好。如果选成了“Use Git from Bash only”你在CMD或PowerShell里敲git会找不到命令还要手动配环境变量纯属给自己找麻烦。第二个是“选择默认编辑器”默认是Vim。很多新手在commit时不小心打开了Vim然后不知道怎么退出卡在窗口里。建议在安装时把这改成VS Code或Notepad也可以在安装后执行git config --global core.editor code --wait来改。如果装完了才发现用的是Vim记住按Esc输入:wq回车就能保存退出。第三个是“换行符转换方式”这个坑很大安装时默认选项是“Checkout Windows-style, commit Unix-style line endings”也就是autocrlftrue。这个选项会让Git在检出文件时把LF改成CRLF提交时再把CRLF转回LF。对纯Windows团队来说问题不大但跨平台协作时容易造成“整个文件都被标记为修改”的假象这个问题我在后面的排查章节专门讲。macOS用户推荐用Homebrew安装brew install git。这条命令会自动安装最新版并配置好PATH。Linux用户可以分不同发行版用apt、yum或者dnf安装比如Ubuntu上是apt install git。安装完成后验证一下git --version能输出版本号比如git version 2.23.0.windows.1就说明安装成功了。如果公司网络下载慢可以用国内镜像站或者包管理器安装装完务必对一下安装包的签名或SHA256不要随便从不明来源下载可执行文件。2.2 第一次配置必须做四件事Git安装完成后不能直接干活必须先做身份配置。Git每次提交都会记录“谁在什么时候改了这些内容”如果没配置用户名和邮箱commit会被拒绝或者生成一串看不出作者的记录。最基本的配置是这两条git config --global user.name 你的名字 git config --global user.email 你的邮箱关于邮箱有个很多人不知道的点如果是往GitHub、Gitee这样的平台推代码提交邮箱最好和平台账号的邮箱一致这样提交记录才能关联到你的账号否则提交会变成“幽灵提交”——代码合进去了但贡献者列表里找不到你个人提交图表也不增长。第三件事是设置默认分支名。旧版Git默认分支叫master新版已经改成main。为了避免每台机器行为不一致建议显式指定git config --global init.defaultBranch main第四件事是配置换行符处理。Windows上设置git config --global core.autocrlf truemacOS/Linux上设置git config --global core.autocrlf input。这条配置的意思是Windows检出时把LF转成CRLF提交时转回LFmacOS/Linux检出时保持LF。这样能最大化避免跨平台的行尾混乱。如果团队项目里已经有.gitattributes文件那么以文件里的规则为准命令行的global配置会被覆盖。2.3 配置文件与查看方式Git的配置分成三个层级system系统级、global用户级、local仓库级。优先级从低到高是system global local也就是说local配置能覆盖global配置这个和覆盖机制是逐层叠加的。实际项目里我见过很多奇怪的问题都是配置冲突导致的。比如某个人全局配置了错误的邮箱项目里又单独配了一个正确的邮箱然后他提交代码时系统到底用哪个答案是用local的。所以排查配置问题时要分别查看三层配置。查看所有生效配置的命令git config --list --show-origin--show-origin会告诉你每一行配置来自哪个文件非常实用。只想看某项配置可以这样git config user.name git config --global user.email我还喜欢配几个别名能显著提升日常效率git config --global alias.st status git config --global alias.co checkout git config --global alias.cm commit git config --global alias.br branch git config --global alias.lg log --oneline --graph --decorate --all配了别名之后git st、git cm -m xxx写起来顺手很多。但团队协作时别强制别人用你的别名别名只是本地个人偏好换一台机器就要重新配。3. 核心实操本地仓库的基本操作流程3.1 从零到第一次提交的完整过程我们先走一遍新手必做的流程把一个普通文件夹变成Git仓库然后提交第一个版本。mkdir my-project cd my-project git initgit init执行成功后会创建一个隐藏的.git目录这里面存放着所有历史数据。很多人第一次看到.git文件夹不知道它是干嘛的解释一下你的项目代码文件是你的工作区.git目录是版本数据库二者互不干扰。如果你删掉了.git代码文件还在但所有历史记录全部丢失这个操作不可逆。如果你想从别人已经建好的仓库开始则用clone而不是initgit clone https://github.com/xxx/xxx.gitclone会自动完成三件事下载历史数据、创建当前分支的工作文件、配置远程跟踪分支origin/main。注意clone之后不需要手动git init再去init反而会破坏原有配置。初始化之后随便创建几个文件然后查看仓库状态git status此时文件处于“未跟踪”状态。Git现在知道这个文件存在但还没有把它纳入版本管理。要让文件进入暂存区git add README.md git add src/ # 添加整个目录 git add . # 添加当前目录所有改动git add .是新手最爱的命令但注意它会把当前目录下所有改动包括变动的、新增的、删除的全部加入暂存区。如果项目里刚好有一个不想提交的临时文件就容易被误加。所以更稳妥的做法是git add明确指定的文件或目录或者先通过.gitignore把不相关的文件排除掉。暂存完成后要提交git commit -m feat: 初始化项目添加项目说明-m是简短提交信息。如果不带-mGit会打开默认编辑器让你填写多行提交信息。提交成功后会输出一行摘要包含分支名、提交哈希、变更的文件数。第一次提交做完之后你对Git的信任感就建立起来了。后续每次改动都是同一个节奏改文件 -git add-git commit。哪怕改动只有一行也要提交这是Git使用中最重要的习惯。3.2 补漏神器git commit --amend怎么用有一次我提交完代码发现少加了一个文件。当时想的是“再提交一次不就行了”结果留下了两条提交记录第二条还写着“fix typo”。这样的记录在别人看历史时是噪音。其实Git提供了一个专门解决这类问题的命令git commit --amend。amend的作用是“修改最近一次提交”。它不会生成新提交而是把当前暂存区里的内容合并进上一个提交替换掉旧的提交对象。使用场景主要有三个第一漏提交了文件。比如你刚提交了index.html但忘记提交style.css现在补上git add style.css git commit --amend -m feat: 添加首页样式注意-m里最好带一份完整、正确的提交信息因为amend之后旧信息会被替换如果你只是想改信息没改代码可以用git commit --amend -m 新的提交信息。第二提交信息写错了字。比如把“feat”写成了“fat”改一下就行。第三把几次小提交合并成一次。比如你写功能时做了三次提交“改了一部分”、“改完功能”、“补一个忘了的变量”在推送到远端之前可以用amend合并git commit --amend --no-edit--no-edit表示沿用上一条提交信息这样修改不会打开编辑器。但这里有两条铁律必须记住。第一条amend只能用于还没有推送到远端的提交。如果你已经git push过了远端已有旧提交此时git commit --amend会生成一个不同的哈希强行push会被拒绝强制push则会把同事基于旧提交的改动全部打乱。第二条amend本质上是“删除旧提交、创建新提交”你以为只改了提交信息其实哈希、时间戳全变了。万一搞坏了用git reflog能找到旧提交并恢复这一点在第5章排查部分展开。3.3 分支操作创建、切换、合并与冲突处理分支是Git最强大的能力也是一堆报错的来源。前面说了Git分支本质上只是指向某个提交对象的指针。创建分支就是复制一个指针几乎零成本。创建并切换分支的常用命令git branch feature/login # 创建分支但不切换 git checkout -b feature/login # 创建并切换旧版 git switch -c feature/login # 创建并切换新版推荐现在Git官方推荐用switch和restore替代容易混淆的checkout。checkout这个命令有太多含义新手常常搞混git checkout feature是切分支git checkout -- file是丢弃文件修改git checkout -b是建分支。语义不清就会用错。新命令把职责拆开了switch只管分支restore只管文件恢复。切换分支后工作区的文件会跟着变化这就是很多人第一次用Git时被吓到的地方切到另一个分支为什么文件不见了其实文件没丢只是每个分支的快照内容不同。Git在你切换分支时会用目标分支的最新快照去更新工作目录。合并分支有两种常见情形。第一种是快进合并fast-forward当目标分支领先于当前分支、且没有分叉时Git直接把当前分支的指针移动到目标分支指向的节点上不产生新的合并提交。第二种是三方合并当两个分支都有各自的提交时Git需要生成一个合并提交把两条线焊在一起。合并命令git switch main git merge feature/login如果合并时两个分支改了同一个文件的同一行Git无法自动判断保留谁的版本就会报冲突。冲突文件会被打上标记里面是开头的当前分支内容和开头的另一分支内容。正确做法是手动编辑文件把不需要的标记和内容删掉保存后git add 冲突文件 git commit -m merge: 合并feature/login分支初学者遇到冲突容易慌其实只要记住一个原则冲突不是错误它只是一个“需要人类做决策”的信号。Git已经把所有能自动合并的都合好了剩下需要你用编辑器打开文件看看保留哪边、调整成什么样子最后add和commit就行。还有一个实用技巧合并大改动之前先看一眼两个分支差了多少git log --oneline main..feature/login这能看到feature分支上但main上没有的提交。如果差了几十个提交合并时冲突概率会很大建议先清理代码、拆分成小合并或者先跑一次git merge --no-commit做预演确认没问题再正式合并。4. 远端协作clone、push、pull与认证4.1 添加远程仓库并理解origin本地仓库和远端仓库通过remote关联。remote是一个别名指向远端仓库的URL。查看当前关联的远端git remote -vclone下来的仓库会自动有一条origin指向你clone的地址。如果是自己先建的本地仓库再想推到远端需要手动添加git remote add origin https://github.com/yourname/repo.git我见过不少人把git remote add origin和git remote set-url origin搞混。前者是首次添加后者是修改已有地址。还有一种情况是本地仓库已经关联了一个远端的仓库A但他想跟仓库B关联又懒得删除旧配置直接再add origin结果报错error: remote origin already exists。正确做法是先删再添git remote remove origin git remote add origin https://github.com/yourname/repo.git这里顺便讲一下origin/main这种奇特的名字。它叫远程跟踪分支是你“上一次和远端通信时远端main分支的指向”。git fetch或者git pull后origin/main会更新。本地的main是你在当前机器上的分支origin/main是远端状态的本地镜像两者可以短暂不一致——这正是分布式版本控制的正常状态。4.2 SSH密钥配置与免密原理连接远端有两种常用协议HTTPS和SSH。HTTPS每次push都要输入用户名密码除非配置了凭据缓存SSH则通过密钥对免密认证。SSH配置步骤ssh-keygen -t ed25519 -C 你的邮箱一路回车会生成一对密钥私钥在~/.ssh/id_ed25519公钥在~/.ssh/id_ed25519.pub。私钥留在本地公钥贴到代码托管平台的SSH Keys设置里然后用这条命令测试ssh -T gitgithub.com如果配置成功会返回类似Hi yourname! Youve successfully authenticated的信息。注意这里用的用户名是git和你的Git账号名无关这是SSH协议层面的固定账号。常见误区有两个。第一个是把私钥内容贴到了平台上私钥一旦泄露等同于密码泄露必须立刻删除重新生成。第二个是平台返回“Key already in use”说明你之前已经把这个公钥添加到另一个账号了——一个公钥只能关联一个账号想多账号使用就得生成多把密钥并通过~/.ssh/config配置。需要多账号协作时可以参考这样的~/.ssh/config配置片段Host github-work HostName github.com User git IdentityFile ~/.ssh/id_ed25519_work Host gitee-personal HostName gitee.com User git IdentityFile ~/.ssh/id_ed25519_personal配置后clone地址要改成对应别名比如git clone gitgithub-work:yourname/repo.git。这种按Host区分密钥的方式比较清晰相比每次切换账号都要改全局配置要省心得多。4.3 push、pull、fetch别盲目pull很多人在远端协作时指令就是“先pull再push冲突就搜谷歌”。其实把这三个动作搞清楚很多问题都能避免。git fetch只做一件事把远端的最新提交下载到本地并更新origin/main等远程跟踪分支。它不会动你的工作区也不会产生合并。git pull等于fetch merge它把远端提交拉下来并自动合并到当前分支。git push是把本地提交推送到远端分支。推荐流程是先把fetch和merge分开看。遇到大改动或者不确定远端有没有新提交时别直接pull而是git fetch origin git log --oneline main..origin/main这能看到远端有而本地没有的提交。看一眼货物内容再决定怎么合并比闭着眼睛pull出冲突之后哭要强。push被拒绝是最常见的远端问题报错一般是! [rejected] main - main (fetch first) error: failed to push some refs原因很简单远端main分支上有你在本地没有的提交Git不敢直接覆盖别人的历史。这时候你有两条路。第一条是git pull --rebase把本地提交“垫”到远端提交之上历史是一条直线第二条是git pull --no-rebase生成一个合并提交把两条线合并。团队协作时建议统一策略。我所在的项目组约定主干分支用rebase保持整洁功能分支随便merge。如果你不确定团队约定先问清楚再动手这种操作会改写提交历史推上去之后很难收拾。push时第一次需要设置上游分支git push -u origin feature/login-u的意思是把本地feature/login和远端origin/feature/login关联起来之后这条分支上直接git push、git pull就不需要再带参数了。4.4 清除账号密码与其他认证问题HTTPS配合缓存在日常使用中最常遇到的麻烦是“密码存错了或者想换账号”。比如你之前用A账号push现在公司换了B账号Git凭据管理器里存的还是A的push时提示认证失败或者一直用旧账号。Windows凭据管理器存储的Git账号可以通过“控制面板 - 用户账户 - 凭据管理器 - Windows凭据”里删除对应的git:https://github.com条目也可以敲命令git credential-manager reject https://github.commacOS用户可以在“钥匙串访问”里搜索github.com删除对应条目。如果连缓存都不想要了可以显式关闭凭据存储git config --global --unset credential.helper还有一个经常被忽略的情况网上教程让用git config --global credential.helper store来免密这个方案虽然简单但会把用户名密码明文存在~/.git-credentials文件里安全性很差。如果你用的是自己的电脑建议用系统自带的凭据管理器如果用共享机器干脆就别缓存每次输入密码也花不了几秒钟。认证失败的另一个常见原因是SSH端口被网络环境拦截导致ssh: connect to host github.com port 22: Connection timed out。这种情况可以考虑改用HTTPS协议clone或者在~/.ssh/config里为对应Host配置443端口Host github.com HostName ssh.github.com Port 443 User git这是我处理过多次的真实案例一台Windows机器在公司网络下SSH连不上配置完443端口后恢复。如果港口的网络策略禁止那就只能用HTTPS了。4.5 git worktree一个处理多个分支的隐藏利器搜“git worktree”的人通常是在一个仓库里遇到“想切分支但手头改动还没提交完”、“想同时在两个分支上干活”的痛点。worktree允许你在同一个仓库下创建多个工作目录每个目录对应不同分支并且互不干扰。比如你正在feature分支开发突然需要修复线上main分支的紧急bug传统做法是stash、切换分支、修复、再切回来手忙脚乱。用worktree可以直接开一个新的目录git worktree add ../hotfix -b fix/urgent main这样项目的../hotfix目录就对应着fix/urgent分支你可以在这个目录里改代码、提交另一个目录的工作完全不受影响。查看、清理工作树git worktree list git worktree remove ../hotfixworktree还有一个好处是并行构建验证。比如两个分支改了不同模块可以各开一个工作目录同时编译。不过要注意同一时间同一个分支只能在一个工作目录里检出因为Git不允许两个工作树操作同一个分支这是设计上的保护防止两份工作区把分支状态搞乱。5. 常见问题与排查技巧实录5.1 常见报错速查表这些年我整理了一份高频报错对照表每次遇到都能快速定位这里分享出来。报错信息触发原因解决思路fatal: not a git repository (or any of the parent directories): .git当前目录不是Git仓库或父目录都不在仓库内确认是否执行过git init用git rev-parse --show-toplevel查看仓库根目录fatal: refusing to merge unrelated histories两个仓库没有共同祖先比如两个独立init的仓库确认确实要合并后使用git merge --allow-unrelated-historieserror: failed to push some refs远端有本地没有的提交先git fetch然后pull或rebase再pushPlease commit your changes or stash them before you merge切换分支/合并时工作区有未提交改动且和目标分支冲突先commit或者git stash暂存操作完再git stash popssh: connect to host github.com port 22: Connection timed outSSH端口被网络拦截改用HTTPS或配置SSH 443端口warning: LF will be replaced by CRLF换行符转换规则触发按团队规范统一配置core.autocrlf或.gitattributes这个表格不是让你背而是遇到问题先确认自己在哪一层是“当前目录没有仓库”初始化问题、还是“合并历史冲突”数据模型问题、还是“网络认证失败”环境问题不同层的排查手段完全不同。5.2 提交发错分支怎么办这个问题每个新手都碰到过在main分支上改了一堆代码其实应该在feature分支上开发。提交已经做了怎么“搬”过去正确步骤是# 1. 记录当前提交到临时分支 git branch temp # 2. 把main分支回退到上一个提交 git reset --soft HEAD~1 # 3. 切到真正要提交的分支 git switch feature/login # 4. 把改动提交过来 git commit -m feat: 正确的提交说明这里的关键是--soft。git reset --soft HEAD~1的含义是把main分支的指针回退一个提交但保留所有改动到暂存区。也就是说代码、暂存状态都还在只是提交节点撤销了。对比一下--mixed默认会回退指针并保留工作区改动但清空暂存区--hard会回退指针并彻底丢弃改动这个命令极其危险执行前一定要确认你不需要那些代码。还有一种是提交已经push到了远端再接一条命令把远端也修正git push --force-with-lease origin main--force-with-lease比--force安全得多它在强推前会检查远端是否还是你上次看到的状态。如果同事已经往这条分支上推了新提交强推会被拒绝防止你覆盖别人的工作。但即便如此改动已经推送的公共分支前一定要和团队沟通这不是命令层面的问题而是协作礼仪问题。5.3 amend、reset误操作后的恢复Git并不是一个“删除了就完蛋”的工具它设计了非常强大的安全网reflog。reflog记录了你在本地仓库中每一次HEAD移动的历史包括commit、reset、checkout、merge。即使你用git reset --hard丢弃了提交reflog里依然能找到那个提交的哈希。先看refloggit reflog输出大概是这样的形式abc1234 HEAD{0}: commit: feat: 登录模块 def5678 HEAD{1}: reset: moving to HEAD~1比如你不小心执行了git reset --hard HEAD~1把最新提交丢掉了。reflog里能看到上一个commit的哈希这时可以恢复git reset --hard abc1234或者用git cherry-pick把那个提交捡回来git cherry-pick abc1234reflog也有过期清理机制一般默认保有90天左右的操作记录。所以遇到误删操作第一反应不要是“完蛋了”而是git reflog先把现场找回来。这个命令我救过自己很多次有一次分支误删就是靠reflog里的commit哈希重建的git branch recover-branch abc1234我强烈建议任何一个用Git的人在理解“分支指针”“提交不可变”的基础上把reflog当成最后一层保险它可以让你在Git里的大部分误操作都有后悔药吃。5.4 添加了.gitignore但文件还在被跟踪很多人往.gitignore里加了一堆路径却发现文件仍然出现在git status里。原因是.gitignore只对未被跟踪的文件生效如果一个文件已经被git add过被跟踪了它就不会再被ignore规则排除。解决办法是把文件从跟踪列表移除但不删除物理文件git rm --cached target/config.yml然后提交这次移除。之后再把这个文件加进.gitignore以后就不会再被跟踪了。这个场景在数据库配置、本地环境变量文件上最常见。比如项目有一个config/database.yml里面存着本地数据库连接信息团队不同成员的内容各不相同就不应该提交到仓库正确做法是提交一份config/database.example.yml作为模板把实际的数据库配置文件ignore掉。5.5 合并冲突处理的经验合并冲突是Git用户绕不过去的坎但处理冲突有一些经验能大幅降低痛苦。第一条经验是合并越频繁冲突越少。很多冲突都是因为分支活了太久、偏离主干太远才爆发的。一个feature分支每完成一个小功能就merge一次主干或者用git merge main把主干的最新代码定期合回feature分支让两边始终保持在较近的距离上。这样每次需要手动解决冲突的范围都很小定位也容易。第二条经验是处理冲突时先看清楚双方意图再动手。冲突标记和之间分别来自两个分支但文件里可能有好几处冲突不要只改一处就提交。建议全局搜一遍冲突标记git grep -n HEAD逐个处理完之后用git diff --check确认没有残留冲突标记和空白错误再git add和commit。第三条经验是不要让Git自动合并二进制文件。图片、压缩包、二进制依赖这类文件一旦双方都改了Git无法合并只能以一方为准。如果你的项目里这类文件经常变动建议考虑用Git LFS统一管理避免反复出现无法合并的问题。我自己就遇到过设计稿图片冲突最后只能找设计同事重新导出白白花了半小时沟通。第四条经验是用stash管理临时修改git stash push -m 暂存当前改动 git stash list git stash popstash会把当前工作区未提交的改动打包暂存让你能在干净状态下切分支、合并处理完再恢复。注意pop时如果和目标文件有冲突同样要手动解决。多分支并行时stash是保命技能比如紧急修复线上bug又不想丢掉正在写的新功能可以先stash、切分支、修完、切回来、pop。5.6 Windows环境特有的坑Windows上是Git问题最多的平台主要围绕换行符和文件系统。换行符问题前面提过表现症状是只是打开文件保存了一下整个文件在diff里显示全变了。因为编辑器把LF换成了CRLF而Git在autocrlffalse的配置下把CRLF当成差异。解决方法是统一提交规范仓库里所有文本文件统一使用LF通过.gitattributes显式声明* textauto *.js text eollf *.json text eollf *.md text eollf这样不管哪个平台、什么编辑器检出文件都用LF提交不产生无意义的换行差异。Windows文件系统的另一个特点是大小写不敏感。如果你在一个仓库里创建了README.md过两天又改成readme.md在Windows上Git可能不会识别为文件重命名导致提交时出现两个文件或者改错对象。Git提供了一个配置项core.ignorecaseWindows上默认是true如果你确实需要严格区分大小写可以设成false但更推荐的做法是保持团队统一命名时一开始就不要用容易混淆的大小写组合。5.7 回退与恢复reset和revert怎么选“代码改坏了要回退”是高频需求但很多人分不清git reset和git revert。git reset是移动分支指针相当于“让历史从某个点重新开始”。它改写历史适合还没推送的提交。git revert是创建一个新提交这个新提交的内容是撤销指定提交的改动但历史里保留原提交的记录。它不改写历史适合已经推送到远端的提交——因为推送过的提交被改写会直接坑队友。例子你想撤销main分支上一次提交。如果用revertgit revert HEADGit会打开编辑器让你写提交信息默认是Revert feat: xxx。这条命令生成的新提交会包含反向修改main的历史上会看到两条记录原来的提交和撤销它的提交。如果提交还没推送用reset更干净git reset --hard HEAD~1但--hard会把工作区文件也恢复成旧状态如果之前有未提交改动会全部丢失。所以如果你只想撤销提交但保留改动用--soft或--mixed。我的习惯是区分使用场景绝不在推送过的公共分支上用reset这是团队协作的底线。日常个人开发分支可以随意reset一旦进了集体仓库的main分支一律用revert或者先跟团队确认。6. 写在最后的个人经验最后分享一个不算技巧但非常重要的习惯提交信息要写清楚。我见过太多update、fix、修改这样的提交信息三个月后回看历史完全不知道当时干了什么。我自己的提交信息风格是类型(范围): 简短描述比如fix(auth): 修复token过期未跳转登录页、feat(api): 添加用户列表分页参数。这种习惯在协作时特别值钱——定位问题、做code review、回退版本第一件事都是看提交信息。还有一个习惯是“小步提交”。别攒了一堆改动才commit一次改一个功能、修一个bug就单独提交。每次提交只包含一个逻辑单元将来出问题定位会非常快。攒几天再提交的代价是一旦中间有一步写错了要么回退一大片要么在reflog里翻半天。Git这门工具不难难的是把“频繁提交、清晰记录、及时同步、谨慎改写”这些习惯真正落实到日常。踩过几次坑之后你会发现它带来的安全感远超学习成本。如果这篇文章能帮你少踩几个坑那很好。
返回列表