LEARN BUILD GROW TOGETHER
DEVELOPER LEARNING HUB
Learn. Build. Grow Together.

Practical tutorials, real-world examples and interview preparation.

.NETC#SQL SERVERANGULAR
Home /Developer Guide /Git & Version Control – Complete Developer Learning Guide

Git & Version Control – Complete Developer Learning Guide

Git & Version Control – Complete Developer Learning Guide

Git & Version Control

A practical, beginner-to-advanced guide to tracking code changes, working with branches, merging and rebasing, resolving conflicts, and collaborating through GitHub pull requests and team workflows.

Git 2.56.1GitHub.NET 10 LTSC# 14Beginner to Advanced

01. Introduction to Version Control

Software changes constantly. Features are added, defects are fixed, dependencies are upgraded, and several developers may work on the same codebase at the same time. Version control records how files change so a team can understand, compare, restore, and collaborate on work safely.

Developer AFeature changesGit repositoryHistory + branchesDeveloper BBug fixesCommit, compare, review, merge and restore changes

Git records project history locally; a hosting platform such as GitHub adds remote collaboration features.

This guide focuses on Git fundamentals and professional team workflows, with examples drawn from an ASP.NET Core Web API solution. The same practices apply to frontend, mobile, data, and other software projects.

02. What Is Git?

Git is a distributed version control system. Each clone contains repository history and can create commits locally without needing a central server. Developers later exchange changes with remote repositories.

  • Distributed: a clone contains the project's Git history, subject to clone options.
  • Snapshot-oriented: commits represent project snapshots, while Git efficiently reuses stored data.
  • Branch-friendly: branches are lightweight references that make parallel work practical.
  • Integrity-aware: Git identifies objects using cryptographic hashes.
Remember: Git is the version control tool. GitHub is a hosting and collaboration platform built around Git repositories. They are related, but they are not the same product.

03. Why Version Control Matters

Without version control, teams often rely on copied folders, filenames such as final-v2-really-final, and manual coordination. Git replaces that fragile process with an auditable history.

  • Understand who changed a file and when.
  • Compare current code with an earlier version.
  • Work on features independently using branches.
  • Review changes before they reach the shared branch.
  • Restore a previous state or revert an unwanted commit.
  • Connect source changes with issues, releases, and automated builds.

04. Git vs GitHub vs GitLab vs Azure Repos

ToolWhat it providesTypical use
GitDistributed version control engine and command-line toolsTrack source changes locally and exchange commits
GitHubGit hosting, pull requests, issues, Actions, security and collaborationOpen-source and enterprise team workflows
GitLabGit hosting with integrated planning, CI/CD and security capabilitiesIntegrated DevSecOps platform
Azure ReposGit repositories and pull requests within Azure DevOpsTeams using Azure Boards and Pipelines

The Git commands in this guide are largely portable across these hosting services. The web interface, policy controls, and automation integrations differ.

05. How Git Stores Changes

Git's object model is built around blobs (file content), trees (directory structure), commits (snapshots plus metadata and parent links), and annotated tags (named release references). A branch is a movable reference to a commit.

Branch: mainCommitTreeBlob: Program.csBlob: appsettingsBlob: README

A simplified view: a branch name points to a commit, and the commit references a tree describing the snapshot.

You usually interact with these internals through commands such as git log, git show, and git cat-file; memorizing object internals is not required for everyday work.

06. Install Git and Verify the Setup

Install Git using the official Git installation page. Git for Windows includes Git Bash; macOS and Linux also provide package-manager options.

git --version
git --help

Git releases evolve independently of .NET. At the time this guide was prepared, Git 2.56.1 was the current stable release. Install the latest security-patched release available for your operating system.

Security note: Keep Git updated. Git security fixes may address risks triggered while cloning or processing untrusted repositories. Do not run scripts from an unfamiliar repository without reviewing them.

07. Configure Your Git Identity

Git stores author and committer identity in commit metadata. Configure a name and an email address that you intend to use for your work.

git config --global user.name "Developer Name"
git config --global user.email "developer@example.com"

git config --global --list

Use --global for your default identity. A repository-specific configuration (without --global) overrides it for that repository. For privacy, GitHub also supports a noreply email address.

08. Create Your First Repository

Start with a small .NET API project and initialize Git in its root directory.

