← Resource center
Engineering··22 min read

Git and GitHub: From your first commit to how teams ship together

Niraj Pahadi·Software Engineer, Novelty Lab
GitHub repository setup

Git is a version control system that tracks changes in your code over time. Think of it as an undo history for your project—you can save snapshots (commits), revert to earlier versions, and safely experiment without breaking your code. It also lets multiple developers work on the same codebase efficiently by managing changes from different people in an organized way.

GitHub is a cloud platform built on top of Git. It hosts your code online, making it easy to collaborate, review changes, and contribute to projects. Alongside managing code history, it enables collaboration through branching, pull requests, and code reviews.

Git works with platforms like GitHub and GitLab in modern development. Git manages code history locally; GitHub and GitLab store it online and enable collaboration. GitHub focuses on code hosting, pull requests, and open-source collaboration, whereas GitLab is an all-in-one DevOps platform with built-in CI/CD, project management, and deployment tools. Together, they form the core workflow for modern software development.

Creating a GitHub account

Navigate to github.com and sign up with a unique username, your email, and a strong password. After verifying the code sent to your email, your profile is ready. For setup, security (including two-factor authentication), and profile best practices, see GitHub's Beginner's guide to setting up and securing your profile.

Before you begin

Install Git from git-scm.com. On Windows, Git Bash is where you'll run Git commands. Open Git Bash and verify:

Bash
git --version

If Git is installed correctly, you'll see something like:

Bash
git version 2.44.0.windows.1

That's your green light—you're ready to go.

Sign every commit with your identity

Before Git tracks your work, it needs to know who you are. Every commit is stamped with a name and email—like signing your work. Run these in Git Bash:

Bash
git config --global user.name "Your Name"
git config --global user.email "you@example.com"

Important: Use the same email as your GitHub account so commits link to your profile.

For example:

Bash
git config --global user.name "Alex Rivera"
git config --global user.email "alex.rivera@example.com"

Double-check:

Bash
git config --global --list

You should see your name and email. If something is wrong, run the `git config` commands again—Git overwrites the old values. Set this once; every commit on this machine will carry your identity from then on.

Setting up a new project on GitHub

On github.com, go to Repositories and click New. Name the repo (e.g. *my-first-project*), add an optional description, and choose Public or Private. If you already have a local project, do not initialize with a README—that can cause conflicts when you connect your local repo. Click Create repository.

Create a project on your PC

Open Terminal, Command Prompt, or PowerShell and go where you want the project (e.g. Desktop with `cd Desktop`). Create a folder with `mkdir project-name`, enter it with `cd project-name`, add your files, then open the folder in your editor with `code .`. You now have a clean project folder before `git init` and connecting to GitHub.

Pushing your first project to GitHub

Open the project in VS Code with `code .`, initialize Git, stage, commit, rename the default branch to `main` (after the first commit), add the remote, and push:

Bash
# Open the current project folder in VS Code
code .

# Initialize a new Git repository (creates a .git folder)
git init

# Stage all files in the project for tracking
git add .

# Create the first commit (save snapshot of your project)
git commit -m "initial commit"

# Rename the default branch to 'main'
git branch -M main

# Connect your local project to a GitHub repository
git remote add origin git@github.com:your-username/your-repo.git

# Push your code to GitHub and set upstream for future pushes
git push -u origin main

Daily workflow: track, stage, and commit

Once the project is connected to Git, use a simple loop: `git status` to see changes, `git add` to stage, `git commit` to save:

Bash
# See what's changed
git status

# Stage everything
git add .

# Or stage a specific file
git add src/components/Header.jsx

# Commit with a meaningful message
git commit -m "feat: add responsive header with mobile nav"

A clean way to manage your code

Use a feature-based branching strategy: every feature gets its own branch instead of coding directly on `main`. That keeps `main` stable while you experiment. Update `main`, create a branch (e.g. `feature/auth-system`), commit, push, then merge—usually via a pull request. This keeps the codebase organized and makes collaboration and reviews smoother.

Bash
# Make sure you're on main and it's updated
git checkout main
git pull origin main

# Create and switch to a new feature branch
git checkout -b feature/your-feature-name

# Work on your feature, then stage and commit changes
git add .
git commit -m "feat: implement your feature"

# Push the feature branch to GitHub
git push -u origin feature/your-feature-name

# After review, merge back into main
git checkout main
git pull origin main
git merge feature/your-feature-name

# Push updated main branch
git push origin main

How teams collaborate on the same codebase

Here's how a five-person engineering team might work in practice:

PersonRoleTask
SarahTeam LeadManages the repo, reviews PRs, handles final merges
AlexDeveloperBuilding the user authentication system
BlakeDeveloperBuilding the payment gateway integration
CharlieDeveloperDesigning the product dashboard
DianaDeveloperFixing a critical bug in the notification service

Nobody writes on `main` directly—`main` is production-ready. Everyone clones locally, branches for their task, and integrates through GitHub.

Step 1: Setting the foundation

Sarah initializes the repository and pushes `main`. Alex, Blake, Charlie, and Diana clone once:

