写这篇 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 系用apt,CentOS/RHEL 系用yum:
sudo 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 "you@example.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 转成 CRLF,commit 时再把 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 git@github.com:user/repo.gitclone其实做了三件事:创建目录、初始化本地仓库、建立远程跟踪分支。克隆大仓库时可以加参数:
git clone -b dev --depth 1 git@github.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 --author=zhangsan --since="2024-01-01" --until="2024-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 就开始 commit,Git 会继续停留在 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 格式应该是git@github.com:user/repo.git。
生成 SSH key 的标准命令:
ssh-keygen -t ed25519 -C "you@example.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 git@github.com第一次连接会提示确认主机指纹,输入yes存进~/.ssh/known_hosts。如果看到类似Hi username! You've 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 git@ssh.github.com如果这个能通过,就把远端地址改成使用 443 端口的格式:
git remote set-url origin ssh://git@ssh.github.com:443/user/repo.git4.3 用 verbose 日志精确定位问题
排查 SSH 最有力的工具是 verbose 模式,它能打印出完整连接过程:
ssh -vT git@github.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再加remote,IDEA 里的对应操作是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 图形化分支切换、提交与冲突解决
分支操作在右下角的状态栏里即可完成。点击当前分支名会弹出分支列表,选中目标分支直接 Checkout;New Branch 创建新分支,输入名称后自动切换。Push 和 Pull 按钮在右上角,也可以用快捷键Ctrl+K打开提交面板。
提交面板左侧列出所有变更文件,右侧是提交信息输入框。选中文件、写好信息、点 Commit,或者直接 Commit and Push 一步到位。这个面板有一个小宝藏:双击变更文件可以看 diff,Unversioned 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或在仓库加.gitattributes |
| push 被远端拒绝 | 远端有本地缺失的提交 | 先git pull --rebase再重新 push |
| clone 反复超时 | 网络或代理配置异常 | 检查git config --global http.proxy,清理无效配置 |
| 中文文件名显示成乱码 | Git 对非 ASCII 路径转义 | 设置git config --global core.quotepath false |
| Permission denied (publickey) | 公钥未绑定或私钥未生效 | 核对公钥、私钥路径、权限和 known_hosts |
| fatal: not a git repository | 当前目录不在仓库内 | 进入项目根目录或先执行git init |
| 合并到一半想放弃 | 冲突复杂或操作中断 | 用git merge --abort/git rebase --abort |
6.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 操作基本可以做到心里有数,踩坑的概率会大幅下降。