dotnet new webapi -n InventoryApi
cd InventoryApi

git init
git status

git init creates the local .git database. It does not upload your code anywhere. The working directory contains your project files; Git status tells you which changes are untracked, staged, or modified.

09. The Three Main Areas of Git

Everyday Git work becomes easier when you understand three areas: the working tree, the staging area (index), and the repository history.

Working treeEdit filesStaging areaSelect next snapshotLocal repositoryCommit historyedit → git add → git commit
  • Working tree: files you are currently editing.
  • Staging area: the exact changes selected for the next commit.
  • Repository: committed snapshots and their history.

10. Check Status and Inspect Changes

Use status and diff frequently. They are safe inspection commands and help prevent accidental commits.

git status
git diff
git diff --staged
git diff -- Program.cs

git diff shows unstaged changes. git diff --staged shows what is currently selected for the next commit. Review both before committing.

11. Stage Files with git add

Staging is an intentional selection step. You can stage one file, several files, or all current changes.

git add Program.cs
git add Controllers/
git add .
git status

For a large or mixed change, consider git add -p to stage individual hunks. This lets one commit contain one coherent logical change even when several files have unrelated edits.

12. Create Meaningful Commits

A commit records the staged snapshot with a message. Prefer small, focused commits that explain why the change exists.

git commit -m "Add product search endpoint"
git log --oneline --decorate -5

A useful message is specific and action-oriented. Avoid vague messages such as changes, update, or final. A commit should ideally represent one logical unit of work.

Example: “Validate inventory quantity before saving” tells a reviewer more than “fix code”.

13. Read and Explore Commit History

Git history helps you understand how a project reached its current state.

git log
git log --oneline --graph --decorate --all
git show HEAD
git show <commit-id>
git blame Controllers/ProductsController.cs

git blame identifies the commit that last changed each line; it is a navigation aid, not proof of who is responsible for a defect.

14. Understand HEAD and References

HEAD identifies the current checkout position, usually the current branch. A branch is a movable name for a commit. As you create commits on that branch, the branch reference advances.

git status
git branch --show-current
git rev-parse HEAD

Detached HEAD means you checked out a commit directly rather than a branch. It is useful for inspection, but create or switch to a branch before making work you want to keep.

15. Create and Switch Branches

Branches isolate work so a feature or fix can progress without changing the main development line.

git branch
git switch -c feature/product-search
# make changes and commit
git switch main

Modern Git recommends git switch for switching branches. The older git checkout command still exists and performs several different tasks.

16. Branch Naming Conventions

Use short, descriptive branch names that make the purpose obvious. Agree on a convention with the team.

PrefixExamplePurpose
feature/feature/customer-exportNew capability
bugfix/bugfix/order-total-roundingDefect correction
hotfix/hotfix/payment-timeoutUrgent production fix
chore/chore/update-packagesMaintenance task
docs/docs/api-readmeDocumentation-only work

Branch naming is a team convention, not a Git requirement.

17. Branching Strategies

A branching strategy defines how a team creates, integrates, and releases work. Choose the simplest strategy that fits release frequency and team coordination.

StrategyShapeUseful when
Trunk-based developmentShort-lived branches integrate frequently into mainTeams release often and rely on automated tests and feature flags
GitHub FlowBranch from main, open PR, review, mergeWeb applications and continuous delivery
Git Flowmain, develop, feature, release and hotfix branchesTeams with planned release trains and parallel maintenance

No strategy is universally best. Long-lived branches increase the time changes remain apart and can make integration harder.

18. GitHub Flow in Practice

GitHub Flow is a lightweight workflow centered on a deployable main branch and short-lived topic branches.

mainbranchreview + PRmergedBuild • Test • Review • Merge • Deploy

A feature branch is created from main, reviewed through a pull request, and merged after required checks pass.

  1. Pull the latest main branch.
  2. Create a focused branch.
  3. Commit and push your changes.
  4. Open a pull request and explain the change.
  5. Address review feedback and automated checks.
  6. Merge using the team's chosen method and delete the branch when appropriate.

19. Merge: Combine Branch Histories

git merge integrates changes from another branch into the currently checked-out branch. A fast-forward merge moves the branch pointer when no divergent history exists. A three-way merge creates a merge commit when histories have diverged and Git can combine them.

git switch main
git merge feature/product-search