Bash
# Run by Alex, Blake, Charlie, and Diana on their respective machines
git clone git@github.com:novelty-lab/global-marketplace.git
cd global-marketplace

Step 2: Isolated feature development

Alex's workflow (user auth)

Bash
git checkout main
git pull origin main
git checkout -b feature/user-auth

# Alex writes authentication code...

git add src/auth/
git commit -m "feat: implement JWT-based user login and session handling"
git push -u origin feature/user-auth

Blake's workflow (payments)

Blake works on `feature/stripe-payments` in parallel—his files don't collide with Alex's auth work:

Bash
git checkout main
git pull origin main
git checkout -b feature/stripe-payments

git add src/payments/
git commit -m "feat: integrate Stripe API for checkout processing"
git push -u origin feature/stripe-payments

Step 3: Peer review and continuous integration

Alex opens a pull request from `feature/user-auth` into `main`. Sarah and Charlie review the diff, leave comments, and after approval Sarah merges on GitHub. Alex's code is now on `main`.

Step 4: Staying in sync and resolving conflicts

After Alex merges, Blake's branch is behind. He updates `main` locally and merges it into his feature branch:

Bash
git checkout main
git pull origin main
git checkout feature/stripe-payments
git merge main

If both edited the same line (e.g. in `package.json`), Git reports a conflict. Blake resolves markers in the editor, then:

Bash
git add package.json
git commit -m "chore: resolve merge conflict with main branch"
git push origin feature/stripe-payments

Step 5: Final review and shipping

Blake opens his PR; Sarah merges after checks pass. Charlie and Diana follow the same loop for dashboard and notifications. Pull, branch, commit, push, review, sync—five people can ship large features without overwriting each other.

When and why teams use rebase

Merging `main` into a feature branch works, but many teams prefer rebase to keep history linear. Rebase replays your commits on top of the latest `main` instead of creating a merge commit.

Merge vs rebase

With merge, histories combine with an extra merge commit. With rebase, your commits are re-applied on top of updated `main`—cleaner `git log`, easier reviews.

Before opening a PR, Blake might run:

Bash
git checkout main
git pull origin main
git checkout feature/stripe-payments
git rebase main
  • The branch includes everything merged to `main` since branching.
  • The PR is smaller and easier to review.
  • History stays linear after merge.

Handling conflicts during rebase

Bash
# Fix the conflict in your editor
git add .
git rebase --continue

When not to rebase: Never rebase shared branches like `main` or `staging`, or any branch others are actively pushing to. Rebase only on your own feature branch.

Taking clean history one step further: squash

Squash collapses many WIP commits into one meaningful commit before merge. Noisy history:

Bash
feat: add payment form
fix: typo in button label
fix: validation not triggering on submit
wip: still debugging stripe webhook
fix: finally got stripe working
chore: remove console logs

After squash, `main` might get a single line: `feat: integrate Stripe payment gateway`.

How to squash commits

Interactive rebase — squash the last four commits:

Bash
git rebase -i HEAD~4

Change `pick` to `squash` (or `s`) on all commits except the first, save, then edit the final message. Squash merge on GitHub — when merging a PR, choose Squash and merge so GitHub squashes automatically; many teams commit freely locally and squash at merge time.

Rebase + squash: the full picture

Bash
# Branch off main
git checkout -b feature/stripe-payments

# Work freely — commit often
git commit -m "wip: payment form"
git commit -m "fix: webhook validation"
git commit -m "fix: remove console logs"

# Rebase onto latest main before the PR
git rebase main
# resolve conflicts, then: git rebase --continue

# Squash messy commits into one
git rebase -i HEAD~3

# Push and open the PR
git push --force-with-lease origin feature/stripe-payments

# Lead merges — main stays clean and linear

After squashing or rebasing, use git push --force-with-lease instead of git push --force. It refuses to overwrite if someone else pushed to the branch since your last fetch.

Merge vs rebase vs squash at a glance

MergeRebaseSquash
What it doesCombines two branch historiesReplays commits on top of another branchCollapses multiple commits into one
Commit historyBranching, non-linearClean and linearClean and minimal
Extra commitsCreates a merge commitNo extra commitsOne final commit
Safe on shared branches?YesNoYes (via GitHub squash merge)
Best forIntegrating stable, completed workKeeping a feature branch currentCleaning up history before merging

Why high-performing teams use all three

  • Merge when combining stable work where full history matters (e.g. a release branch into `main`).
  • Rebase during development to stay current and keep history linear once merged.
  • Squash to turn noisy commits into one clear entry in shared history.

Together they produce a history that's easy to debug, fast to scan with `git log`, and clear for the next engineer who joins the project.

Quick reference

CommandWhat it does
git initInitialize a new repository
git clone <url>Copy a remote repository locally
git statusSee what has changed
git add .Stage all changes
git commit -m "message"Save a snapshot of staged changes
git pushUpload commits to GitHub
git pullDownload and merge remote changes
git checkout -b <name>Create and switch to a new branch
git merge <branch>Merge another branch into the current one
git rebase <branch>Replay your commits on top of another branch

Feature branching, pull requests, and rebasing are how professional teams ship every day. Master these habits early—they scale with you at every stage of your career.