Git and GitHub Basics
Software changes over time. A feature may take several attempts, two people may edit the same area, and a change that looked correct may later need to be undone. Source control gives a project a structured history so that this work can be understood and coordinated.
This chapter introduces Git, the source-control tool used by Chahua, and GitHub, the service where the project is shared. You do not need to memorize every command. The important first step is learning what Git keeps track of and where your changes are.
Why Source Control Exists
A source control management system, often shortened to SCM or called a version-control system, records changes to a collection of files. It helps developers:
- See what changed, when it changed, and why.
- Work on different changes without constantly overwriting one another.
- Review a proposed change before adding it to the shared project.
- Return to an earlier version when investigating a problem.
- Connect related file changes to an explanation of their purpose.
Source control is more than a backup. A backup can recover an old copy of a file, but source control organizes changes into meaningful units and records how lines of development relate to one another.
Git and GitHub Are Different
Git is the version-control program. It runs on your computer and can record history without an internet connection. A directory whose history is managed by Git is called a repository, or repo.
GitHub is an online service that hosts Git repositories and adds collaboration tools. Chahua developers use it to share branches, discuss proposed changes, run automated checks, and review pull requests.
You can use Git without GitHub, and other hosting services can host Git repositories. In this project, they are used together:
- Git manages files, branches, and commits.
- GitHub stores a shared copy and supports collaboration around it.
A Mental Model of Git
When working on a change, think of it moving through four places:
working directory -> staging area -> local repository -> remote repository
git add git commit git push
The working directory is the project directory you edit. Its files may differ from the last version Git recorded.
The staging area is the set of changes selected for the next commit. Staging lets you choose which changes belong together instead of committing every modified file at once.
The local repository is the Git history stored on your computer. Creating a commit adds to this local history; it does not immediately upload anything.
A remote repository is a copy stored elsewhere, such as on GitHub. The conventional name for the remote from which you cloned a project is origin.
This model explains an important fact: saving a file, staging it, committing it, and pushing it are four different actions.
Inspect Before You Act
The safest command to run when you are unsure is:
git status
git status reports your current branch and describes files with unstaged changes, staged changes, and some files that Git is not yet tracking. It does not modify anything.
To inspect the actual unstaged changes, run:
git diff
After staging changes, inspect what the next commit would contain with:
git diff --staged
These commands answer different questions: git status summarizes where changes are, while git diff shows what changed inside the files.
Commits and the Staging Area
A commit is a recorded unit of change. It represents a snapshot of the project that incorporates the staged changes. It also has a short identifying hash, an author and time, a message explaining the change, and a connection to the commit that came before it.
A useful commit usually represents one understandable idea. For example, correcting a button label and adding its translation may belong in one commit. An unrelated database change should probably be a separate commit. Focused commits are easier to review and investigate later.
After editing a file, select it for the next commit with:
git add path/to/file
The file is now staged. Staging does not save it permanently and does not upload it. It only updates the proposed contents of the next commit. If you edit the same file again after staging it, the staged version and the new unstaged edits can be different, which git status will show.
Once the staging area contains exactly what you intend, create the commit:
git commit -m "Explain the purpose of the change"
The message should help another person understand the commit without reading every changed line. Prefer a concrete description such as Add empty state to conversation list over a vague message such as updates.
Tracked, Untracked, and Ignored Files
A tracked file is already part of the repository’s history. An untracked file exists in the working directory but has not been added to Git.
A .gitignore file lists patterns for files Git should normally leave untracked. Projects commonly ignore generated build output, dependency directories, editor files, and local configuration containing secrets.
.gitignore does not remove a file that is already tracked. It is also not a security boundary: a secret that has been committed may remain in Git history even if the file is ignored later. Check staged changes before committing and never intentionally commit credentials or private keys.
Branches
A branch is a movable name pointing to a line of commits. Branches let work develop separately from the project’s main line. A contributor can create a branch for one feature while other work continues elsewhere.
To create a branch and switch to it:
git switch -c descriptive-branch-name
To switch to an existing branch:
git switch branch-name
Creating a branch does not duplicate the entire project. Initially, the new branch points to the same commit as the branch from which it was created. As you commit, the branch name moves forward to include the new commits.
Before editing, use git status to confirm that you are on the intended branch.
Combining Lines of Work
Branches eventually need to be combined. Git primarily supports two ways to do this: merge and rebase.
Merge
A merge combines the histories of two branches. When both branches have new commits, Git may create a merge commit that records where the histories joined. The existing commits keep their identities.
Conceptually, merging says: “Bring these two lines of work together here.”
Rebase
A rebase takes commits from one branch and recreates them on top of another starting point. This can produce a simpler, linear history, but the recreated commits have new identities.
Conceptually, rebasing says: “Replay my work as though it began from this newer point.”
Because rebase rewrites commits, do not casually rebase commits that other people are already using. Follow the project’s contribution process or ask a maintainer when unsure.
Merge Conflicts
Git can often combine changes automatically. A merge conflict occurs when Git cannot confidently decide how changes should fit together, such as when two branches changed the same lines differently.
A conflict is not necessarily an error by either developer. It is a request for a person to choose the intended result. Read git status, inspect each conflicted file, understand both changes, and test the resolved result before continuing. Avoid guessing merely to make the conflict markers disappear.
Remotes: Fetch, Pull, and Push
Your local repository and the remote repository do not synchronize automatically. Git provides commands that move information between them.
Fetch downloads information about remote branches and commits without integrating them into your current branch:
git fetch origin
This is useful when you want to inspect what changed remotely before changing local history.
Pull fetches remote changes and then integrates them into the current branch according to Git’s configuration:
git pull
Because it performs both steps, read its output carefully. If you want to understand the remote state first, fetch and inspect it separately.
Push uploads local commits and updates a branch on a remote:
git push
The first push of a new branch commonly sets its upstream relationship:
git push -u origin descriptive-branch-name
After that, Git knows which remote branch corresponds to the local branch, so a plain git push is usually sufficient.
These directions are worth remembering:
fetchbrings remote history to your local repository without integrating it.pullbrings remote history down and integrates it into your current branch.pushsends local commits to the remote repository.
A Git pull and a GitHub pull request are different things. git pull updates a local branch. A pull request proposes that maintainers review and combine a branch on GitHub.
Pull Requests and Review
A pull request, often shortened to PR, is a GitHub collaboration feature rather than a Git command. It presents the difference between branches and provides a place for:
- An explanation of the problem and proposed solution.
- Discussion and code review.
- Automated builds, tests, and other checks.
- Additional commits that respond to feedback.
- A decision to merge or close the proposal.
Opening a pull request does not immediately change the main branch. It makes the proposed work visible for review. When the pull request is accepted, GitHub combines it according to the project’s chosen merge strategy.
Exercise: Make a Small Documentation Contribution
In this exercise, you will add a Markdown comment that helps future authors keep the welcome chapter focused. Unlike visible book text, a Markdown comment gives maintainers guidance without appearing in the rendered page.
Do this exercise in a Chahua clone where you are allowed to create a branch. If your clone uses a main branch with a different name, substitute that name below.
1. Prepare a Branch
Check your current state, update main without creating a merge commit, and create a branch for the exercise:
git status
git switch main
git pull --ff-only
git switch -c docs/comment-welcome-purpose
If git status reports uncommitted work, stop before switching branches or pulling. Preserve and understand that work first. The --ff-only option makes the pull stop instead of creating an unexpected merge commit when the histories have diverged.
2. Make the Change
Open docs/src/welcome.md. Directly below # Welcome, add:
<!-- Keep this chapter welcoming and leave setup instructions for Part II. -->
Save the file. This change is now in your working directory, but it is not staged or committed.
3. Inspect and Stage It
Ask Git where the change is and inspect its contents:
git status
git diff
The file should appear as modified, and the diff should show only the comment you added. Stage that specific file:
git add docs/src/welcome.md
Run git status again. The change should now appear under Changes to be committed. Confirm the exact staged change:
git diff --staged
If anything unexpected is included, stop and investigate before committing.
4. Commit and Push It
Record the staged change in your local repository:
git commit -m "docs: clarify the purpose of the welcome chapter"
Run git status. The working tree should be clean, but the commit still exists only in your local repository. Push the branch to the remote:
git push -u origin docs/comment-welcome-purpose
5. Open a Pull Request
On GitHub, open a pull request from docs/comment-welcome-purpose into main. Explain that the comment helps future authors keep setup instructions in the setup section, and mention that you verified the rendered welcome page is unchanged.
Before submitting it to the real project, ask whether maintainers want exercise contributions. If not, stop after pushing—or keep the exercise entirely local. For a real contribution, use the same workflow with a documentation clarification the project actually needs.
If review leads to another edit, make it on the same branch, inspect it, commit it, and push again. The pull request updates automatically.
Check Your Mental Model
At the end of the exercise, you should be able to identify when the comment existed only in the working directory, when it was staged, when it became a local commit, and when it reached the remote repository.
When You Are Unsure
Before trying a recovery command, pause and locate your work in the mental model:
- Which branch are you on?
- Are the changes only in the working directory?
- Are they staged for a commit?
- Have they been committed locally?
- Have those commits been pushed to a remote?
- Is someone else already using the same branch?
Start with read-only commands such as git status, git diff, git diff --staged, and git log --oneline. Read the output before acting. If a command might discard changes or rewrite shared history, ask for help and preserve the current state until you understand the consequences.
Git becomes easier when you stop treating its commands as a recipe and start asking where each version of your work currently lives. The working directory, staging area, local repository, and remote repository give you a map for answering that question.