简介:这份文档面向刚接触版本控制的开发者与计算机专业学生,系统讲解 Git 的初始化流程与本地仓库基本操作,帮助读者从零建立对分布式版本控制的理解,解决代码变更难以追溯、团队协作易冲突等问题。资源包共1个文件,为 docx 格式的图文教程,压缩包约26KB,内容以文字讲解配合命令示例为主,便于随时查阅与笔记整理。文档从 Git 基础概念切入,对比集中式与分布式版本控制系统的差异,并给出 SVN 与 Git 的常用命令对照;随后详细展开初始化仓库、将现有目录转换为仓库、配置全局用户信息等操作,并延伸至 git add、git commit 等本地仓库核心命令的使用场景与原理说明。目前已有114人学习,适合作为入门阶段的系统学习材料,也可供开发者在日常操作中快速回顾关键命令与配置要点。
1. Git 初始化与本地仓库操作:从 git init 到第一次提交,中间到底发生了什么
很多人第一次接触 Git,是从git init这一行命令开始的。敲下去之后终端只回一句Initialized empty Git repository in ...,看起来什么都没发生,但目录里已经多了一个.git文件夹——这就是整个本地仓库的“黑匣子”。标题里的「Git 初始化与本地仓库操作」,说的正是这条从零到一的路:怎么把普通目录变成 Git 仓库、怎么配置身份、怎么把文件放进暂存区、怎么提交、怎么查看历史、怎么回退。它解决的是“代码还没有远程托管、只想在本地把版本管起来”这个最基础也最高频的需求,适合刚装完 Git 的新手,也适合用了几年却一直靠 IDE 按钮、没搞清底层状态的开发者。下面按真实操作顺序拆开讲,每一步都给出可复制的命令和参数含义。
2. 初始化之前:安装、身份配置与仓库边界的确定
2.1 安装 Git 后必须确认的三件事
装 Git 这件事本身不复杂,Windows 上从官网下载安装包一路下一步即可,macOS 用brew install git,Ubuntu/Debian 用sudo apt install git。但装完之后有三件事必须确认,否则后面提交会出各种玄学问题。
第一件是版本。Git 2.23 之后git checkout被拆分成git switch和git restore,2.28 之后默认分支名可以配置为main。版本太老会导致教程里的命令报错。执行:
git --version # 输出示例:git version 2.43.0第二件是身份。Git 每次提交都会把作者名和邮箱写进 commit 对象,没配置就直接提交会报Please tell me who you are。配置分全局和仓库级两层:
# 全局配置,对本机所有仓库生效,写入 ~/.gitconfig git config --global user.name "Your Name" git config --global user.email "you@example.com" # 只对当前仓库生效,写入 .git/config,优先级高于全局 git config user.name "Work Name" git config user.email "work@company.com" # 查看当前生效的值,加 --show-origin 能看到它来自哪个文件 git config --list --show-origin参数说明:--global影响当前用户所有仓库;不加则只影响当前仓库;--system影响整台机器,一般不用。排查“为什么提交作者不对”时,--show-origin是最快的后悔药,它会直接告诉你这个值是从全局配置还是仓库配置读出来的。
第三件是换行符。Windows 默认 CRLF,Linux/macOS 默认 LF,跨平台协作时会出现“整个文件都变了”的假 diff。常见做法是在 Windows 上设git config --global core.autocrlf true,在 macOS/Linux 上设input。这一步不做,后面合并分支时会被换行符坑到怀疑人生。
2.2 git init 到底创建了什么
在一个普通目录里执行初始化:
mkdir demo-repo && cd demo-repo git init # 输出:Initialized empty Git repository in /path/demo-repo/.git/ ls -a # 输出:. .. .gitgit init只做了一件事:创建.git目录。这个目录里装着仓库的全部元数据,包括对象库objects/、引用refs/、配置config、暂存区索引index、HEAD 指针等。工作区里你看到的文件,Git 并不直接管理,它管理的是.git里的对象和索引。理解这一点,后面所有“文件去哪了”“为什么删了还能恢复”的问题都能自己推出来。
如果想让默认分支叫main而不是master,有两种方式:
# 方式一:初始化时指定 git init -b main # 方式二:改全局默认,之后所有 init 都用 main git config --global init.defaultBranch main-b是 2.28 引入的参数,老版本不支持,会报unknown switch b,这时只能先git init再git branch -m main重命名。
2.3 仓库边界:.gitignore 与“哪些文件不该进仓库”
初始化完第一件事不是git add .,而是先写.gitignore。一旦把编译产物、依赖目录、密钥文件提交进去,后面想删就得改写历史,代价很大。
# 依赖与构建产物 node_modules/ dist/ build/ *.class __pycache__/ # 环境与密钥,绝对不能进仓库 .env *.pem *.key # 编辑器与系统文件 .idea/ .vscode/ .DS_Store Thumbs.db # 例外:这个目录要保留,用 ! 取反 !config/example.env规则说明:/结尾表示只匹配目录;*匹配任意字符但不跨目录;**跨目录匹配;!取反表示重新纳入。一个高频翻车点是:文件已经被git add过之后再写进.gitignore,规则不生效,因为 Git 已经在跟踪它了。解决办法是先把它从索引里移除:
git rm --cached .env # --cached 只删索引不删工作区文件,别漏了这个参数3. 本地仓库的日常操作:add、commit、status、log 的完整闭环
3.1 三个区域与文件状态流转
Git 本地操作围绕三个区域展开:工作区(你编辑文件的地方)、暂存区(.git/index,准备提交的快照)、版本库(.git/objects,已提交的历史)。文件在这三个区域之间有四种状态:未跟踪(untracked)、已修改(modified)、已暂存(staged)、已提交(committed)。
# 新建文件后查看状态 echo "hello git" > readme.txt git status # 输出:Untracked files: readme.txt # 加入暂存区 git add readme.txt git status # 输出:Changes to be committed: new file: readme.txt # 提交 git commit -m "docs: add readme" git status # 输出:nothing to commit, working tree cleangit status是使用频率最高的命令,它告诉你当前处于哪个状态、下一步该做什么。加-s输出精简格式,??表示未跟踪,A表示已暂存新增,M表示已修改。养成“改完先 status 再 add”的习惯,能避免误提交。
3.2 add 与 commit 的参数细节
git add不只是“添加文件”,它的本质是把工作区的当前内容写入暂存区。几个常用形式:
git add file.txt # 添加单个文件 git add src/ # 添加整个目录 git add . # 添加当前目录下所有变更(不含被 ignore 的) git add -A # 添加全仓库所有变更,包括删除 git add -p # 交互式分块暂存,同一文件的不同改动分开提交-p(patch)是熟手最常用的参数。它把每个改动块逐个展示,让你选y(暂存)、n(跳过)、s(拆分更小的块)、q(退出)。一个文件里同时改了 bug 和加了日志,用-p就能拆成两个干净的提交,历史可读性完全不同。
git commit的核心参数:
git commit -m "fix: correct off-by-one in pagination" git commit -am "fix: quick patch" # -a 等价于先 add 所有已跟踪文件的修改再 commit,注意它不包含新文件 git commit --amend # 修改最近一次提交:改信息或补文件,会生成新的 commit hash--amend是把双刃剑。它只应该用在“这次提交还没推送到远程”的场景,一旦推送过再 amend,本地和远程历史就分叉了,强推会覆盖别人的工作。血泪经验:amend 之前先git log确认这条提交是不是只有你自己在用。
3.3 log、diff、show:看清历史与改动
提交之后要能查。git log默认输出冗长,实际排查时常用组合:
git log --oneline --graph --all # 一行一条,带分支图,显示所有分支 git log -3 # 只看最近 3 条 git log --author="Your Name" --since="2024-01-01" # 按作者和时间过滤 git log -p readme.txt # 看某个文件的每次改动内容git diff分三种场景,很容易混:
git diff # 工作区 vs 暂存区,看还没 add 的改动 git diff --staged # 暂存区 vs 最近提交,看即将提交的内容 git diff HEAD # 工作区 vs 最近提交,看所有未提交改动提交前用git diff --staged过一遍,是防止把调试代码、临时打印提交进去的最后一道关。git show <commit>则用来查看某次提交的完整内容,排查“这行代码是谁什么时候改的”时配合git blame file.txt使用。
3.4 撤销与回退:reset、restore、revert 怎么选
本地操作最容易出事的就是撤销。三个命令对应三种场景,选错会丢代码。
# 场景一:改了工作区文件,还没 add,想丢弃改动 git restore readme.txt # 老版本写法:git checkout -- readme.txt # 场景二:已经 add 到暂存区,想撤出暂存但保留工作区改动 git restore --staged readme.txt # 老版本写法:git reset HEAD readme.txt # 场景三:已经 commit,想回退 git reset --soft HEAD~1 # 撤销提交,改动留在暂存区 git reset --mixed HEAD~1 # 撤销提交,改动留在工作区(默认) git reset --hard HEAD~1 # 撤销提交,改动直接丢弃,危险--hard是真正的后悔药失效点,它会同时重置工作区、暂存区和 HEAD,未提交的改动无法找回。如果提交已经推送到远程、别人可能已经拉取,就不要用reset,改用git revert <commit>,它会生成一条反向提交来抵消原提交,历史保持线性,是团队协作里唯一安全的回退方式。
4. 分支与本地协作:让本地仓库真正好用起来
4.1 分支的本质与最小操作集
Git 的分支只是一个指向某次提交的可移动指针,创建和切换成本极低。初始化后默认在master或main上,日常开发应该为每个任务开分支。
git branch # 列出本地分支 git branch feature/login # 创建分支,不切换 git switch feature/login # 切换分支(2.23+) git switch -c feature/login # 创建并切换 git branch -d feature/login # 删除已合并分支 git branch -D feature/login # 强制删除未合并分支git switch和git checkout的区别:switch只用于切分支,checkout还能恢复文件,语义更杂。新项目统一用switch和restore,命令意图更清晰,也不容易误操作。
4.2 合并与冲突处理
分支开发完要合回主线,两种方式:
# 方式一:fast-forward 或 merge commit git switch main git merge feature/login # 方式二:变基,把分支提交挪到主线最新提交之后 git switch feature/login git rebase main git switch main git merge feature/login # 此时是 fast-forwardmerge保留真实的分支结构,rebase得到线性历史。团队规范通常要求:公共分支用 merge,个人分支在合并前用 rebase 整理。冲突发生时,Git 会在文件里插入<<<<<<<、=======、>>>>>>>标记:
git merge feature/login # 输出:CONFLICT (content): Merge conflict in readme.txt # 手动编辑文件,删掉标记,保留想要的内容,然后: git add readme.txt git merge --continue # 想放弃这次合并:git merge --abort冲突处理的核心是“先看懂两边各自改了什么”,不要盲目选一边。用git diff看冲突上下文,或者配置git config --global merge.conflictstyle zdiff3,它会额外显示共同祖先的内容,判断起来准确得多。
4.3 本地仓库的清理与维护
用久了本地会积累无用分支、悬空对象、过期引用。定期清理:
git branch --merged main | grep -v main | xargs git branch -d # 删除所有已合并到 main 的分支 git remote prune origin # 清理远程已删除但本地还留着的跟踪分支 git gc # 垃圾回收,压缩对象库,仓库大了之后能明显提速 git fsck --lost-found # 找回误删提交:悬空对象会列出来,用 git show 确认后 cherry-pick 回来git gc一般不用手动跑,Git 会在对象数达到阈值时自动触发。但仓库克隆了好几年、git log明显变慢时,手动git gc --aggressive一次会有改善,代价是耗时较长。
5. 避坑与排查:本地仓库操作里最容易翻车的五件事
5.1 fatal: not a git repository
现象:执行任何 git 命令都报fatal: not a git repository (or any of the parent directories): .git。
原因:当前目录及其所有父目录都没有.git,说明你不在仓库里,或者仓库的.git被误删、被移动。
解决:pwd确认当前路径,ls -a看有没有.git。如果确实在子目录里,往上找到仓库根再操作;如果.git真丢了,只能重新git init并重新提交,或者从远程重新克隆。这也是为什么.git目录要纳入备份范围。
5.2 .gitignore 写了却不生效
现象:明明把node_modules/写进了.gitignore,git status里还是能看到它。
原因:这些文件在写规则之前已经被git add过,Git 对已跟踪文件不应用 ignore 规则。
解决:先移出索引再提交规则。
git rm -r --cached node_modules git add .gitignore git commit -m "chore: ignore node_modules"注意--cached不能省,否则会把工作区文件一起删掉。
5.3 提交作者信息不对
现象:git log里显示的 author 是别人的名字,或者是一台共用电脑上的旧配置。
原因:仓库级配置覆盖了全局配置,或者全局配置本身就是错的。
解决:用git config --list --show-origin定位来源,改掉对应层级的配置。已经提交的错误作者信息,如果还没推送,可以用git commit --amend --author="Name <email>"修正;如果已经推送多条,需要git rebase -i配合--exec批量改,操作前务必备份分支。
5.4 reset --hard 之后代码没了
现象:执行git reset --hard HEAD~1后,工作区改动全部消失。
原因:--hard同时重置三个区域,未提交内容没有进入对象库,常规手段看不到。
解决:先别做任何写操作,用git reflog查看 HEAD 的移动记录,找到 reset 之前的那条 hash,然后git reset --hard <hash>回去。reflog 默认保留 90 天,是本地操作真正的后悔药。如果改动从未 add 过,reflog 也救不回来,只能靠编辑器历史或系统备份。
5.5 换行符导致整文件 diff
现象:只改了一行,git diff却显示整个文件都变了。
原因:文件在 Windows 上被存成 CRLF,在 Linux 上被存成 LF,Git 认为每一行都不同。
解决:统一配置core.autocrlf,并在仓库根加.gitattributes固化规则:
* text=auto *.sh text eol=lf *.bat text eol=crlf已经产生的假 diff,可以用git add --renormalize .重新按规则归一化后再提交。
6. 进阶技巧:用 reflog 和 stash 把本地操作变成可回滚的
本地仓库最值钱的能力不是提交,而是“任何操作都能回滚”。git reflog记录 HEAD 和分支引用的每一次移动,包括 commit、reset、rebase、merge、checkout,是排查“我刚才干了什么”的第一入口。
git reflog # 输出示例: # a1b2c3d HEAD@{0}: reset: moving to HEAD~1 # e4f5g6h HEAD@{1}: commit: feat: add login # i7j8k9l HEAD@{2}: checkout: moving from main to feature/login # 回到任意历史位置 git reset --hard HEAD@{1} # 或者用 hash git reset --hard e4f5g6h配合git stash处理“改到一半要切分支”的场景:
git stash push -m "wip: login form" # 暂存当前改动 git stash list # 查看暂存列表 git switch main # 去处理别的事 git switch feature/login git stash pop # 恢复并删除最近一条 stash git stash apply stash@{1} # 恢复指定条,保留 stash git stash drop stash@{0} # 删除指定条stash默认不包含未跟踪文件,要连新文件一起暂存得加-u。一个常见坑是stash pop遇到冲突后 stash 不会自动删除,需要手动drop,否则列表越堆越长。
验证本地仓库是否健康,我一般跑这一组:
git status -s # 工作区是否干净 git log --oneline -5 # 最近提交是否正常 git fsck --no-progress # 对象库是否有损坏 git count-objects -vH # 仓库体积分布git fsck报 dangling commit 不一定是坏事,那通常是被 reset 或 amend 丢弃的提交,用 reflog 能找回来;报 missing blob 才是真损坏,需要从远程重新拉取。
我自己带新人时反复强调一个习惯:动手前先git status和git log --oneline -3,确认自己在哪个分支、工作区干不干净、最近提交长什么样,再敲任何带--hard、--force、-D的命令。这三行命令花不到两秒,却能挡掉八成“代码没了”的事故。本地仓库操作没有捷径,把状态看清、把边界守住,比记住一百个参数都管用。希望帮到你。
本文还有配套的精品资源,点击获取