Git workflow for C# developers: from chaos to order

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Git workflow for C# developers: how to stop fearing merges and start living



Have you ever spent half a day figuring out who and when rewrote your favorite CalculateOrderTotal() method? Or maybe you pushed a "hotfix" straight to master, and then production crashed with a NullReferenceException? Sound familiar? Welcome to the club of C# developers trying to survive Git chaos without a clear workflow.



If you think Git is just git add . and git push, you're missing the point. A proper Git workflow is not a religious debate, but a tool that saves nerves, time, and money. Especially in the world of C#, where we have solutions (.sln), projects (.csproj), and a bunch of NuGet packages that love to conflict.



In this article, I'll show you working branching strategies, real C# code examples, and how to automate the routine. Let's go!



Why do C# projects require a special approach to Git?



When working with C#, you're dealing with more than just text files. You have:



  • Solution (.sln) — one file that references all projects. If two developers add a new project simultaneously, a merge conflict is guaranteed.
  • .csproj files — XML files that update when adding NuGet packages or changing the Target Framework. Merging these files manually is painful.
  • appsettings.json and web.config — configs that often contain connection strings. They shouldn't be committed, but everyone forgets.
  • bin/ and obj/ folders — if you commit them once, your colleagues will curse you forever.


Therefore, your Git workflow for C# must be carefully thought out. And it starts with a proper .gitignore.



Step 1: Setting up .gitignore for C#



The standard .gitignore for C# can be downloaded from GitHub/gitignore, but I'll add a few important lines that are often missed:



# Configuration files with secrets (do not commit!)appsettings.Development.jsonappsettings.Local.jsonsecrets.json

# Files generated by ReSharper or Rider*.DotSettings.user*.DotSettings

# NuGet packages (cache)packages/*.nupkg

# Test resultsTestResults/*.trx

# Visual Studio folders.vs/*.suo*.user*.sln.docstates


Why is this important? Imagine you commit appsettings.Development.json with a local database connection string. A colleague pulls it, and their application crashes because they don't have that database. It seems like a small oversight, but it wastes an hour of work time.



Choosing a branching strategy for your C# team



There are several popular Git workflows. For C# projects, I recommend two main strategies: Git Flow and Trunk-Based Development. Let's break them down with examples.



Option 1: Git Flow (classic for large projects)



Git Flow is like SOLID for Git. It's ideal when you have clear releases (e.g., version 2.1.0, 2.2.0). The branches look like this:



  • main — only stable code.
  • develop — integration branch.
  • feature/XXX-123-add-new-api — features from develop.
  • release/2.1.0 — release preparation.
  • hotfix/2.0.1-critical-bug — urgent fixes from main.


Example for C#: you're working on a new feature "Calculate discount by promo code".



# Create a feature from developgit checkout developgit pullgit checkout -b feature/ABC-42-add-promo-discount

# Write C# code// DiscountService.cspublic class DiscountService{ public decima

Blogs

Book Recommendations