庫(kù)初始化與項(xiàng)目保存全攻略:從git init到遠(yuǎn)程推送實(shí)戰(zhàn))
初始化一個(gè) Git 倉(cāng)庫(kù)再把自己的項(xiàng)目完整地保存進(jìn)去——這套操作我前前后后做過(guò)的次數(shù)早就數(shù)不清了帶過(guò)的新人也不少。說(shuō)實(shí)話很多人卡住的不是git init這一條命令而是后面跟著的一連串連鎖問(wèn)題Git 裝好了不知道全局身份怎么配、第一次提交把node_modules和target目錄一股腦推上去、想上傳到 Gitee 卻報(bào) SSH 認(rèn)證失敗、分支亂了不知道怎么合并。這篇文章就把“初始化 Git 倉(cāng)庫(kù)并保存項(xiàng)目”這條完整鏈路拆開講透從環(huán)境安裝、全局配置、git init 的三種形態(tài)到第一次提交、關(guān)聯(lián)遠(yuǎn)程倉(cāng)庫(kù)最后是高頻故障的排查實(shí)錄。無(wú)論你是剛摸 Git 的新手還是用了挺久但一直沒(méi)系統(tǒng)梳理過(guò)的開發(fā)者應(yīng)該都能從里面拿到一些可以直接照做的內(nèi)容。1. 初始化前的準(zhǔn)備環(huán)境安裝與全局身份配置動(dòng)手git init之前有兩件事必須先做對(duì)否則后面全是坑。第一是 Git 本體裝好且能正常使用第二是全局身份配好。這兩件事看起來(lái)基礎(chǔ)實(shí)際出問(wèn)題的人最多。1.1 Git 安裝三個(gè)平臺(tái)的差異與驗(yàn)證Windows 上我推薦直接裝 Git for Windows下載安裝包一路 Next 就行。需要注意安裝向?qū)Ю锏?PATH 環(huán)境變量選項(xiàng)建議選“Git from the command line and also from 3rd-party software”這樣不僅 Git Bash 能用CMD 和 PowerShell 里也能直接敲git命令。裝完打開 Git Bash輸入git --version能看到版本號(hào)說(shuō)明環(huán)境沒(méi)問(wèn)題。macOS 系統(tǒng)自帶的 Git 版本往往偏舊某些老版本對(duì) SSH 密鑰格式、分支行為的支持有差異保險(xiǎn)起見(jiàn)用 Homebrew 裝一份新的brew install gitLinux 上 Debian/Ubuntu 系用sudo apt install gitCentOS/RHEL 系用sudo yum install git。裝完之后統(tǒng)一驗(yàn)證一下版本。我在實(shí)際工作中見(jiàn)過(guò)不少同事在 Windows 上堅(jiān)持用 CMD 操作 Git結(jié)果遇到中文亂碼、路徑轉(zhuǎn)義、shell 腳本沒(méi)法跑的問(wèn)題。Git Bash 本質(zhì)上是一個(gè)模擬 Linux 環(huán)境的終端很多 Git 相關(guān)的命令和腳本都是按 bash 的習(xí)慣寫的用它能省掉大量莫名其妙的麻煩。這是我要強(qiáng)調(diào)的第一個(gè)實(shí)操點(diǎn)Windows 環(huán)境下盡量使用 Git Bash 而不是 CMD。1.2 全局身份配置為什么必須最先做安裝完 Git第一件事就是設(shè)置身份git config --global user.name 你的名字 git config --global user.email 你的郵箱這兩條配置會(huì)寫進(jìn)用戶目錄下的.gitconfig文件之后的每一次提交都會(huì)記錄這個(gè)身份信息。有人會(huì)問(wèn)我就一個(gè)人開發(fā)不配行不行不行。Git 提交記錄里的 author 字段是空的遠(yuǎn)程倉(cāng)庫(kù)平臺(tái)無(wú)法識(shí)別提交人后續(xù)想要追溯問(wèn)題、關(guān)聯(lián)賬號(hào)都會(huì)很麻煩。更現(xiàn)實(shí)的是Gitee、GitHub 這類平臺(tái)都要求提交郵箱必須和賬號(hào)郵箱匹配否則提交雖然能推上去但不會(huì)顯示你的頭像也不會(huì)計(jì)入貢獻(xiàn)記錄。Git 的配置有三個(gè)層級(jí)system是機(jī)器級(jí)global是當(dāng)前用戶級(jí)local是當(dāng)前倉(cāng)庫(kù)級(jí)。優(yōu)先級(jí)從高到低是 local global system。用git config --list可以查看當(dāng)前所有生效的配置。我在公司里會(huì)讓新人統(tǒng)一用 local 層級(jí)配公司郵箱global 留個(gè)人郵箱避免提交身份混用。個(gè)人項(xiàng)目里直接用 global 就足夠了不用過(guò)度設(shè)計(jì)。1.3 SSH 密鑰生成與認(rèn)證一次搞定要把項(xiàng)目保存到遠(yuǎn)程倉(cāng)庫(kù)主流方式有兩種HTTPS 和 SSH。HTTPS 每次推送都要輸賬號(hào)密碼雖然可以配置憑據(jù)緩存但團(tuán)隊(duì)協(xié)作或者頻繁推送時(shí)體驗(yàn)很差。SSH 配置一次之后長(zhǎng)期免密是更推薦的方式。生成密鑰的命令ssh-keygen -t ed25519 -C 你的郵箱一路回車會(huì)生成一對(duì)密鑰私鑰~/.ssh/id_ed25519公鑰~/.ssh/id_ed25519.pub。選 ed25519 而不是傳統(tǒng) rsa 的原因很簡(jiǎn)單它的密鑰更短、生成更快、安全性在當(dāng)前標(biāo)準(zhǔn)下已經(jīng)被廣泛接受rsa 4096 雖然也能用但屬于“能用但沒(méi)必要”的舊方案只有在需要兼容老服務(wù)器時(shí)才改用-t rsa -b 4096。然后把公鑰內(nèi)容復(fù)制到 Gitee 或 GitHub 的設(shè)置頁(yè)面里的 SSH Keys 區(qū)域。驗(yàn)證是否配置成功ssh -T gitgitee.com # 返回歡迎信息即為成功 ssh -T gitgithub.com我第一次配 SSH 時(shí)踩過(guò)坑在 Windows 下直接打開 CMD 執(zhí)行ssh-keygen生成的密鑰路徑和我預(yù)期的不一致折騰半天才發(fā)現(xiàn)是 CMD 的當(dāng)前用戶目錄和 Git Bash 的 HOME 概念不一樣。所以生成密鑰這步我建議在 Git Bash 里做路徑最省心。還有一個(gè)高頻場(chǎng)景是同一臺(tái)機(jī)器上有多套賬號(hào)比如公司 Gitee 和個(gè)人 GitHub 都要用。只有一個(gè)默認(rèn)私鑰會(huì)導(dǎo)致認(rèn)證串號(hào)解決辦法是在~/.ssh/config里按 host 指定不同的私鑰文件。這一步的具體寫法我在后面的排查章節(jié)會(huì)詳細(xì)說(shuō)。2. git init 的完整拆解三種形態(tài)怎么選git init是在當(dāng)前目錄創(chuàng)建一個(gè)全新的 Git 倉(cāng)庫(kù)。這句話說(shuō)起來(lái)簡(jiǎn)單但它背后其實(shí)有好幾種形態(tài)選錯(cuò)了后面會(huì)很難受。2.1 標(biāo)準(zhǔn)倉(cāng)庫(kù)日常開發(fā)的不二選擇在項(xiàng)目根目錄執(zhí)行g(shù)it init操作成功后目錄下會(huì)多出一個(gè).git文件夾里面包含 config、HEAD、objects、refs 等文件。這一步的本質(zhì)是Git 開始對(duì)這個(gè)目錄下的文件進(jìn)行版本追蹤但此刻還沒(méi)有任何提交。你可以把這個(gè)過(guò)程類比成給一塊新的移動(dòng)硬盤做格式化——目錄還是那個(gè)目錄但底層的管理機(jī)制已經(jīng)完全變了。標(biāo)準(zhǔn)倉(cāng)庫(kù)帶有一個(gè)工作區(qū)你可以正常編輯文件、增刪內(nèi)容Git 會(huì)在后臺(tái)記錄這些變化。日常開發(fā)幾乎都用這種形態(tài)不需要想太多。但我要多提醒一句git init之前先確認(rèn)目錄里沒(méi)有亂七八糟的臨時(shí)文件。因?yàn)槌跏蓟筮@些文件都會(huì)被 Git 納入追蹤范圍除非你寫了.gitignore。我見(jiàn)過(guò)有人直接在下載目錄里執(zhí)行 init結(jié)果把一堆壓縮包、安裝程序全推到了倉(cāng)庫(kù)里。正確做法是在一個(gè)干凈的、專門的項(xiàng)目目錄里執(zhí)行。我的習(xí)慣是每個(gè)項(xiàng)目一個(gè)獨(dú)立文件夾文件夾名字就是項(xiàng)目名路徑清晰后續(xù) clone、push 都不容易出錯(cuò)。2.2 裸倉(cāng)庫(kù)服務(wù)端專用形態(tài)git init --bare創(chuàng)建的是裸倉(cāng)庫(kù)。它沒(méi)有工作區(qū)里面只有 Git 的內(nèi)部數(shù)據(jù)文件相當(dāng)于一個(gè)只存儲(chǔ)版本歷史、不參與實(shí)際開發(fā)的倉(cāng)庫(kù)。裸倉(cāng)庫(kù)最常見(jiàn)的用途有兩個(gè)一是作為團(tuán)隊(duì)共享的中央倉(cāng)庫(kù)大家統(tǒng)一往這個(gè)倉(cāng)庫(kù)推送代碼二是作為自建的備份倉(cāng)庫(kù)。我?guī)团笥汛钸^(guò)小團(tuán)隊(duì)的內(nèi)網(wǎng) Git 服務(wù)用的就是裸倉(cāng)庫(kù)配合一個(gè)簡(jiǎn)單的服務(wù)端目錄。流程大概是在服務(wù)器上執(zhí)行g(shù)it init --bare project.git本地git clone這個(gè)地址之后正常 push。在沒(méi)有外部代碼托管平臺(tái)的環(huán)境里這是最輕量的團(tuán)隊(duì)協(xié)作方案也適合放在 NAS 上做自己的代碼備份。2.3 初始分支名main 還是 master老版本 Git 初始化后默認(rèn)分支叫 master近些年社區(qū)和主流托管平臺(tái)統(tǒng)一改用 main。如果你用的是新版 Gitgit init的默認(rèn)分支取決于你的配置可能是 master 也可能是 main。想要明確指定git init -b main為什么在意這件事因?yàn)?Gitee、GitHub 新建倉(cāng)庫(kù)時(shí)默認(rèn)分支通常叫 main本地如果初始化出來(lái)是 master推送時(shí)要先把本地分支改名或者用git push -u origin master:main這種麻煩的映射方式。與其事后折騰不如初始化時(shí)直接-b main。如果你是老倉(cāng)庫(kù)已經(jīng)是 master 分支改名也很簡(jiǎn)單git branch -m main順便看一眼初始化后的目錄結(jié)構(gòu).git/HEAD文件里寫著當(dāng)前分支指向的引用.git/config里是倉(cāng)庫(kù)級(jí)配置.git/objects是對(duì)象存儲(chǔ)。這些東西知道一下就行不用背但理解它們能幫你排查“這個(gè)倉(cāng)庫(kù)怎么怪怪的”這類問(wèn)題。比如有次我遇到倉(cāng)庫(kù)明明存在但 Git 不認(rèn)一看就是.git目錄被人手動(dòng)改壞了。3. 第一次提交從工作區(qū)到版本庫(kù)初始化完成只是萬(wàn)里長(zhǎng)征第一步“保存項(xiàng)目”真正的核心是提交commit。一套完整的提交流程是工作區(qū)修改 → 暫存區(qū) → 版本庫(kù)。3.1 三個(gè)區(qū)域的關(guān)系與正確操作順序我用一個(gè)快遞發(fā)貨的類比來(lái)解釋工作區(qū)是你的貨倉(cāng)里面堆著所有貨物項(xiàng)目文件。暫存區(qū)是打包臺(tái)你把要發(fā)的貨挑出來(lái)放在這里git add。版本庫(kù)是快遞公司的倉(cāng)儲(chǔ)系統(tǒng)貨物一旦入庫(kù)就有據(jù)可查、可以回溯git commit。git add . # 把當(dāng)前目錄所有變動(dòng)放入暫存區(qū) git status # 查看工作區(qū)和暫存區(qū)狀態(tài) git commit -m feat: 初始化項(xiàng)目結(jié)構(gòu)git add .是新手最常用的命令但我不建議無(wú)腦使用。正確習(xí)慣是git add指定文件或目錄比如git add src/ pom.xml這樣提交粒度更清晰。等你對(duì)項(xiàng)目結(jié)構(gòu)足夠熟悉了再考慮用git add .的便捷性。我經(jīng)常跟新人強(qiáng)調(diào)提交之前一定先跑一遍git status看清楚暫存區(qū)里到底放了什么。這個(gè)習(xí)慣能避免很多尷尬現(xiàn)場(chǎng)——比如不小心把包含密碼的配置文件提交了。3.2 提交信息怎么寫得讓人看得懂git commit -m后面的信息不是隨便敲的。好的提交信息是項(xiàng)目的歷史說(shuō)明書三個(gè)月后你回來(lái)看提交記錄要能一眼看出這次改動(dòng)做了什么。我推薦 Conventional Commits 的簡(jiǎn)化版就是給提交信息加一個(gè)語(yǔ)義化前綴前綴適用場(chǎng)景示例feat:新增功能feat: 增加用戶注冊(cè)接口fix:修復(fù)缺陷fix: 修復(fù)登錄超時(shí)問(wèn)題docs:文檔調(diào)整docs: 更新部署說(shuō)明refactor:重構(gòu)代碼refactor: 抽取公共工具類chore:雜項(xiàng)維護(hù)chore: 升級(jí)依賴版本比如feat: 新增用戶登錄接口就比update有信息量得多。還有一點(diǎn)提交要盡量原子化一次提交只做一個(gè)邏輯上的變更。不要一個(gè)提交里既改 bug 又加功能還重構(gòu)代碼那樣出了問(wèn)題沒(méi)法單獨(dú)回滾團(tuán)隊(duì) review 也難受。這是我在代碼評(píng)審里最常提的一條。3.3 .gitignore哪些文件不該進(jìn)倉(cāng)庫(kù)保存項(xiàng)目之前必須想清楚哪些文件不該被保存。以 Java 項(xiàng)目為例target/目錄是編譯產(chǎn)物本地隨時(shí)可以重新生成沒(méi)必要進(jìn)倉(cāng)庫(kù)IDE 的.idea/目錄保存的是個(gè)人配置進(jìn)了倉(cāng)庫(kù)反而會(huì)污染別人的開發(fā)環(huán)境。Node 項(xiàng)目要忽略node_modules/Python 項(xiàng)目要忽略__pycache__/和虛擬環(huán)境目錄。在項(xiàng)目根目錄創(chuàng)建一個(gè).gitignore文件寫規(guī)則target/ .idea/ *.iml node_modules/ __pycache__/ *.log .env這里有一個(gè)非常經(jīng)典的坑如果某個(gè)文件已經(jīng)被提交到倉(cāng)庫(kù)之后你再往.gitignore里加規(guī)則是不生效的。因?yàn)?Git 已經(jīng)在追蹤這個(gè)文件了ignore 只對(duì)未被追蹤的文件起作用。處理辦法是用git rm --cached把文件從版本庫(kù)里移除但保留本地文件git rm -r --cached target/ git commit -m chore: 移除誤提交的編譯產(chǎn)物這個(gè)操作我每次接手別人的項(xiàng)目幾乎都會(huì)做一遍太常見(jiàn)了。很多開源項(xiàng)目的提交記錄里都能看到這一類 chore 提交本質(zhì)上都是在為當(dāng)初的誤提交善后。4. 保存到遠(yuǎn)程倉(cāng)庫(kù)Gitee 實(shí)戰(zhàn)與分支合并本地提交只能算“保存了一半”。真正意義上的“保存項(xiàng)目”一定要有遠(yuǎn)程倉(cāng)庫(kù)做備份這樣換電腦、組員協(xié)作都不是問(wèn)題。國(guó)內(nèi)場(chǎng)景我最常用 GiteeGitHub 作為備選方案也順手提一下。4.1 創(chuàng)建遠(yuǎn)程倉(cāng)庫(kù)的幾個(gè)細(xì)節(jié)在 Gitee 上新建倉(cāng)庫(kù)時(shí)幾個(gè)選項(xiàng)值得注意。倉(cāng)庫(kù)名和路徑建議和項(xiàng)目名保持一致方便記憶。私有還是公開按需求選初學(xué)者建議先選私有推代碼時(shí)心理負(fù)擔(dān)小改公開隨時(shí)可以。初始化倉(cāng)庫(kù)那一欄一般有三個(gè)可勾選項(xiàng)README、.gitignore、開源許可。我的建議是全部不要勾選。為什么如果遠(yuǎn)程倉(cāng)庫(kù)初始化時(shí)生成了 README 或 .gitignore而本地倉(cāng)庫(kù)已經(jīng)有了提交兩邊歷史沒(méi)有共同祖先推送時(shí) Git 會(huì)判定為沖突報(bào) non-fast-forward 錯(cuò)誤。雖然可以用--allow-unrelated-histories強(qiáng)制合并但純粹是給自己添麻煩。最省心的方式是遠(yuǎn)程倉(cāng)庫(kù)保持完全空白創(chuàng)建好之后直接本地 push遠(yuǎn)程會(huì)自動(dòng)接收本地歷史。4.2 關(guān)聯(lián)遠(yuǎn)程地址并完成首次推送git remote add origin gitgitee.com:用戶名/倉(cāng)庫(kù)名.git git branch -M main # 確認(rèn)本地分支名為 main git push -u origin main這里origin是遠(yuǎn)程倉(cāng)庫(kù)的別名理論上可以隨便叫但業(yè)界默認(rèn)叫 origin別特立獨(dú)行。-u參數(shù)會(huì)把本地分支和遠(yuǎn)程分支的追蹤關(guān)系記錄下來(lái)之后直接git push就可以不用每次帶參數(shù)。推送成功之后遠(yuǎn)程倉(cāng)庫(kù)頁(yè)面就能看到你的代碼這時(shí)候才算真正完成了“保存項(xiàng)目”。之后每次修改的固定節(jié)奏是git add→git commit→git push。這是單人開發(fā)的基本節(jié)奏。如果是已經(jīng)存在的遠(yuǎn)程倉(cāng)庫(kù)比如團(tuán)隊(duì)項(xiàng)目就不需要 remote add 了直接 clonegit clone gitgitee.com:用戶名/倉(cāng)庫(kù)名.gitclone 下來(lái)之后倉(cāng)庫(kù)的 remote 配置是自動(dòng)帶上的直接開始干活即可。注意 clone 出來(lái)的默認(rèn)分支就是遠(yuǎn)程的 HEAD 分支通常是 main。4.3 分支合并從保存到團(tuán)隊(duì)協(xié)作“保存項(xiàng)目”如果只是一個(gè)人在 main 分支上推來(lái)推去Git 的價(jià)值只發(fā)揮了一半。分支的本質(zhì)是并行空間你在 feature 分支上改代碼不影響主干改完再合并回去。git checkout -b feature/login # 創(chuàng)建并切換到新分支 # ... 開發(fā)、提交 ... git checkout main # 切回主分支 git merge feature/login # 合并功能分支合并時(shí)最頭疼的是沖突。沖突的本質(zhì)是兩個(gè)分支在同一個(gè)文件的同一個(gè)位置做了不同修改Git 不知道聽(tīng)誰(shuí)的。解決辦法是打開沖突文件Git 會(huì)在沖突區(qū)域打上標(biāo)記 HEAD 主分支上的內(nèi)容 功能分支上的內(nèi)容 feature/login把不需要的部分刪掉保留正確內(nèi)容然后git addgit commit完成合并。我在團(tuán)隊(duì)里強(qiáng)調(diào)過(guò)很多次合并之前先git pull同步遠(yuǎn)程最新的代碼能顯著減少?zèng)_突。別攢了一周的代碼悶頭一推十有八九要處理一堆沖突。5. 常見(jiàn)問(wèn)題與排查技巧實(shí)錄這一章是我認(rèn)為整篇文章最值得收藏的部分。以下問(wèn)題都是我在實(shí)際工作和帶新人時(shí)反復(fù)遇到的每個(gè)都給出排查思路和解決步驟。5.1 SSH 認(rèn)證失敗Permission denied (publickey)這是新手遇到最多的問(wèn)題報(bào)錯(cuò)長(zhǎng)這樣gitgitee.com: Permission denied (publickey).排查步驟按順序來(lái)確認(rèn)本地有密鑰文件ls ~/.ssh/看有沒(méi)有id_ed25519和id_ed25519.pub。確認(rèn)公鑰已添加到平臺(tái)登錄 Gitee進(jìn)入設(shè)置 → SSH 公鑰粘貼.pub文件內(nèi)容。確認(rèn) ssh-agent 正在運(yùn)行且加載了私鑰eval $(ssh-agent -s) ssh-add ~/.ssh/id_ed25519測(cè)試認(rèn)證ssh -T gitgitee.com。有一次我?guī)屯屡挪檎垓v半天發(fā)現(xiàn)是電腦上有兩個(gè)密鑰文件Git 默認(rèn)用了舊的那個(gè) id_rsa而平臺(tái)里貼的是新生成的 ed25519 公鑰。多賬號(hào)、多密鑰場(chǎng)景下直接在~/.ssh/config里指定最穩(wěn)妥Host gitee.com HostName gitee.com User git IdentityFile ~/.ssh/id_ed25519_gitee還可以在里面繼續(xù)加 GitHub 的配置段落指定另一把私鑰互不干擾。這個(gè)文件配置好之后ssh -T測(cè)試會(huì)自動(dòng)選對(duì)應(yīng)密鑰基本不會(huì)再出現(xiàn)串號(hào)問(wèn)題。5.2 推送被拒絕non-fast-forward報(bào)錯(cuò)信息通常包含failed to push some refs和non-fast-forward。意思是遠(yuǎn)程分支上有本地沒(méi)有的提交Git 拒絕覆蓋別人的歷史。處理方式git pull --rebase origin main # 解決可能出現(xiàn)的沖突 git push origin main用--rebase而不是默認(rèn)的git pullmerge是為了保持提交歷史是一條直線而不是出現(xiàn)一堆 merge commit 分叉。我個(gè)人的習(xí)慣是團(tuán)隊(duì)協(xié)作時(shí)統(tǒng)一用 rebase 拉取只有合并分支時(shí)才用 merge歷史會(huì)清爽很多。當(dāng)然這屬于團(tuán)隊(duì)約定沒(méi)有絕對(duì)優(yōu)劣但一定要達(dá)成統(tǒng)一。5.3 提交錯(cuò)了或誤刪文件reset 與 reflog先說(shuō)誤刪文件的情況。還沒(méi)提交時(shí)誤刪了工作區(qū)文件git checkout -- 文件名這個(gè)命令會(huì)用版本庫(kù)里的內(nèi)容恢復(fù)工作區(qū)文件非常救命。如果是 commit 提交錯(cuò)了想回滾git reset有三種模式模式暫存區(qū)工作區(qū)適用場(chǎng)景--soft保留保留撤銷提交但保留所有改動(dòng)--mixed默認(rèn)清空保留撤銷提交和暫存工作區(qū)不動(dòng)--hard清空清空徹底回滾到指定提交硬重置有風(fēng)險(xiǎn)我一般會(huì)提醒一句執(zhí)行--hard之前先確認(rèn)工作區(qū)沒(méi)有未提交的重要修改否則文件直接蒸發(fā)。還有一種更安全的方法是git revert HEAD它會(huì)生成一個(gè)反向提交來(lái)抵消錯(cuò)誤提交適合已經(jīng)推送到遠(yuǎn)程的場(chǎng)合因?yàn)椴粫?huì)改寫歷史。萬(wàn)一 reset 之后發(fā)現(xiàn)回滾錯(cuò)了還有最后的救命稻草git reflog。reflog 記錄了 HEAD 的所有歷史移動(dòng)包括被撤銷的提交。執(zhí)行g(shù)it reflog找到目標(biāo)提交的 hash然后git reset --hard hash就能找回來(lái)。我靠這招救回過(guò)不小心刪掉的分支直到現(xiàn)在還記得當(dāng)時(shí)的心情。5.4 歷史里誤提交了大文件隨著項(xiàng)目發(fā)展偶爾會(huì)誤提交一個(gè)巨大的文件比如幾百 MB 的視頻或安裝包導(dǎo)致每次 push 都異常痛苦。徹底清除這種文件需要用git filter-repo它會(huì)重寫整個(gè)提交歷史屬于高風(fēng)險(xiǎn)操作執(zhí)行前一定要完整備份倉(cāng)庫(kù)目錄。如果是單人項(xiàng)目且遠(yuǎn)程還沒(méi)有被影響最簡(jiǎn)單的辦法是把大文件從工作區(qū)移走提交一次后續(xù)推送不再受影響。歷史里的大文件雖然還占著倉(cāng)庫(kù)體積但至少不會(huì)讓每天的操作卡死。等哪天真的需要瘦身了再花時(shí)間研究 filter-repo。5.5 高頻報(bào)錯(cuò)速查表最后整理一張速查表遇到問(wèn)題先對(duì)照一下報(bào)錯(cuò)信息可能原因快速處理Permission denied (publickey)SSH 公鑰未配置或密鑰未被加載按 5.1 的順序排查failed to push some refs遠(yuǎn)程有本地沒(méi)有的提交git pull --rebase 后重推fatal: Not a git repository當(dāng)前目錄不在倉(cāng)庫(kù)內(nèi)檢查目錄是否存在 .gitUpdates were rejected because the remote contains work遠(yuǎn)程歷史與本地分叉同上先 pull 再 pushRPC failed; HTTP 413 curl 22推送內(nèi)容過(guò)大檢查是否誤提交大文件這張表是我?guī)氯藭r(shí)的入門清單覆蓋了最常見(jiàn)的七八成問(wèn)題。剩下的問(wèn)題基本都能通過(guò)git log、git status、git remote -v三連定位到方向。6. 實(shí)操心得把“保存項(xiàng)目”變成習(xí)慣最后分享幾點(diǎn)我在實(shí)際工作中沉淀下來(lái)的操作習(xí)慣不深?yuàn)W但都是踩過(guò)坑換來(lái)的。第一提交頻率要高提交粒度要小。寧可一個(gè)下午提交十次不要一天結(jié)束憋一個(gè)大提交。小提交的回滾成本低review 也方便。我給團(tuán)隊(duì)定的習(xí)慣是完成一個(gè)功能點(diǎn)就提交版本可用就打 tag。第二推送之前永遠(yuǎn)先看git status和git log。status 看的是有什么將變log 看的是將要推什么。這兩條命令加起來(lái)十秒鐘的事能避免把調(diào)試代碼、臨時(shí)日志推上遠(yuǎn)程的尷尬。第三每到一個(gè)里程碑比如版本發(fā)布、功能完成記得打一個(gè) tag。git tag v1.0.0之后你的項(xiàng)目就有了一個(gè)不可變的歷史坐標(biāo)隨時(shí)可以通過(guò)這個(gè) tag 找回當(dāng)時(shí)的完整代碼。這個(gè)習(xí)慣在你需要復(fù)盤線上問(wèn)題時(shí)價(jià)值極大。第四Git 的底層原理不用精通但 HEAD、分支、遠(yuǎn)程追蹤這幾個(gè)概念必須想明白。很多人學(xué) Git 只記住命令換個(gè)場(chǎng)景就不會(huì)了就是因?yàn)闆](méi)搞懂這三個(gè)東西的關(guān)系。建議你在本地多建幾個(gè)測(cè)試倉(cāng)庫(kù)隨便瞎玩玩壞了用 reflog 重來(lái)比看一百篇教程都管用。我個(gè)人從最早敲git init時(shí)的懵懂到后來(lái)在大項(xiàng)目里面對(duì)上百個(gè)分支和無(wú)數(shù)次合并最大的體會(huì)是Git 不是一個(gè)需要背命令的工具而是一套需要建立心智模型的工作方式。把“初始化倉(cāng)庫(kù)并保存項(xiàng)目”這件事從一條命令變成一套流程不管是個(gè)人項(xiàng)目還是團(tuán)隊(duì)協(xié)作代碼的安全感和可控性都會(huì)明顯上一個(gè)臺(tái)階。