Skip to main content
Published / updated

Repository Basics

Before you start

You need: basic file and terminal usage. Start this track with your first project, not after — every article you write is worth not losing.

Time: about 50 minutes, at the keyboard.

Learning objective

Create a repository, stage changes deliberately, and write commits a colleague can read six months later.

Topics

  • What version control gives you
  • Installing and configuring
  • The three areas
  • init, status, add, commit
  • Reading a diff
  • Commit messages
  • .gitignore
  • Undoing before a commit

What version control gives you

WithoutWith
StudentService_final_v2_USE_THIS.csOne file, full history
"Who changed this and why?"git blame
Overwriting a colleague's workMerging
No way back from a bad changeEvery commit is a restore point

The property that matters most is the last one: every commit is a point you can return to. That changes how you work — experimenting freely is safe when reverting costs nothing.

Installing and configuring

git --version
git config --global user.name "Ravi Kumar"
git config --global user.email "ravi.kumar@nexcoding.in"
git config --global init.defaultBranch main
git config --global core.autocrlf true # Windows
git config --global core.autocrlf input # macOS and Linux
git config --global pull.rebase false

git config --list

Use the email your commits should be attributed to. Commits are matched to a profile by email, so a mismatch leaves work unattributed — and on a company repository it creates confusion in audits. Changing it later does not fix existing commits.

core.autocrlf prevents a whole-file diff the first time a Windows developer commits to a repository created on Linux. Without it, every line appears changed because the line endings differ.

pull.rebase false sets an explicit strategy. Without one, newer Git warns on every pull.

The three areas

Working directory → Staging area → Repository
(your files) (git add) (git commit)
AreaContains
Working directoryYour files as they are now
Staging areaChanges marked for the next commit
RepositoryCommitted history

The staging area is what makes small commits possible. You can commit two of five changed files and leave the rest pending — so one afternoon's work becomes three focused commits rather than one unreviewable dump.

That is not a detail. A commit doing one thing can be reviewed, reverted and bisected; a commit doing eight cannot.

init, status, add, commit

git init
git clone https://github.com/TeamSahasra/school-portal.git
git status
git status -s # short form
M src/Services/StudentService.cs modified, not staged
M src/Data/StudentRepository.cs modified, staged
?? src/Services/FeeService.cs untracked
A database/01-schema.sql added
D src/Old/Legacy.cs deleted

The left column is the staging area; the right is the working directory. MM means staged changes and further unstaged edits to the same file.

git status before every commit. It is the cheapest habit in this article and it prevents most accidental commits.

git add src/Services/StudentService.cs
git add src/Services/
git add . # everything, including untracked
git add -u # tracked files only
git add -p # interactively, hunk by hunk

git add -p is the tool that turns one messy change into two clean commits. It walks each hunk and asks whether to stage it: y, n, s to split a hunk further, q to stop.

git commit -m "Fix fee calculation to exclude cancelled payments"
git commit # opens an editor for a full message
git commit -am "..." # stage tracked files and commit

git commit -am skips the staging step, which also skips the review. Use it only for a change you have already read.

Reading a diff

