Start a repository
Make a folder, go into it, and turn it into a repository.
mkdir attendance-app
cd attendance-app
git init
Git prints something like Initialized empty Git repository in /home/ravi/attendance-app/.git/.
That hidden .git folder is the entire repository: every commit, every branch, all of the history. Delete it and you delete the history while keeping your current files. Never edit anything inside it by hand.
Your first commit
echo "# Attendance App" > README.md
git status
Git says README.md is untracked, meaning it has never been committed.
git add README.md
git status
Now it is staged, shown under "Changes to be committed".
git commit -m "Add README with project name"
Git replies with the branch, a short hash like a1b2c3d, and how many lines changed. You have a commit.
What a commit really is
A commit is not a diff. A commit is a complete snapshot of every tracked file at that moment, plus:
- a message you wrote
- the author name and email
- a timestamp
- a link to the previous commit, called the parent
- a 40-character SHA-1 hash that identifies it
Commits form a chain. Each one points back to the one before it. That chain is your history, and it is why Git can rebuild any past state exactly.
Git does not waste space storing unchanged files again. Internally it stores each file's content once and reuses it. But the mental model that matters is: a commit is a full snapshot, not a patch.
Add two more commits
echo "console.log('attendance app');" > app.js
git add app.js
git commit -m "Add empty app entry point"
echo "students = []" >> app.js
git add app.js
git commit -m "Add students array"
Read the history
git log
git log --oneline
git log --oneline --graph --all
--oneline gives one short line per commit. Learn that one; you will use it constantly.
See exactly what a commit changed:
git show a1b2c3d
See what you changed but have not staged yet:
git diff
See what is staged and about to be committed:
git diff --staged
Read git diff --staged before every commit. It takes five seconds and catches the debug console.log you meant to delete.
Writing a commit message
A bad history is useless. Compare:
update
fix
asdf
final changes
with:
Add roll number validation to signup form
Fix crash when attendance list is empty
Remove hardcoded database password
Rules that work:
- Write what the commit does, in the present tense.
- Under 60 characters for the first line.
- One logical change per commit. If your message needs the word "and"
twice, it should probably be two commits.
Your commit history is read by teammates, by evaluators looking at your GitHub, and by you at 2am the night before submission.
Undoing things
git restore app.js
Throws away unstaged changes to that file. Permanent. Be sure.
git restore --staged app.js
Unstages a file but keeps your edits.
git commit --amend -m "A better message"
Rewrites the most recent commit. Fine before you push. Do not do it after pushing to a shared branch; it changes the commit hash and confuses everyone else.
git add . stages everything in the folder, including things you did not mean to add: node_modules, a 2GB dataset, a .env file with passwords. Always run git status first and actually read the list. A password committed once stays in the history even after you delete the file in a later commit.
When it says nothing to commit
nothing to commit, working tree clean
That is not an error. It means every change is already committed. Beginners see the word "nothing" and panic. Run git log --oneline and see your commits sitting there.
Commit small and commit often. Ten small commits are easier to review, and far easier to undo, than one giant commit at midnight called "project done". A good target while learning: commit whenever something works, even if it is small.
Next: branches, so you can try an idea without breaking what already works.