Merge preserves the original commits. A merge commit records the integration point and can make the history of parallel work visible.

20. Resolve Merge Conflicts

A conflict occurs when Git cannot automatically determine how to combine overlapping changes. Git pauses the merge and marks the affected files.

git status
# Open each conflicted file and decide the correct result
git add Controllers/ProductsController.cs
git commit

Conflict markers commonly look like <<<<<<<, =======, and >>>>>>>. Remove the markers, preserve the intended code, run tests, then stage the resolved file.

Do not blindly choose “ours” or “theirs”. Understand both changes and verify the resulting behavior. To cancel a merge in progress, use git merge --abort when supported by the current state.

21. Rebase: Replay Commits on a New Base

git rebase moves or replays commits so your branch is based on a newer commit. It can create a linear history, but the replayed commits receive new identities.

git switch feature/product-search
git fetch origin
git rebase origin/main
Before rebase→After rebasemainbasemain tipfeature commitsnew basereplayed

Conceptual illustration: feature commits are replayed after the updated main commit.

Rebase is useful for updating a private feature branch before review. Avoid rewriting commits that teammates have already based work on unless the team explicitly coordinates it.

22. Merge vs Rebase

AspectMergeRebase
HistoryPreserves branch topology; may add merge commitReplays commits and produces new commit IDs
TraceabilityShows integration pointsOften creates a linear sequence
Shared commitsSafe way to integrate shared branch historyRewriting shared history can disrupt collaborators
Typical useIntegrate completed workRefresh a private feature branch

Both are valid. Agree on repository policy and understand whether history is being rewritten before choosing rebase.

23. Interactive Rebase and Squashing

Interactive rebase lets you edit, reorder, reword, combine, or remove commits in a selected range.

git rebase -i HEAD~3

Common actions include pick, reword, squash, fixup, and drop. Use it to clean up your own unpublished work before sharing. Do not use it casually on commits already consumed by others.

24. Undo Changes Safely

Different commands undo different kinds of work. Check git status first and understand whether the change is uncommitted or already shared.

CommandPurposeCaution
git restore fileDiscard unstaged working-tree edits in a fileLocal edits can be lost
git restore --staged fileUnstage a file while keeping its working-tree editsDoes not discard the edits
git revert commitCreate a new commit that reverses an earlier commitReview the inverse change
git resetMove the current branch reference and optionally alter index/working treeCan discard work or rewrite local history

For shared branches, git revert is usually safer than rewriting published history with reset.

25. Reset: Soft, Mixed and Hard

git reset moves the current branch to a selected commit. Its mode controls what happens to the staging area and working tree.

git reset --soft HEAD~1
git reset --mixed HEAD~1
git reset --hard HEAD~1
  • --soft: move HEAD; keep changes staged.
  • --mixed: move HEAD; unstage changes but keep working-tree content (the default mode).
  • --hard: move HEAD and overwrite the index and working tree.
Danger: --hard can permanently discard uncommitted changes. Confirm the target commit and backup important work before using it.

26. Stash Temporary Work

Stash saves selected working-tree changes temporarily so you can switch context without creating a commit.

git stash push -m "WIP product validation"
git stash list
git stash show -p
git stash apply
git stash pop

apply keeps the stash entry; pop applies it and removes the entry when successful. Stash is a short-term shelf, not a substitute for committing valuable work.

27. Tags and Releases

Tags identify important points in history, commonly release versions. Lightweight tags are simple references; annotated tags store metadata and can be signed.

git tag v1.0.0
git tag -a v1.1.0 -m "Inventory API 1.1.0"
git push origin v1.1.0
git tag --list

Use a consistent versioning policy such as Semantic Versioning where it fits the product. A tag does not automatically create a GitHub Release, though GitHub can create a release from a tag.

28. Remote Repositories

A remote is a named reference to another repository, often hosted on GitHub, GitLab, or Azure Repos.

git remote -v
git remote add origin https://github.com/org/inventory-api.git
git remote set-url origin <new-url>
git fetch origin

origin is only a conventional remote name. A repository can have multiple remotes, for example an upstream project and your own fork.

29. Clone, Fetch, Pull and Push