git diff # working directory vs staging
git diff --staged # staging vs last commit
git diff HEAD # working directory vs last commit
git diff main feature/x # between branches
git diff --stat # summary of files and line counts
diff --git a/src/Data/FeeRepository.cs b/src/Data/FeeRepository.cs
index 3a4f2b1..8c9d0e2 100644
--- a/src/Data/FeeRepository.cs
+++ b/src/Data/FeeRepository.cs
@@ -42,7 +42,8 @@ public class FeeRepository
public decimal GetTotalPaid(int feeAccountId)
{
- const string sql = "SELECT SUM(Amount) FROM FeePayment WHERE FeeAccountId = @Id";
+ const string sql = @"SELECT ISNULL(SUM(Amount), 0) FROM FeePayment
+ WHERE FeeAccountId = @Id AND IsCancelled = 0";

- is removed, + is added. @@ -42,7 +42,8 @@ means the hunk starts at line 42, was 7 lines, is now 8.

git diff --staged before every commit. You are checking four specific things:

CheckWhy
Debug leftoversConsole.WriteLine, a hardcoded id used while testing
Files you did not mean to touchappsettings.json, .csproj, a bin/ folder
SecretsConnection strings, API keys, passwords
Whitespace-only churnA reformat burying the real change

A committed secret is a leaked secret. Deleting it in a later commit does not remove it — it stays in history, readable by anyone who clones the repository. The only real fix is rotating the credential.

Five seconds reading the diff prevents it.

Commit messages

Fix fee calculation to exclude cancelled payments

FeeAccount.PaidAmount summed every FeePayment row, including
reversed ones, so students with a cancelled payment showed as
Paid while still owing money.

Filter to IsCancelled = 0 in the repository query.
Reported by the accounts team for Ravi Kumar (NCA-2024-0012).

Fixes #142

Subject line: under 50 characters, imperative mood, no full stop.

Add student search by roll number
Fix absent students being counted as failed
Remove unused FeeCalculator class
Update Dapper to 2.1.35

Imperative because it completes the sentence "this commit will…" — which is also how Git's own generated messages read.

Body: the why.

The diff already shows what changed. What it cannot show is why you made that choice, what was broken, and what you considered. Updated StudentController.cs is worthless — the filename is already in the commit.

You are writing for the person who runs git blame on this line in eighteen months. That person is usually you.

If the subject needs "and", it is probably two commits:

Bad: Fixed fee calculation and added student search and updated README
Good: Fix fee calculation to exclude cancelled payments
Add student search by roll number
Update README with new setup steps

Conventional Commits is a common convention worth knowing:

feat(students): add search by roll number
fix(fees): exclude cancelled payments from the total
docs(readme): document local setup
refactor(data): extract StudentMapper
test(fees): cover the cancelled-payment case
chore(deps): update Dapper to 2.1.35

Machine-readable, so tooling can generate changelogs and infer version bumps. Adopt it if the team does.

.gitignore

# .NET
bin/
obj/
*.user
*.suo
.vs/

# Configuration with secrets
appsettings.Development.json
appsettings.Production.json
.env
*.pfx

# Node
node_modules/
dist/
.env.local

# Python
__pycache__/
*.pyc
.venv/
venv/

# Databases and logs
*.mdf
*.ldf
*.log

# OS
.DS_Store
Thumbs.db

Create it before the first commit. Adding it later does not untrack files already committed.

git rm --cached appsettings.Development.json
git rm -r --cached bin/

--cached removes from tracking and keeps the local file. Without it, the file is deleted.

git check-ignore -v src/bin/Debug/app.dll

That reports which rule is ignoring a file — the answer to "why will Git not add this?".

If bin/ keeps appearing in git status, the .gitignore is wrong or the files are already tracked. Unticking them by hand every day is not the fix.

Start from a template: gitignore.io generates one for your stack.

Git in Visual Studio and VS Code

Most teams use a mixture of the command line and an editor's Git tools. This track teaches the command line because it is identical everywhere and it is what error messages, documentation and colleagues assume. But you will work in an editor daily, so know what each button actually runs.

Visual StudioView → Git Changes:

In the windowRuns
A file under Changes, with +git add <file>
Stage Allgit add .
Message box plus Commit Stagedgit commit -m "..."
Commit Allgit commit -am "..." — skips your review
Double-clicking a filegit diff for that file
Push / Pull / FetchThe same commands
Git → Manage Branchesgit branch, git switch
Right-click a commit → Revertgit revert <hash>

VS Code — the Source Control panel (Ctrl+Shift+G):

In the panelRuns
+ beside a filegit add <file>
+ beside "Changes"git add .
Clicking a fileOpens a side-by-side git diff
Selecting lines → Stage Selected RangesThe equivalent of git add -p
The with a messagegit commit
The branch name, bottom leftgit switch
The sync arrowsgit pull then git push

Two of these are worth using over the command line. VS Code's side-by-side diff is easier to read carefully than terminal output, and Stage Selected Ranges does hunk-by-hunk staging with a mouse — the same job as git add -p, with less friction.

GitHub Desktop is a standalone client covering commit, branch, push, pull and pull requests, with a clear diff view. It is a reasonable way to start and it does not cover the recovery commands in article 07 — so learn the command line alongside it, not instead of it.

Two cautions apply to every GUI:

"Commit All" stages and commits in one click, skipping the review that catches a debug line or a connection string. Stage deliberately, then read the diff, then commit.

A GUI hides which command it ran. When something goes wrong — a rejected push, a detached HEAD, a conflict — the error message is in command-line vocabulary, and the fix usually is too. That is why this track teaches the commands: not because the buttons are wrong, but because you cannot diagnose a button.

Undoing before a commit

git restore src/Services/StudentService.cs # discard working changes
git restore . # discard everything unstaged
git restore --staged src/Data/Repo.cs # unstage, keep the change
git restore --source=HEAD~2 src/Config.cs # restore from an older commit

Older syntax you will still meet:

git checkout -- file # same as git restore
git reset HEAD file # same as git restore --staged

git restore <file> is unrecoverable. The change was never committed, so Git has no copy. There is no undo — which is why git status and git diff come first.

git stash # shelve everything
git stash -u # include untracked files
git stash push -m "wip search" # named
git stash list
git stash pop # restore and remove
git stash apply # restore and keep
git stash drop

git stash without -u leaves untracked files behind, which is a frequent surprise — you stash, switch branch, and your new file is still there.

Stash is for switching branches with unfinished work. It is not storage: a stash from three weeks ago is a commit you should have made on a branch.

Amending

git commit --amend # edit the last message
git commit --amend --no-edit # add staged changes to the last commit

Right for a typo in a message or a file you forgot, before pushing.

Amending rewrites history. After pushing, the amended commit has a different hash, so everyone else's history diverges — and the fix is a force push, which is a conversation with the team, not a solo decision.

Rule: amend freely before pushing, never after.

History

git log
git log --oneline
git log --oneline --graph --all
git log -5
git log --author="Ravi"
git log --since="2 weeks ago"
git log -- src/Data/FeeRepository.cs # commits touching one file
git log -p -- src/Data/FeeRepository.cs # with diffs
git log -S "IsCancelled" # commits adding or removing that string
git show a3f9c1
git show a3f9c1 --stat
git show a3f9c1:src/Data/FeeRepository.cs

git log -S "text" searches the content of changes, not commit messages. It answers "when did this magic number appear?" and "who wrote this connection string?" — often the fastest route to a cause.

Diagnosing

SymptomCause
A file will not be ignoredAlready tracked — git rm --cached
bin/ in every commitMissing or wrong .gitignore
Every line shows as changedLine endings — set core.autocrlf
Commits show the wrong authorEmail mismatch in config
"nothing to commit" after editingNot staged — run git add
A lost uncommitted changegit restore discarded it — unrecoverable
A stashed file is missingUntracked, stashed without -u
git config user.email
git check-ignore -v <path>
git status

Those three answer most of the table.

Errors you will hit

MessageCauseFix
fatal: not a git repositoryNot inside onegit init, or cd into it
nothing to commit, working tree cleanChanges not staged, or nothing changedgit status
bin/ keeps appearingMissing .gitignore, or already trackedgit rm --cached
Every line shows as changedLine endingsSet core.autocrlf
Commits show the wrong authorEmail mismatchgit config user.email
A change vanishedgit restore discarded itUnrecoverable — it was never committed

git restore on an uncommitted change is unrecoverable. That is why git status and git diff come first.

Common mistakes

  • No .gitignore before the first commit
  • Committing bin/, obj/, node_modules/
  • Committing a connection string or .env
  • git add . without reading git status
  • Committing without reading git diff --staged
  • Messages that restate the filename
  • Giant end-of-day commits
  • git add -A when the change should be two commits
  • Amending after pushing
  • Using stash as long-term storage
  • The wrong email in config

Practice

The course exercise is create meaningful commits.

  1. Create a repository and configure name, email and core.autocrlf.
  2. Write a .gitignore for .NET before the first commit.
  3. Make two unrelated changes in two files. Stage one, commit it, and confirm the other is still pending.
  4. Make two unrelated changes in one file. Use git add -p to commit them separately.
  5. Read git diff --staged before a commit. Add a Console.WriteLine, stage it, and catch it in the diff.
  6. Write a message with a body explaining why. Then write one saying Updated file and compare what each tells a reader.
  7. Commit a file, then add it to .gitignore. Confirm it is still tracked, then git rm --cached it.
  8. Run git check-ignore -v on a file Git will not add.
  9. Edit a file and git restore it. Confirm the change is gone permanently.
  10. Stage a change, then git restore --staged it. Confirm the change survives.
  11. Stash tracked and untracked changes without -u. Switch branch and find the untracked file still present.
  12. Amend a commit message, then amend to add a forgotten file.
  13. Run git log --oneline --graph --all on a repository with several branches.
  14. Use git log -S to find when a specific string was introduced.
  15. Commit a fake connection string, then look for it with git log -p | grep. Confirm deleting it in a later commit does not remove it from history.

Exercise 15 is the one to do once, deliberately, on a throwaway repository.

You can now

  • Create a repository and configure your identity
  • Write a .gitignore before the first commit
  • Stage deliberately with git add -p
  • Read git diff --staged before committing
  • Write a commit message that explains why
  • Use Git from Visual Studio and VS Code as well as the command line

Review questions

  1. What does the staging area let you do that committing everything does not?
  2. What four things are you looking for in git diff --staged?
  3. Why does deleting a committed secret not remove it?
  4. When is git commit --amend safe?

Next: Remote repositories