Introduction to Git
Git is a distributed version control system used to track changes to files and coordinate work across repositories. Unlike systems in which a client retrieves only the latest version of a project, Git clones the entire repository, including its complete history. As a result, every clone effectively serves as a full backup of the project data.
This article introduces Git’s core ideas and demonstrates a practical workflow covering repository creation, staging and committing files, viewing history, working with GitHub, cloning and synchronizing repositories, branching, merging, conflict resolution, resetting commits, and using .gitignore.
1. How Git Stores Project History
Traditional version control systems such as CVS, Subversion, and Perforce commonly use a delta-based model. They begin with a complete version of a file and then record a sequence of differences, or deltas, describing how that file changes over time.
Git takes a different approach.
Git treats project history as a stream of snapshots. Each commit represents a snapshot of the project at that moment. When a file has not changed since the previous commit, Git does not need to store another identical copy; instead, it references the previous identical object.
This snapshot-oriented design is one of the central ideas behind Git.
2. Important Characteristics of Git
Many Git operations are performed locally, which means developers can inspect history, compare versions, create branches, and make commits without continuously communicating with a remote server.
Git also emphasizes data integrity. Everything stored by Git is checksummed before being saved and is subsequently referenced using that checksum. The slides describe Git hashes as 40-character hexadecimal SHA-1 values calculated from file or directory contents.
An example hash looks like this:
24b9da6552252987aa493b52f8696cd6d3b00373
Hashes allow Git to uniquely refer to stored objects and commits.
3. Git’s Three States
A file in Git typically moves through three important states:
- Modified: The file has been changed, but those changes have not yet been committed.
- Staged: The current version of the modified file has been selected for inclusion in the next commit.
- Committed: The data has been safely stored in the local Git database.
These states correspond to three major parts of a Git project:
- Working tree — where files are edited.
- Staging area — where changes are prepared for the next commit.
- Git directory (
.git) — where Git stores repository information and history.
Conceptually, the workflow is:
Working Tree
|
| git add
v
Staging Area
|
| git commit
v
Git Repository
The diagram on page 8 of the slides illustrates this movement between the working directory, staging area, and .git repository.
4. Installing and Configuring Git
Git can be downloaded from the official Git website. After installation, verify that Git is available with:
git --version
Git also provides built-in manual pages. For example:
git help init
Press q to exit the manual viewer.
Global Configuration
Git allows global settings that apply to repositories on your computer unless a particular repository overrides them.
Set your name:
git config --global user.name "Your Name"
Set your email:
git config --global user.email "your@email.com"
Set the default initial branch:
git config --global init.defaultBranch main
The name and email become part of commit metadata.
To inspect your global configuration:
git config --global --list
5. Creating a Git Repository
Create a project directory and move into it:
mkdir project1
cd project1
Before Git initialization, running:
git status
produces an error because the directory is not yet a Git repository.
Initialize the repository:
git init
Now:
git status
reports that you are on the initial branch, that there are no commits yet, and that the working tree contains nothing to commit.
The .git Directory
Running git init creates a hidden .git directory.
This folder contains Git’s internal repository data, including information such as:
- commit history,
- branches,
- configuration,
- the staging index.
On Windows, hidden files can be shown through File Explorer. On macOS, hidden files can be toggled using:
Command + Shift + .
The .git directory is what turns an ordinary folder into a Git repository.
6. Tracking a File
Create a file such as README.md.
On macOS:
touch README.md
On Windows PowerShell:
New-Item README.md
Check the repository:
git status
Git initially lists README.md as an untracked file.
Stage the File
Add the file to the staging area:
git add .
Then:
git status
shows README.md under Changes to be committed.
Commit the File
Create the first commit:
git commit -m "updated README.md"
Afterward:
git status
should report:
nothing to commit, working tree clean
A commit records the staged snapshot in the local Git repository.
7. Modifying an Existing File
Suppose README.md is changed to contain content such as:
# Project 1
* This is a sample Project added from Project 1
After editing, run:
git status
Git now reports:
Changes not staged for commit:
modified: README.md
The file is tracked, but its latest changes have not yet entered the staging area.
To stage and commit explicitly:
git add README.md
git commit -m "Update README"
For already tracked files, Git also supports:
git commit -a -m "Update README"
The slides contrast these two approaches.
8. Viewing Changes with git diff
Before committing a modification, inspect the difference between the working copy and the previously recorded version:
git diff README.md
A Git diff may contain lines such as:
--- a/README.md
+++ b/README.md
-# Title
+# Project 1
The notation means:
--- a/README.mdrefers to the old version.+++ b/README.mdrefers to the new version.- lines beginning with
-were removed. - lines beginning with
+were added.
Git may also show a hunk header such as:
@@ -1 +1,4 @@
This can be interpreted as:
@@ -oldStart,oldCount +newStart,newCount @@
In the example, the old content begins on line 1 with one line, while the new content begins on line 1 with four lines.
Once satisfied with the changes:
git add .
git commit -m "updated README.md"
9. Viewing Commit History
Use:
git log
to display detailed commit history, including commit hashes, authors, timestamps, and messages.
For a shorter history:
git log --oneline
Example:
f6a3cb2 updated README.md
689c559 updated README.md
The shortened hash at the beginning of each line can often be used to reference a commit.
Viewing a Specific Commit
A commit can be inspected using part of its hash:
git show f6a3cb2
You can also refer to commits relative to HEAD:
git show HEAD
git show HEAD~1
HEAD represents the currently checked-out commit, while HEAD~1 refers to its parent.
10. Connecting a Local Repository to GitHub
A local Git repository can be linked to a remote repository hosted on GitHub.
After creating a GitHub repository, add it as a remote:
git remote add origin https://github.com/naneja/project1.git
Here:
- the URL identifies the remote GitHub repository;
originis the conventional nickname for that remote.
Rename the Branch
If necessary, rename the current branch to main:
git branch -M main
The -M option performs the rename forcefully if required.
Push the Repository
Push the local branch:
git push -u origin main
This uploads the local main branch to the remote named origin.
The -u, or --set-upstream, option tells Git to remember that local main tracks origin/main. After this initial setup, later synchronization can usually use the shorter commands:
git push
or:
git pull
The slides also demonstrate GitHub’s personal access token workflow and the process of creating a private repository on GitHub on pages 33–38.
11. Cloning a Repository
A remote repository can be copied locally with:
git clone https://github.com/naneja/project1 project2
Then:
cd project2
git remote -v
shows the configured remote for both fetching and pushing.
Because Git is distributed, cloning does more than download the current files. The clone contains the repository’s history and branches.
Two separate working directories can therefore point to the same GitHub repository. In the slides, both project1 and project2 are linked to the same naneja/project1 remote repository.
12. Synchronizing Multiple Local Copies
Suppose a new file is created in project1:
touch hello.cpp
git add .
git commit -m "Added hello.cpp"
The local history might then show:
git log --oneline
c4f321a (HEAD -> main) Added hello.cpp
f6a3cb2 (origin/main) updated README.md
689c559 updated README.md
At this point, the new commit exists locally but has not necessarily reached GitHub.
Push it:
git push
Now GitHub contains the update.
However, another clone such as project2 will not automatically receive the change. Before synchronization, it may still contain only README.md.
Update it with:
git pull
The new hello.cpp file then becomes available locally.
This demonstrates a common Git collaboration cycle:
Local repository A
|
push
v
Remote repository
|
pull
v
Local repository B
13. Branching
Branches allow different lines of development to exist independently.
List branches:
git branch
The active branch is marked with *.
Create a Branch
git branch br1
List branches again:
git branch
You might see:
br1
* main
Switch Branches
Use:
git switch br1
or the older equivalent:
git checkout br1
Create and Switch in One Command
A new branch can be created and checked out immediately:
git switch -c br2
or:
git checkout -b br2
This combines branch creation and branch switching.
14. Files and Branch Independence
Suppose a file is created while on br2:
git switch br2
touch hello_b2.cpp
git add .
git commit -m "hello_br2 added"
If you switch back to main:
git checkout main
the committed hello_b2.cpp file does not appear on main.
A change committed only on one branch remains isolated from other branches until the branches are merged. The slides also note that uncommitted changes may sometimes remain visible when switching branches.
15. Merging Branches
To integrate br2 into main:
git switch main
git merge br2 -m "merged br2"
Once merged, the changes from br2 become part of main.
If the branch is no longer needed:
git branch -D br2
16. Working with Multiple Branches
Git branches can themselves have child branches.
The slides demonstrate a structure in which:
m1branches frommain,m11branches fromm1,m111andm112branch fromm11,m2branches frommain,m21branches fromm2,m3branches frommain.
For example:
git checkout -b m1
touch hello_m1.cpp
git add .
git commit -m "Added hello_m1.cpp"
A child branch can then be created:
git checkout -b m11
touch hello_m11.cpp
git add .
git commit -m "Added hello_m11.cpp"
To visualize the entire branch structure:
git log --oneline --graph --all
The diagram and terminal output on page 73 show how Git renders several branches as a text-based commit graph.
17. Merge Conflicts
Git can often merge branches automatically. A conflict occurs when incompatible changes affect the same part of a file.
The slides demonstrate this using hello.cpp.
On main:
git switch main
Add:
int main(){}
Then commit:
git add .
git commit -m "added main function"
On br1, modify the same file differently:
git switch br1
Add:
int hello(){}
Then:
git add .
git commit -m "added hello function"
Now attempt the merge:
git switch main
git merge br1
Git may report:
Auto-merging hello.cpp
CONFLICT (content): Merge conflict in hello.cpp
Automatic merge failed; fix conflicts and then commit the result.
Resolving the Conflict
Open the conflicted file, inspect the changes from both branches, and manually decide what the final file should contain.
After correcting it:
git add .
git commit -m "updated hello.cpp"
git push
The important point is that Git identifies the conflict, but the developer determines the correct final content.
18. Undoing the Last Commit with a Hard Reset
To move the current branch back one commit and discard the current changes:
git reset --hard HEAD~1
The slides describe this as a hard reset to the previous commit, with all changes discarded.
Because --hard modifies both repository state and working files, it should be used carefully.
19. Ignoring Files with .gitignore
Not every file in a project should be tracked. Build outputs, operating-system metadata, generated files, and other temporary files can be excluded using .gitignore.
Examples from the slides include:
*.out
Ignore all .out files.
!a.out
Track a.out even though .out files are otherwise ignored.
/TODO
Ignore only the TODO file in the current directory.
build/
Ignore files in directories named build.
doc/*.txt
Ignore .txt files directly inside doc, but not necessarily those in deeper subdirectories.
doc/**/*.pdf
Ignore PDF files inside doc and its subdirectories.
.DS_Store
Ignore macOS .DS_Store metadata files.
20. A Typical Git Workflow
The concepts in the slides can be combined into a standard day-to-day workflow.
First, create or obtain a repository:
git init
or:
git clone <repository-url>
Edit files and inspect the repository:
git status
git diff
Stage selected work:
git add .
Commit it:
git commit -m "Describe the change"
Inspect history:
git log --oneline
Synchronize with a remote:
git pull
git push
Create a feature branch:
git switch -c feature
After development, merge it:
git switch main
git merge feature
This workflow illustrates Git’s central model: developers make changes locally, deliberately stage snapshots, commit them into repository history, organize parallel development through branches, and synchronize repositories through remote services such as GitHub.
Conclusion
Git combines local version control, complete repository history, snapshot-based storage, branching, merging, and remote synchronization into a powerful development workflow.
The most important concepts to remember are:
- a Git clone contains the repository and its history;
- files move through modified, staged, and committed states;
git addprepares content for a commit;git commitrecords a snapshot locally;git logandgit showinspect history;git pushsends local commits to a remote repository;git pullretrieves remote updates;- branches isolate lines of development;
git mergecombines them;- merge conflicts require manual resolution;
.gitignoreprevents unwanted files from being tracked.
Once these ideas become familiar, Git becomes less about memorizing commands and more about understanding how snapshots of a project move through local history, branches, and shared repositories.