git clone https://github.com/org/inventory-api.git
git fetch origin
git pull --ff-only
git push -u origin feature/product-search
  • clone: create a local copy of a remote repository.
  • fetch: download remote objects and update remote-tracking references without integrating them into your current branch.
  • pull: fetch and then integrate changes according to configuration/options.
  • push: publish local commits to a remote branch.

Use git pull --ff-only when you want pull to refuse an implicit merge if a fast-forward is not possible. Teams may choose another explicit pull strategy.

30. Track Remote Branches

Remote-tracking branches such as origin/main represent the last fetched state of branches on a remote. They are updated by fetch and are not normally edited directly.

git branch -a
git switch --track origin/feature/customer-export
git branch -vv

After fetching, compare your local branch with its upstream to see whether you are ahead or behind.

31. Forks and Upstream Workflows

A fork is your own server-side copy of another repository. It is common in open-source collaboration and organizations that restrict direct writes to the main repository.

git remote add upstream https://github.com/original/project.git
git fetch upstream
git switch main
git merge --ff-only upstream/main
git push origin main

Use a pull request from your fork to the original repository. Follow the project's contribution guide, license, code of conduct, and security policy.

32. GitHub Repository Essentials

A GitHub repository combines Git history with collaboration features. Common repository elements include README, license, contribution guidelines, issue templates, pull request templates, branch rules, releases, and Actions workflows.

For a professional .NET repository, document prerequisites, how to restore/build/test, configuration requirements, database setup, and how to run the application locally. Never put secrets or production connection strings in the README.

33. Pull Requests: Purpose and Lifecycle

A pull request (PR) proposes a set of changes for review before merging them into a target branch. It provides a shared place to discuss design, inspect diffs, run checks, and record approval.

Push branchCommitsOpen PRDescribe scopeReviewCommentsChecksBuild + testsMergeIntegrateA PR is a conversation and quality gate around a proposed change.

Keep PRs focused, explain the reason for the change, link the related issue, describe testing, and call out risks or deployment steps.

34. Write Effective Pull Request Descriptions

A reviewer should quickly understand the problem, the approach, and how to verify the result. A practical PR description can include:

  • Summary: what changed and why.
  • Implementation: important design decisions.
  • Testing: commands or test cases executed.
  • Risk: migration, configuration, compatibility, or rollout concerns.
  • Evidence: screenshots or API examples where useful.

Keep the diff reviewable. Split unrelated refactoring from a feature change when doing so makes review safer.

35. Code Review Best Practices

Good code review improves correctness and shared understanding. Review behavior, edge cases, readability, security, performance, tests, and maintainability—not personal style preferences that are already handled by formatters or analyzers.

  • Ask specific, respectful questions.
  • Explain why a requested change matters.
  • Distinguish blocking issues from optional suggestions.
  • Review the full diff, not only the changed lines.
  • Authors should respond to every actionable comment and rerun relevant checks.

36. Choose a Pull Request Merge Strategy

MethodHistory resultUse when
Merge commitPreserves branch commits and adds an integration commitTeam wants visible branch topology
Squash and mergeCombines PR commits into one commit on the base branchOne logical PR should become one commit
Rebase and mergeReplays commits onto base without a merge commitTeam prefers linear history and commits are meaningful

GitHub repository settings can enable or disable available merge methods. Pick a policy that matches your team's history and release practices.

37. Protect Important Branches

Protect the default and release branches with repository rules or branch protection settings. Depending on the hosting plan and repository configuration, policies can require pull requests, approvals, status checks, signed commits, linear history, or restricted pushes.

  • Require CI checks to pass before merging.
  • Require at least one approval for sensitive repositories.
  • Dismiss stale approvals when new commits change the reviewed code, if appropriate.
  • Restrict force pushes and deletion of protected branches.
  • Use CODEOWNERS to request review from responsible teams.

38. Git Ignore and .gitignore

.gitignore tells Git which untracked files and paths to ignore. A .NET repository commonly excludes build output, IDE user state, local secrets, and temporary files.

**/bin/
**/obj/
.vs/
*.user
*.suo
.env
appsettings.Development.local.json

Do not ignore files that the team needs to build the project. A file already tracked by Git remains tracked even if it is later added to .gitignore; remove it from the index with git rm --cached when appropriate.

39. Git Attributes, Line Endings and File Types

.gitattributes controls attributes such as text normalization, diff behavior, and merge handling. Consistent line endings reduce noisy diffs when developers use different operating systems.

