
写这篇 Git 操作全流程手册是因为我在各种团队和项目里见过太多因为 Git 使用不当而浪费时间的事故。提交信息乱写、分支合并一团糟、SSH 认证失败后什么都连不上这些坑几乎每个人都会踩一遍。Git 是分布式版本控制系统它真正解决的核心问题是让你在多人协作和多版本并行时还能准确追踪每一次改动是谁、在什么时候、基于什么状态产生的。这篇内容我会从下载安装、全局配置、日常命令到分支合并实战、SSH 认证失败排查最后覆盖在 IntelliJ IDEA 里创建新项目并拉取 Git 仓库的完整流程目标是让新手能照着做让老手遇到问题时能快速定位、少走弯路。1. 环境准备从安装到全局配置一步都不能省1.1 各平台安装实操细节Windows 上安装 Git第一选择是 Git for Windows直接去官网 git-scm.com 下载对应架构的安装包就行。安装过程里最需要警惕的选项有三处。第一处是 PATH 环境变量。安装向导会问你要不要把 Git 加入系统 PATH一定要选择Use Git from the command line and also from 3rd-party software。这个选项的意思是CMD、PowerShell、Git Bash以及后续所有 IDE 的内置终端都能直接识别 git 命令。如果选了只从 Git Bash 使用后面在 IDEA 的 Terminal 面板里敲 git 会提示不是内部或外部命令你还要去改环境变量折腾一圈。第二处是换行符处理方式。Git 默认会尝试把 Unix 风格的换行符 LF 转成 Windows 风格的 CRLF。如果团队里既有 Windows 又有 macOS/Linux 队友这种转换经常导致整个文件被标记为已修改实际上只是每个换行符的位置变了而已。我的建议是选择Checkout as-is, commit as-is不自动转换所有成员靠.gitattributes文件统一约束换行格式这是最省心的方案。第三处是安装 Git Bash 之后默认打开会自带一个终端模拟器。这个工具本身非常好用它提供了比 CMD 更接近 Linux 的操作体验后续很多 SSH 配置、shell 命令都可以在这里执行。建议不要跳过。macOS 上虽然自带 git但苹果自带的版本往往滞后一两个大版本某些新命令如git switch可能在旧版本中不存在。用 Homebrew 安装最新版更稳妥brew install gitLinux 用户根据发行版选择包管理器Ubuntu/Debian 系用aptCentOS/RHEL 系用yumsudo apt install git装完统一验证一下版本git --version输出类似git version 2.40.1就是正常环境。1.2 三个必做的全局配置安装完成后第一件事绝对不是 clone 代码而是配置提交者的身份信息。Git 的每一次提交都会记录 name 和 email而且这些信息会永久留在历史里后期很难干净地修改。执行git config --global user.name your-name git config --global user.email youexample.com第二个必做配置是默认分支名。新版本 Git 通常默认新建仓库的分支是master但从 Git 2.28 开始社区普遍转向main如果你用的版本和团队约定不一致很容易出现仓库 A 用 main、仓库 B 用 master 的混乱。统一设置git config --global init.defaultBranch main第三个是 Windows 用户必须关注的core.autocrlf。这个参数控制 Git 在 checkout 和 commit 时是否自动转换换行符。简单理解checkout 代码时把 LF 转成 CRLFcommit 时再把 CRLF 转回 LF。Windows 上如果默认 true 没问题但一旦团队仓库统一用 LF建议所有成员设置input避免每次 checkout 都产生全文件 diff。macOS/Linux 用户设置input或者保持默认都行。配置完成后可以这样验证git config --list还有一个常见坑团队给某个仓库单独设置了user.name但全局还是空的这时提交报错user.name is missing。遇到这种情况先看git config --list --show-origin查配置到底落在哪一层是系统级、全局级还是仓库级。1.3 确认基础环境是否真的可用配置做完后我习惯先在临时目录里跑一遍完整链路git init、git add、git commit确认核心流程能走通再开始真正的项目操作。这个动作只需几十秒却能提前暴露很多环境问题比如主目录权限异常、编辑器未配置、ssh-agent 没起来等。如果你发现git commit会卡在某个地方通常是系统默认编辑器的问题。可以在第一次提交前配置一个轻量编辑器git config --global core.editor code --wait用 VSCode 作为编辑器提交信息会直接在编辑器里写。如果当前环境没有图形编辑器也可以用 nano 或者 vim。2. Git 基础命令日常高频操作一次讲透2.1 新建仓库与首次提交从零开始一个项目要在空目录里运行git init这个命令会在当前目录生成一个.git隐藏目录里面保存所有版本对象、分支、配置。之后就可以添加文件并提交git add . git commit -m init project如果项目已经存在于远端仓库直接用git clone拿下来更高效git clone gitgithub.com:user/repo.gitclone其实做了三件事创建目录、初始化本地仓库、建立远程跟踪分支。克隆大仓库时可以加参数git clone -b dev --depth 1 gitgithub.com:user/repo.git-b dev表示只拉取 dev 分支--depth 1表示只拿最近一次提交的记录体积小速度快。后续如果需要完整的历史运行git fetch --unshallow补齐。要提醒的是用了--depth 1的仓库无法直接切到其他分支因为远端分支引用是残缺的需要先补齐历史。初始化仓库后第一时间要写好.gitignore尤其是 Java、Python、Node 这类有编译产物和依赖目录的项目。如果忽略规则不写target、node_modules、.idea这类目录会被 Git 当成普通文件跟踪后面每个git status都充满噪音误提交的概率也会翻倍。2.2 修改、暂存与提交的标准流程日常开发离不开三个概念工作区、暂存区、本地仓库。工作区是你打开编辑器看到的文件暂存区是 Git 内部保存下一步要提交的内容的地方本地仓库是已经提交过的历史对象。git add是把工作区的改动放进暂存区git commit把暂存区固化为一条历史提交git push才把本地历史推到远端。提交前先看状态git statusgit add支持精确到文件也支持全量添加git add src/main/java/com/example/UserService.java git add .更精细的操作是git add -p它会逐个 hunk 询问你要不要暂存这个改动。当你在一个文件里同时写了两个不相关的逻辑修改时-p可以把它们拆成两次独立提交让历史更清晰。提交信息方面我的习惯是首行简练说明做了什么中间空一行再写为什么这么做。比如git commit -m fix: 修复用户登陆时 token 过期判断错误 原因旧逻辑只检查了 issuedAt未校验 expiresAt 风险涉及用户会话状态建议回归测试。 这种提交信息在团队代码 review 和问题回溯时价值非常高比一句update强一百倍。2.3 查看历史、撤销与回滚查看提交历史最常用的组合git log --oneline --graph --all -20--graph显示分支分叉和合并的拓扑结构--all包含所有分支-20只显示最近 20 条。配合时间过滤可以定位某个时段的改动git log --authorzhangsan --since2024-01-01 --until2024-03-01看文件差异时git diff比较的是工作区与暂存区git diff --cached比较暂存区与本地仓库git diff HEAD直接比较工作区与最新提交。这些命令在你提交之前检查我到底改了什么时几乎是每天必用。撤销分三种情况千万别混淆。第一种工作区有改动但还没add想放弃修改用git restore filename第二种已经add进暂存区但还没 commit想取消暂存git restore --staged filename第三种已经 commit 但还没 push想回退到某个历史版本git reset --hard commit-hash因为还没 push本地随便改历史都没有后果。但一旦 push 过就不能用 reset要改用git revert commit-hash它会生成一个反向提交来抵消目标提交的改动不破坏公共历史。这条规则是协作项目保命的底线。还有一个容易忽略的命令是git clean。它清理未跟踪的文件和目录git clean -fd会连带删除目录而且不进回收站。执行前一定要先用git clean -n预览要删的东西确认没有误伤。3. 分支合并实战从创建分支到解决冲突的完整链路3.1 分支创建与切换的规范姿势Git 的分支本质上就是指向某次提交的指针创建分支几乎不占额外空间所以不要吝啬分支。项目里我习惯用 main、dev、feature 这套分层结构main 始终保持可上线状态dev 是集成测试分支feature 从 dev 拉出来开发新功能。创建分支的三个常用操作git branch feature/login git switch feature/login git switch -c feature/user-login第一条命令只创建不切换第二条切换第三条创建并切换。git branch查看本地分支列表git branch -r看远程分支git branch -a全部列出。切换分支前第一原则是确保工作区干净。虽然 Git 允许你带着未提交的修改切换分支但两个分支如果对同一文件做了不同的修改切换可能直接报错或者把改动带过去轻则打乱思路重则覆盖工作内容。遇到紧急切换需求先把修改藏起来git stash push -m wip: user service refactor git stash list git stash poppop会在恢复修改的同时把这条 stash 记录删掉。如果你只是想恢复但暂时保留记录用git stash apply。要注意 stash 里面的东西别囤太久否则过了两三周再恢复上下文早就忘了很容易误操作。3.2 merge 与 rebase 的取舍历史优先还是简洁优先合并 dev 分支进 main 的直白方式git switch main git merge dev当 dev 的起点就是 main 的 HEAD且 main 没有新提交时Git 会执行 fast-forward把 main 快进到 dev 的位置历史是一条直线。当两个分支有分叉Git 会生成一个 merge commit把两个分支的历史汇聚到一起。团队如果重视合入痕迹会加参数强制不用快进git merge --no-ff dev这样即使可以快进也会额外生成一个 merge commit在图上能看到一条清晰的功能合入主线。rebase 的思路完全不同git switch feature git rebase main效果是把 feature 分支上的所有提交摘下来以 main 的最新提交为基底重新应用一遍。好处是提交历史完全线性读起来非常舒服。代价是每个提交的 hash 会变化如果这个分支已经推送过且被别人基于它开了新分支rebase 会造成双方历史分叉协同混乱。我的实践经验是分支还没推送随便 rebase分支已经推送、且有人基于它工作只 merge 绝不 rebase。rebase 前记得把工作区清干净否则 Git 会拒绝执行。如果 rebase 过程中出现冲突Git 会停在某个提交位置解决完冲突后执行git add然后git rebase --continue不想继续了用git rebase --abort。3.3 冲突标记与三路合并原理所谓冲突在技术底层是 Git 的三路合并算法发现两边的修改针对同一段内容产生了不同结果。它不像 diff 工具那样只比较两个版本而是同时取三个输入共同祖先版本、当前分支版本、待合并分支版本。只有当两边的改动重叠且不一致时才需要人工裁决。冲突文件里会有这样的标记 HEAD 当前分支的代码 对方分支的代码 feature/login手动解决的操作流程是三步打开冲突文件把不需要的内容删除并去掉所有标记git add标记为已解决最后git commit完成合并。这里最容易犯的错是改完文件后忘了 add 就开始 commitGit 会继续停留在 MERGING 状态提交不出去。图形化工具能大幅降低处理门槛。IDEA 的 Resolve Conflict 界面是三栏对比左边是本地版本右边是远端版本中间是合并结果每段冲突都可以一键选择左侧或右侧内容。VSCode 的冲突提示则用不同颜色区分两方。如果你是纯命令行党可以用git mergetool配置外部工具比如 Beyond Compare 或 Meld。合并到一半想放弃执行git merge --abort就能回到合并前状态不留下任何残留。4. SSH 认证失败排查从密钥生成到连接调试的完整方案4.1 正确生成密钥并绑定平台SSH 认证失败是新手最常遇到的崩溃场景报错通常是Permission denied (publickey)或Host key verification failed。排查的第一步其实是确认远端地址格式。运行git remote -v如果你看到的是https://github.com/user/repo.git那走的是 HTTPS 认证跟 SSH key 没有关系。SSH 格式应该是gitgithub.com:user/repo.git。生成 SSH key 的标准命令ssh-keygen -t ed25519 -C youexample.com-t ed25519指定算法比老的 RSA 更安全也更快。一直回车会把密钥保存到~/.ssh/id_ed25519私钥文件是id_ed25519公钥文件是id_ed25519.pub。如果你设置 passphrase每次连接 SSH 都要输入密码不想频繁输入就要配合 ssh-agent 使用。生成后查看公钥内容cat ~/.ssh/id_ed25519.pub把完整的公钥复制到 Git 平台的 SSH Keys 设置页。GitHub、GitLab、Gitee 的入口都在个人设置账户的 SSH Keys 菜单下。添加完成后测试连通性ssh -T gitgithub.com第一次连接会提示确认主机指纹输入yes存进~/.ssh/known_hosts。如果看到类似Hi username! Youve successfully authenticated的提示说明认证链路完全通了。4.2 高频失败原因与逐步定位如果测试失败按这个顺序排查最有效率第一检查公钥是否真的添加到平台。很多人复制公钥时多复制了空格或换行或者粘贴了私钥都会导致校验不过。登录平台重新核对不要只看终端输出。第二确认本地用的是哪把私钥。Git 在执行 SSH 登录时默认尝试~/.ssh/id_rsa或~/.ssh/id_ed25519。如果你电脑上有多个密钥而目标平台只绑定了其中某一把就需要在~/.ssh/config里显式指定Host github.com HostName github.com User git IdentityFile ~/.ssh/keys/work_ed25519这个文件在 Windows 上同样生效路径需要写成绝对路径。第三检查私钥文件的权限。SSH 对私钥文件权限非常敏感如果其他用户也有读权限会直接拒绝使用。Linux/macOS 上修复为chmod 600 ~/.ssh/id_ed25519Windows 上则要右键文件 - 属性 - 安全确保只有当前用户有读取权限。第四确认网络环境是否连接正常。如果连接直接超时或卡住不动多半是网络策略拦截了 22 端口。GitHub 官方支持 SSH over HTTPS测试命令是ssh -T -p 443 gitssh.github.com如果这个能通过就把远端地址改成使用 443 端口的格式git remote set-url origin ssh://gitssh.github.com:443/user/repo.git4.3 用 verbose 日志精确定位问题排查 SSH 最有力的工具是 verbose 模式它能打印出完整连接过程ssh -vT gitgithub.com输出里重点看三处尝试读取哪些私钥文件、服务器接受的认证方法、被拒绝的具体原因。比如你看到Offering public key: /home/user/.ssh/id_ed25519之后紧跟Authentications that can continue: publickey说明私钥已经送出但服务器端校验失败问题大概率出在公钥绑定。如果输出里根本没有你的私钥路径说明 SSH 压根没找到这把密钥这时要考虑~/.ssh/config里的 IdentityFile 配置是否正确。ssh-agent 的使用也很重要。如果你设了 passphrase又不希望在每次会话中重复输入可以开启代理eval $(ssh-agent -s) ssh-add ~/.ssh/id_ed25519之后在同一个终端会话内 SSH 连接会免密。Windows 用户除了在 Git Bash 里执行上面的命令也可以直接开启系统服务 OpenSSH Authentication Agent然后在 PowerShell 里执行ssh-add。我真切建议把这套流程配置好因为它省下来的时间非常可观尤其是你每天要 push 几十次的场景。5. IDEA 集成创建项目并拉取 Git 仓库的图形化路径5.1 从 Version Control 直接克隆仓库很多开发者命令行用得很溜换个图形 IDE 反而放不开手脚。IntelliJ IDEA 的 Git 集成其实相当完整核心入口有三个启动欢迎页的Get from VCS按钮、菜单栏VCS - Get from Version Control、以及新建项目向导里的Project from Version Control。点击后输入仓库地址、选择本地保存目录IDEA 会自动 clone。如果是私有仓库IDEA 会弹出认证面板。HTTPS 模式下通常用 Token 或账号密码SSH 模式下则依赖前文配置的密钥。公司在用 GitLab 的朋友需要注意如果远端是 HTTPS 地址IDEA 默认走 Git Credential Manager可能会出现反复弹窗或者无法保存认证的情况解决办法是改用 SSH 地址前提是把密钥配置好。Clone 弹窗底部还有分支选择、轻量克隆等选项按需勾选即可。5.2 本地已有项目与 Git 初始化关联另一种常见情况是项目已经在你本地写好想把它纳入 Git 管理。命令行写法是git init再加remoteIDEA 里的对应操作是VCS - Enable Version Control Integration选择 Git 后当前项目根目录就会被初始化。初始化完成后右下角会出现当前分支信息左侧的 Commit 面板也能看到所有文件变更。接下来要在 IDEA 里添加远端仓库地址。打开 Git 工具栏选择Manage Remotes填入远端 URL。如果远端是空仓库可以直接在这个界面添加再执行第一次 push 即可。这里一定要强调.gitignore的重要性。IDEA 的.idea目录、Java 的target目录、前端项目的node_modules都是不该提交的内容。如果不加规则直接提交版本库会被垃圾文件污染后面清理非常痛苦。IDEA 在新建项目时支持按模板生成.gitignore也可以装官方推荐的 .gitignore 插件在项目树里右键文件直接生成忽略规则。5.3 图形化分支切换、提交与冲突解决分支操作在右下角的状态栏里即可完成。点击当前分支名会弹出分支列表选中目标分支直接 CheckoutNew Branch 创建新分支输入名称后自动切换。Push 和 Pull 按钮在右上角也可以用快捷键CtrlK打开提交面板。提交面板左侧列出所有变更文件右侧是提交信息输入框。选中文件、写好信息、点 Commit或者直接 Commit and Push 一步到位。这个面板有一个小宝藏双击变更文件可以看 diffUnversioned Files 分组下能直接右键把文件加入.gitignore。冲突解决是 IDEA 相对命令行最舒服的地方。合并时出现冲突文件会被红色高亮双击进入 Resolve 窗口三栏界面分别显示本地版本、合并结果、远端版本。你可以逐段用箭头应用左侧或右侧的内容也可以直接在中间区域手工修订最后点 Apply。IDEA 会自动执行 add 操作将冲突标记为已解决剩下只需要 commit 即可。对于几百行的代码合并这个工具的效率比盯着尖括号高得多。6. 高频问题速查表与避坑经验6.1 常见问题定位速查现象根因解决方案提交报 user.name/email missing全局或仓库级身份未配置执行git config --global user.name/email文件 diff 显示整行变化换行符 CRLF/LF 不一致统一core.autocrlf或在仓库加.gitattributespush 被远端拒绝远端有本地缺失的提交先git pull --rebase再重新 pushclone 反复超时网络或代理配置异常检查git config --global http.proxy清理无效配置中文文件名显示成乱码Git 对非 ASCII 路径转义设置git config --global core.quotepath falsePermission denied (publickey)公钥未绑定或私钥未生效核对公钥、私钥路径、权限和 known_hostsfatal: not a git repository当前目录不在仓库内进入项目根目录或先执行git init合并到一半想放弃冲突复杂或操作中断用git merge --abort/git rebase --abort6.2 几个我强烈建议养成的好习惯第一提交信息结构化。用feat:、fix:、refactor:这类前缀辅助信息写为什么改不要只写改了代码。第二push 前先看git status和git diff HEAD确认没有把本地密钥、配置文件、临时文件误提交进去。第三不熟悉新命令时先git command -h看帮助不要凭直觉猜参数Git 的某些参数破坏性极大。第四配置常用别名提高效率git config --global alias.st status git config --global alias.ci commit git config --global alias.br branch git config --global alias.lg log --oneline --graph --all配置后git st和git lg都是日常高频动作。最后再分享一个小技巧是我个人实际在项目里反复用到的保命方法做合并、rebase、reset 这类有风险的操作前先花十秒钟在当前位置记一个安全点比如创建一个临时分支git branch backup-before-rebase或者打一个 lightweight taggit tag backup-before-rebase。一旦操作结果不如预期git reset --hard backup-before-rebase就能瞬间回到操作前的状态。Git 本身不区分危险操作和安全操作它只是忠实地执行你的每个指令所以提前留好坐标永远是第一位的。这套流程你认真走几遍日常的 Git 操作基本可以做到心里有数踩坑的概率会大幅下降。