
最近带几个新人做C#项目发现一个特别普遍的尴尬代码在本地写得好好的一说到传到GitHub上大家就卡住了。有的是不知道GitHub到底能帮C#项目做什么有的是命令敲到一半报错就慌了还有的干脆问网页上能不能直接传文件夹。我一直在用GitHub管理C#项目从最简单的控制台程序到带数据库的上位机框架都这么管。这篇文章就把我实际跑通的流程完整写一遍从本机初始化一个C#项目到推到GitHub再到日常提交、开分支、配CI自动构建。全程用最实在的方式讲每一步命令都直接给你照着抄就能跑通踩过的坑也一并列出来。1. GitHub和C#到底怎么配合1.1 为什么C#项目值得用GitHub托管很多做C#的朋友尤其是写上位机、写桌面工具的习惯了代码就在自己电脑里改了就能跑觉得没必要搞个远程仓库。这个想法在只有你一个人、项目又小的时候确实没啥问题但项目一旦超过两三个星期问题就来了改坏了一段代码想回退只能靠记忆想在家里的电脑继续写得拿U盘拷最要命的是代码丢了几个月白干。GitHub解决的就是这三件事版本历史、多机同步、团队协作。它核心是一个Git远程仓库Git在你本地管理每次修改的版本快照GitHub负责把这些快照存到云端并提供网页端浏览、Issues、PR、Actions这些协作能力。C#项目和其他语言的项目在GitHub上没有任何本质区别仓库里就是源码加配置文件。但C#有一点特殊它的工具链.NET SDK、NuGet包、解决方案文件规范程度高配合GitHub的Actions做自动化构建特别顺手。后面我会专门讲这个。1.2 一个规范的C#仓库应该长什么样我见过太多乱糟糟的仓库根目录堆了一堆没用的文件。一个合格的C#仓库结构基本是这样的MyProject/ ├── .github/ │ └── workflows/ │ └── build.yml # GitHub Actions 自动构建配置 ├── src/ │ └── MyProject/ # 主项目源码 │ ├── MyProject.csproj │ └── Program.cs ├── tests/ │ └── MyProject.Tests/ # 测试项目 ├── .gitignore # 忽略 bin、obj 等生成目录 ├── README.md # 项目说明仓库门面 └── MyProject.sln # 解决方案文件对刚起步的朋友不用一上来就搞这么全但.gitignore、README.md、src这三样从第一次提交就养成分开来的习惯后面省事很多。尤其 .gitignore很多人不重视结果把bin、obj这些编译产物推到仓库里每次写完代码提交都是一大堆没用的变更review 代码的时候痛苦得要命。2. 从零搭一个C#项目2.1 本机准备三样东西缺一不可写C#代码需要SDK管理GitHub仓库需要Git工具写代码本身需要编辑器。这三样是底线缺哪个都会卡住。.NET SDK去微软官网下载选最新的长期支持版本比如 .NET 8。装完之后命令行输入dotnet --version能输出版本号就说明OK了。GitWindows 上装 Git for Windows装的时候一路默认就行唯一建议改的是把默认分支名从master改成main现在GitHub新仓库默认就是 main保持一致少踩坑。编辑器/IDEVisual Studio 或 VS Code 都行。VS Code 装个 C# Dev Kit 扩展就够用写大型项目建议直接用 Visual Studio Community免费。提示判断环境是否就绪就两条命令dotnet --version和git --version。能看到版本号再继续往下走别上来就卡在环境上。2.2 用 dotnet CLI 创建项目很多人不知道创建C#项目最快的方式不是打开IDE点向导而是命令行。打开终端Windows 下 PowerShell 或 CMD 都行执行dotnet new console -n MyFirstApp cd MyFirstAppdotnet new console会生成一个最小的控制台项目-n指定项目名。生成后目录里有Program.cs入口代码和MyFirstApp.csproj项目文件相当于项目身份证。然后直接跑一下dotnet run看到终端输出Hello, World!你的项目就算活了。这一步验证的是SDK没问题、项目文件没问题后续再怎么折腾都有个兜底。如果你要的不是控制台项目dotnet new还支持很多模板dotnet new webapiASP.NET Core Web APIdotnet new classlib类库dotnet new sln解决方案文件用来管理多个项目我做上位机项目时最常用的是winforms或wpf模板dotnet new winforms。不管选哪种创建和推送的流程完全一样。2.3 第一次提交先让Git接管你的代码项目建好了现在要让它进入版本管理。在项目根目录执行git init这会在当前目录生成一个隐藏的.git文件夹你的项目从此被Git接管。接着创建.gitignore文件内容至少包含bin/ obj/ *.user .vs/这三行分别忽略编译输出目录、临时文件夹、IDE用户设置。这些都是系统自动生成的不该进仓库。然后把当前所有文件加入暂存区并提交git add . git commit -m 初始提交创建控制台项目这一步之后你的项目就在本地Git仓库里留下了第一个版本。随时可以git checkout回滚到这一刻。这版提交不需要推送因为远程仓库还没建下一步就是把它推到GitHub。3. 把项目推到GitHub3.1 先在GitHub上建好远程仓库登录GitHub右上角点号选New repository。仓库名建议和本地项目名一致比如MyFirstApp。这里有个非常关键的选择Description 随便填但 Add a README file 和 .gitignore 都不要勾。因为你本地已经有项目了又加了 .gitignore远程再生成一份会跟你本地的一模一样而且会在第一次推送时制造冲突。GitHub 提示你初始化这些文件是针对完全从网页端开始建仓库的用户的本地已有代码的人照做反而添乱。建好之后页面会显示一个远程地址格式是https://github.com/你的用户名/MyFirstApp.git。记下来下一步用。3.2 关联远程并推送第一次push的命令回到本地终端在项目根目录执行git remote add origin https://github.com/你的用户名/MyFirstApp.git git branch -M main git push -u origin main三个命令逐条说git remote add origin把本地仓库和远程仓库关联起来origin是远程仓库的默认名字约定俗成不用改。git branch -M main把当前分支改名为main。如果你git init之后没改Git默认分支名你的分支可能还叫master跟GitHub默认的main对不上推送时会出问题。git push -u origin main把本地main分支推送到远程-u表示建立关联以后直接git push就行不用再加参数。第一次push会要求你登录GitHub。如果用HTTPS这里要的不是密码而是Personal Access TokenPAT。这个坑绊倒过无数新手后面我专门写一节怎么处理。3.3 认证方式PAT和SSH到底怎么选这是新手遇到最多的拦路虎。以前GitHub允许用密码 push后来彻底关闭了现在必须用token或者SSH密钥。方式一HTTPS PAT推荐新手用GitHub网页右上角头像 → Settings → Developer settings → Personal access tokens → Tokens (classic) → Generate new token。生成时勾选repo权限复制那串ghp_开头的字符串。在push提示输入密码时粘贴进去回车即可。但要注意这个token只在生成页面显示一次关掉就看不到了丢了只能重新生成。而且3个月会过期过期后重新生成一个。建议把token存到密码管理器里省得老重新弄。方式二SSH密钥推荐长期用本地生成密钥ssh-keygen -t ed25519 -C 你的邮箱一路回车然后查看公钥cat ~/.ssh/id_ed25519.pub把输出的一长串复制到 GitHub → Settings → SSH and GPG keys → New SSH key。之后把远程地址换成SSH格式gitgithub.com:用户名/仓库名.git就能免密推送。我个人推荐临时用就HTTPStoken长期维护的项目直接上SSH。SSH一旦配置好就得劲每次推送不用掏token。3.4 网页上能不能传文件夹这个坑必须说很多新手在网页端打开仓库看到Add file只能传单个文件就以为GitHub不能传文件夹跑来问怎么上传文件夹。答案网页端确实没有直接拖拽整个文件夹的功能虽然浏览器上传单个文件可以但你不是非要在网页传代码。Git的设计理念就是本地操作、远程同步。你在本地git add .的时候整个文件夹连同子目录都被纳入了提交git push之后GitHub上自然会显示完整的目录结构。所以上传文件夹这个问题本质上是你还没建立起本地即真身、远程是备份的心智模型。4. 日常开发流程写代码、提交、同步4.1 一次标准提交的节奏项目上了GitHub日常开发就是循环改代码 → 提交 → 推送。建议遵循这个节奏每次只做一件事的修改比如修复了登录超时问题就是一次提交别把十个改动揉在一起。提交信息用简洁的祈使句中文英文都行但要让人一眼看懂修复空值导致程序崩溃、Add user login API都合格可别写update、aaa这种。推送前先git pull把远程最新的变更拉下来合并再push。具体命令git add . git commit -m 修复空值导致程序崩溃 git pull --rebase git pushgit pull --rebase是个好东西它把本地新提交垫在远程最新提交后面保持历史线性不会产生乱七八糟的merge记录。多人协作时强制自己养成这个习惯仓库历史会干净很多。4.2 从别人的C#项目里取经clone和forkGitHub上C#的学习项目、框架源码多得是。想拿一个开源项目到本地看代码执行git clone https://github.com/用户名/仓库名.gitclone会把整个仓库含历史版本下载到当前目录。想自己改着玩建议先去GitHub网页上点Fork把仓库复制到你自己的账号下再clone你自己的那份改完 push 到自己仓库这就不会碰原作者的代码。4.3 分支和Pull Request多人协作的正确姿势一个人开发用main分支直接提交没问题。但一旦跟人协作或者做正经项目就要学会分支git checkout -b feature/login-page这条命令创建并切换到新分支。你在新分支上随便折腾不影响主干。写完了再合并到主干git checkout main git merge feature/login-page git push团队的规范做法是不直接merge而是在GitHub网页上发起Pull RequestPR把 feature 分支push到远程后在GitHub仓库页面点 Compare pull request写清楚你做了什么改动让同事review完再合并。这不仅是代码审查也是团队知识沉淀的过程。5. 进阶操作用GitHub Actions自动构建C#项目5.1 为什么C#项目特别需要CIC#项目有个特点本地能编译不代表别人环境里能编译。依赖包版本不一致、目标框架不对、编译顺序问题都能让人抓狂。GitHub Actions可以在每次push时自动拉取代码、执行编译、跑测试有问题直接在PR页面上标红。这就是持续集成CI。对于C#项目CI的意义尤其大因为dotnet build和dotnet test在命令行里太好用了一条命令就能完成构建和测试配合Actions几乎零成本。我甚至见过很多人只为了自动跑测试就专门给C#项目配CI。5.2 一个能直接用的workflow配置在项目根目录建.github/workflows/build.yml内容如下name: dotnet-build on: push: branches: [ main ] pull_request: branches: [ main ] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkoutv4 - name: Setup .NET uses: actions/setup-dotnetv4 with: dotnet-version: 8.0.x - name: Restore NuGet packages run: dotnet restore - name: Build run: dotnet build --configuration Release --no-restore - name: Test run: dotnet test --no-build --configuration Release这段配置做的事当有人push到main分支或发起PR时GitHub开一台Ubuntu虚拟机装好.NET 8然后按顺序执行还原依赖、编译、跑测试四步。任何一个步骤非零退出工作流就是红叉直接在PR页面上告诉所有人别合并编译没过。on定义了触发条件runs-on指定运行系统steps是依次执行的步骤。这套配置我用了两年多只改过版本号稳定得一批。5.3 CI踩过的坑三个高频问题第一个坑本地能编译Actions里却还原失败。多数是NuGet源的问题公司内网源在Actions里访问不到。解决方案是让CI走公共NuGet源环境变量或NuGet.config里指定。第二个坑测试项目没有测试dotnet test返回的退出码异常。空测试项目直接跑也会报错要么给测试项目加个最简单的断言要么把Test步骤删掉。第三个坑Actions跑一次要等好几分钟觉得浪费时间。其实可以配置缓存把~/.nuget/packages缓存起来第二次跑能省一半时间。steps里加一段缓存配置就行- name: Cache NuGet packages uses: actions/cachev4 with: path: ~/.nuget/packages key: ${{ runner.os }}-nuget-${{ hashFiles(**/*.csproj) }}6. 常见问题与排查实录6.1 新手高频报错速查表我整理了一份实战中遇到最多的错误全部带排查思路报错信息原因解决办法fatal: origin does not appear to be a git repository没执行git remote add origin或地址错了重新执行git remote add origin 正确地址用git remote -v检查Support for password authentication was removed用了密码登录改用PAT生成token后在密码框粘贴failed to push some refs远程仓库有本地没有的提交先git pull --rebase再pushremote: Repository not found仓库不存在或没权限确认地址、确认登录账户是否有仓库访问权限warning: LF will be replaced by CRLFWindows换行符与Unix差异无需处理或执行git config --global core.autocrlf true规避error: src refspec main does not match any本地没有main分支或没做任何提交先git add . git commit -m ...再git branch -M main6.2 几条压箱底的经验经验一提交前先看一眼改了啥。养成git status和git diff的习惯。git status看哪些文件变了git diff看具体改了什么。我有次没看就提交结果把一个调试用的硬编码IP推进了仓库被同事当场抓包。小事但丢面子。经验二.gitignore 出问题了先别删仓库。有次我不小心把bin/提交上去了推了几十MB没用的文件。网上很多教程教你删远程仓库重建这是下策。正确的做法是git rm -r --cached bin git commit -m 移除误提交的编译输出 git push--cached的意思是只从版本控制中移除不动本地文件。仓库瘦身完毕历史里还有记录但日常不受影响。经验三README写好了项目就算成功了一半。仓库创建时可以不勾选README但push之后一定要补一个。README不需要长说清楚三件事这个项目干什么、怎么跑起来、依赖什么环境。我见过很多C#开源项目代码写得挺好但README一片空白直接劝退使用者。经验四分支名统一用main。老的教程都写masterGitHub新仓库默认main。统一用main省心代码、文档、Actions配置里都不用纠结分支名。6.3 关于网络问题的几句实话GitHub服务器在海外国内访问偶尔会慢或者超时这是客观存在的。遇到fatal: unable to access这种网络报错先别急着怀疑代码大概率就是网络抖了一下。我的处理方式简单粗暴过几分钟重试一次或者换个时间段再推。代码本身没问题的话重试基本都能成功。最后分享一个习惯说个我自己的习惯每次开始写一个新C#项目的第一件事不是写代码而是先git init然后完成第一次提交。哪怕这个项目最后只写了三行代码就废弃了这期间的每一次变化都有迹可循。这套GitHub C#的流程我用了好几年最初也是从网页上传不了文件夹这种问题开始摸索的。关键是别被那些命令吓住你需要的其实就那五六条add、commit、pull、push、clone熟练之后全是肌肉记忆。真把这几条跑顺了GitHub对你来说就从一个存代码的网站变成了一个帮你管理代码工程的帮手后面再接触 Actions、PR 这些高级功能都是水到渠成的事。