* text=auto
*.cs text eol=lf
*.sln text eol=crlf

Choose a repository policy that matches your toolchain and team. Do not copy line-ending rules blindly; validate them on Windows, macOS, and Linux environments used by the project.

40. Secrets and Repository Security

Never commit passwords, API keys, private certificates, access tokens, or production secrets. Add local secret files to .gitignore, use environment variables or a secret manager, and configure CI secrets through the hosting platform's protected secret store.

  • Enable secret scanning and push protection where available.
  • Use least-privilege tokens and short-lived credentials.
  • Rotate a secret immediately if it is committed or exposed.
  • Removing a secret in a later commit does not remove it from earlier history.
  • Use signed commits or verified identities when required by policy.
Incident response: Treat an exposed credential as compromised. Revoke or rotate it first; then assess repository history and coordinate any history rewrite with collaborators.

41. Git LFS and Large Files

Git is optimized for source files and text diffs. Large binary assets such as media, datasets, or design files can make a repository grow quickly. Git Large File Storage (LFS) stores pointer files in Git while the large content is stored separately.

git lfs install
git lfs track "*.psd"
git add .gitattributes
git add design/mockup.psd

Review hosting quotas, bandwidth, retention, and team needs before adopting LFS. Do not use it as a replacement for a proper artifact or data-storage system.

42. Submodules and Subtrees

Submodules and subtrees let one repository include content maintained in another repository. They solve different dependency and source-sharing needs.

git submodule add https://github.com/org/shared-library.git libs/shared
git submodule update --init --recursive

Submodules pin a specific commit of another repository and require developers to initialize/update them. Subtrees copy or merge another project's history into a subdirectory. For .NET libraries, a package feed is often simpler than embedding another repository.

43. Git Worktrees

Worktrees let you check out multiple branches from one local repository into separate working directories. This is useful when you need to inspect a hotfix while keeping a feature branch open.

git worktree add ../InventoryApi-hotfix hotfix/payment-timeout
git worktree list
git worktree remove ../InventoryApi-hotfix

Worktrees share the repository's object database but have separate working directories and indexes. A branch generally cannot be checked out in two worktrees simultaneously.

44. Useful Git Inspection and Recovery Tools

git reflog
git fsck --lost-found
git diff main...feature/product-search
git log --all --oneline --graph
git show --stat HEAD

git reflog records recent movements of local references and can help recover a commit after a mistaken reset or rebase. Reflog entries expire, so it is not a permanent backup. Learn these tools before you need emergency recovery.

45. Git Hooks and Automation

Git hooks are scripts triggered by repository events such as commit or push. They can run formatters, linters, or checks locally, but local hooks can be bypassed and are not a substitute for server-side CI requirements.

For a .NET solution, a pre-commit hook might run formatting checks, while CI should perform authoritative restore, build, test, and security checks on pull requests.

46. GitHub Actions: CI for a .NET Project

GitHub Actions runs workflows defined as YAML files in .github/workflows. A workflow can run on pull requests, pushes, manual dispatch, or schedules. This simple example restores, builds, and tests a .NET 10 solution.

name: .NET CI

on:
  pull_request:
  push:
    branches: [ main ]

jobs:
  build-and-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-dotnet@v4
        with:
          dotnet-version: '10.0.x'
      - run: dotnet restore
      - run: dotnet build --no-restore --configuration Release
      - run: dotnet test --no-build --configuration Release
Action versions: This is an instructional example. Before production use, review current action versions, pin third-party actions to full commit SHAs according to your security policy, and configure permissions with least privilege.

47. A Practical Team Workflow for an ASP.NET Core API

  1. Clone the repository and install the required .NET SDK.
  2. Read README, contribution guidance, and branch policy.
  3. Fetch the latest remote state and update main.
  4. Create a branch such as feature/customer-search.
  5. Implement the change and add or update tests.
  6. Run dotnet format, dotnet build, and dotnet test as appropriate.
  7. Review staged changes and create focused commits.
  8. Push the branch and open a pull request.
  9. Address review comments and wait for required CI checks.
  10. Merge using the repository policy and verify the deployed result.
git switch main
git pull --ff-only
git switch -c feature/customer-search

# edit, test, inspect
git status
git diff
git add .
git commit -m "Add customer search endpoint"
git push -u origin feature/customer-search

