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