48. Common Git Mistakes

MistakeBetter practice
Committing generated outputUse a reviewed .gitignore and inspect status
One huge commit for unrelated workStage and commit coherent changes
Rebasing shared commits without coordinationPreserve published history or coordinate a rewrite
Force-pushing mainProtect important branches and use reviewed PRs
Committing secretsUse secret stores and scanning; rotate exposed credentials
Ignoring conflicts without testingUnderstand both sides and run relevant tests
Pulling without understanding strategyUse explicit fetch/integration behavior agreed by the team

49. Troubleshooting Everyday Git Problems

  • “Nothing to commit”: check whether files changed, are ignored, or are already staged.
  • Push rejected: fetch remote changes, integrate them safely, then push again.
  • Authentication failed: verify HTTPS credential manager or SSH key setup and account permissions.
  • Wrong branch: inspect status and branch before committing; move uncommitted work carefully.
  • Merge conflict: resolve each file, stage the result, and complete or abort the merge.
  • Accidental commit: decide whether it is local-only or shared; choose reset, amend, or revert accordingly.

When in doubt, stop and inspect git status, git log, and git reflog before running destructive commands.

50. Mini Project: Collaborate on an Inventory API

Practice the full workflow with a small ASP.NET Core API repository.

  1. Create an InventoryApi repository and add a README, license if appropriate, and .gitignore.
  2. Create a main branch with a working baseline and a CI workflow.
  3. Developer A creates feature/product-crud; Developer B creates feature/stock-validation.
  4. Each developer commits focused changes and pushes their branch.
  5. Open separate pull requests and review each other's code.
  6. Intentionally create an overlapping edit to practice conflict resolution.
  7. Merge using the team's chosen strategy and verify CI.
  8. Tag a sample release such as v1.0.0.

Deliverable: a repository with a clear commit history, reviewed pull requests, a repeatable build/test workflow, and documented setup instructions.

51. Interview Questions and Answers

1. What is Git?

Git is a distributed version control system that records project history and supports parallel development.

2. How is Git different from GitHub?

Git is the version control tool; GitHub hosts Git repositories and adds collaboration, review, automation, and project features.

3. What are the working tree, index, and repository?

The working tree contains current files, the index stages the next snapshot, and the repository stores committed history.

4. What is a commit?

A commit is a recorded snapshot with metadata and parent commit references.

5. What is a branch?

A branch is a movable reference to a commit, commonly used to isolate a line of development.

6. What is the difference between fetch and pull?

Fetch downloads remote updates without integrating them; pull fetches and then integrates according to the configured or specified strategy.

7. What is the difference between merge and rebase?

Merge integrates histories and may create a merge commit; rebase replays commits onto a new base and changes their identities.

8. What is a merge conflict?

A conflict occurs when Git cannot automatically combine overlapping changes. A developer must resolve the intended result.

9. When should you use revert instead of reset?

Revert is generally safer for shared history because it adds a new inverse commit. Reset moves a branch reference and can rewrite or discard local work.

10. What does git stash do?

It temporarily shelves selected uncommitted changes so you can switch context.

11. What is a pull request?

A pull request proposes changes for discussion, review, automated checks, and eventual integration.

12. What are squash, merge commit, and rebase merge?

They are PR integration methods that respectively combine changes into one commit, preserve branch commits with a merge point, or replay commits linearly.

13. Why should secrets never be committed?

Secrets in Git history may remain accessible even after a later deletion. Exposed credentials must be revoked or rotated.

14. What is .gitignore?

A file of patterns that tells Git which untracked files and paths to ignore.

15. What is GitHub Actions?

A GitHub automation platform that runs workflows defined in YAML, commonly for CI, testing, and deployment.

52. Official Documentation and Further Learning

Use the official documentation for current command options, hosting features, security guidance, and release details.

53. Final Thought

Git is more than a set of commands. It is a shared discipline for making software changes understandable, reviewable, and recoverable. Learn to inspect before changing history, commit focused work, collaborate through short-lived branches and pull requests, and protect shared repositories with automated checks.

Start with status, diff, add, commit, branch, switch, fetch, pull, and push. Then practice merge, rebase, conflict resolution, revert, and recovery in a safe repository. Strong Git habits make every software project easier to maintain.

Skills Tutorials – Learn • Build • Grow Together