Tutorial: Git Tutorial for Beginners: Learn Git in 1 Hour
Prerequisites
- None explicitly stated, but implies basic computer literacy and comfort with command line interfaces.
What You'll Learn
- A good grasp of Git basics for beginners.
- Understanding fundamental Git concepts and essential commands used daily.
- Readiness to learn more about intermediate to advanced Git concepts.
- Ability to track project history and collaborate effectively with others.
- Confidence in using the command line for Git operations.
In this tutorial, you will gain a strong foundation in Git, the most widely used version control system. This article will guide you through understanding fundamental Git concepts and essential commands used daily. By following the steps outlined, you will learn how to track project history, collaborate effectively with others, and confidently use the command line for Git operations.
Table of Contents
Step 1: Introduction to Git
Git is the most popular distributed version control system.
If you're an absolute beginner or have been using Git for a while but never truly understood its mechanics, this tutorial is designed for you. You will grasp all fundamental concepts and essential commands used daily. By the end, you'll have a solid understanding of the basics and be prepared for intermediate to advanced topics.
Understanding Git and Its Popularity
Git stands as the world's most popular version control system (VCS). A VCS tracks changes made to code over time within a special database called a repository. This allows you to:
- Review your project's history, identifying who made what changes, when, and why.
- Easily revert your project to an earlier state if mistakes occur.
Without a VCS, managing code changes would involve constantly creating copies of the entire project in various folders, a method that is slow and doesn't scale, especially when multiple individuals are working on the same project. This would lead to continuously emailing the latest code and manually merging changes. In essence, a VCS enables project history tracking and collaborative work.
Centralized vs. Distributed Version Control Systems
Version control systems are categorized into two main types:
- Centralized Systems: In a centralized system, all team members connect to a central server to retrieve the latest code and share their changes. Examples include Subversion and Microsoft Team Foundation Server. A key drawback of this architecture is the single point of failure; if the central server goes offline, collaboration ceases, and project snapshots cannot be saved until the server is back online.
- Distributed Systems: Distributed systems overcome the limitations of centralized systems. Every team member possesses a full copy of the project history on their local machine. This allows you to save project snapshots locally, and if the central server is unavailable, team members can synchronize their work directly with each other. Git and Mercurial are examples of distributed version control systems.
Git is the most popular distributed VCS globally due to several factors:
- Free and Open-Source: It is available at no cost and its source code is publicly accessible.
- Speed and Scalability: Operations like branching and merging, which can be slow and challenging in other VCS like Subversion or TFS, are exceptionally fast and efficient in Git.
Git's widespread adoption is evident, with over 90% of software projects worldwide utilizing it. Consequently, almost every software developer job description lists Git as a required skill. Therefore, having an in-depth understanding of Git—how it works and how to use it for tracking project history and collaborating effectively—is a must-have for any aspiring software developer.
Ways to Use Git
You can interact with Git in several ways:
-
Command Line:
- Open a terminal or command prompt window to execute Git commands.
- This is often the fastest and easiest way to perform tasks, which is why many developers prefer it.
-
Code Editors and IDEs (Integrated Development Environments):
- Most modern code editors and IDEs come with built-in support for basic Git features. For instance, Visual Studio Code (VS Code) includes a Source Control panel providing essential Git functionalities.
- Extensions are also available to enhance Git features within these environments. GitLens is a popular VS Code extension that adds many Git features.
-
Graphical User Interfaces (GUIs):
- There are dedicated GUI tools specifically designed for Git. The Git website (git-scm.com) lists a comprehensive collection of these tools for various platforms (Windows, Mac, Linux, Android, iOS).
- Among these, GitKraken and SourceTree are two of the most popular:
- GitKraken: This is a preferred GUI tool, known for its beautiful design and cross-platform compatibility. It integrates with other GitKraken products like GitKraken Boards for issue tracking and GitKraken Timelines for project management. It is free for open-source projects but requires an annual fee for commercial use.
- SourceTree: This tool is completely free but is only available for Windows and Mac. Linux users would need to opt for GitKraken or another GUI tool.
In this course, the primary focus will be on using Git via the command line for two main reasons:
- GUI Limitations: Most GUI tools have limitations, supporting only the most frequently used Git commands. There will be instances where you'll need to resort to the command line to complete a task, even if you primarily use a GUI.
- Command Line Availability: The command line is always accessible. In situations where a GUI tool might not be available (e.g., connecting to a remote server without installation permissions), knowing the command line is crucial to avoid being stuck.
In practice, many developers, including myself, use both the command line and a GUI tool. This course will demonstrate both approaches. There are scenarios where a GUI tool is more intuitive and efficient, while other times, the command line is quicker and simpler. The goal is to use the right tool for the job. Avoid the pitfall of developers who exclusively use the command line and dismiss GUI users; choose the method that best suits the task.
While the command line will be central to this course, examples using VS Code and GitKraken will be provided when a GUI tool is beneficial, as they are widely popular. If you are new to the command line, don't worry; this guide will walk you through everything step-by-step. It's often much easier than it seems.
Installing Git
Before proceeding, let's verify if Git is installed on your machine and determine its version.
-
Open your terminal or command prompt:
- Mac: Press
Command + Spaceand typeterminal. - Windows: Click the search icon in the bottom navigation bar and type
cmd. Your terminal window's appearance may vary, but its function for executing Git commands remains the same.
- Mac: Press
-
Check Git version:
- In the terminal, type
git --version. - For example, a machine might show Git version
2.19.2, but the latest version at the time of recording this video is2.27.0. It is highly recommended to download and install the latest version.
- In the terminal, type
-
Download and Install Git:
- Go to
git-scm.com/download. - You will find instructions for installing Git on various operating systems. The process is straightforward.
- Windows Users: After installation, you will get an application called Git Bash (short for Bourne Again Shell). This is a command prompt window that emulates Unix/Linux environments. Throughout this course, it is recommended to use Git Bash instead of the built-in Windows Command Prompt for a more consistent experience with the examples provided.
- Go to
Customizing Your Git Environment
The first time you use Git, you must specify a few configuration settings: your name, email, default editor, and how Git should handle line endings. These settings can be configured at three levels:
- System Level: Settings here apply to all users on the current computer.
- Global Level: Settings here apply to all repositories for the current user. This is the most common level for personal configurations.
- Local Level: Settings here apply only to the current repository or the repository in the current folder. This allows for specific configurations per project.
Configure Global Settings:
-
Set your name:
git config --global user.name "Your Name"- Use double quotes around your name if it contains spaces.
-
Set your email:
git config --global user.email your.email@example.com- Double quotes are not needed for email addresses without spaces.
-
Set your default editor:
- On Mac, Git defaults to
vim, which can be challenging for beginners. This course uses Visual Studio Code (VS Code). - If you don't have VS Code, download the latest version from
code.visualstudio.com. Ensure VS Code is added to your system's PATH so you can open it directly from the terminal by typingcode. (Troubleshoot PATH issues based on your operating system ifcodecommand doesn't work.) - To set VS Code as your default editor:
git config --global core.editor "code --wait""code --wait": This command launches VS Code and the--waitflag tells the terminal to wait until the VS Code instance is closed before regaining control.
- On Mac, Git defaults to
-
Edit Global Configuration File (Optional - for verification):
- All these settings are stored in a text file. You can open and edit this file using your default editor:
git config --global -e - This will open your
~/.gitconfigfile (orC:\Users\YourUser\.gitconfigon Windows). You will see sections for[user]and[core]containing your configured name, email, and editor. - The terminal will wait for you to close VS Code.
- All these settings are stored in a text file. You can open and edit this file using your default editor:
-
Configure Line Endings (
core.autocrlf):- This is a crucial setting that many users overlook.
- Background: On Windows, end-of-lines (EOL) are marked with two special characters: carriage return (
\r) and line feed (\n) (CRLF). On Mac and Linux, EOLs are indicated by only a line feed (\n) (LF). Inconsistent EOL handling can lead to unexpected issues. - Scenario: Consider John (Windows) and Julie (Mac) collaborating on the same repository.
- John (Windows): When John commits code, Git removes the carriage return (
\r) character from the EOLs. When he checks out code, Git adds the carriage return character back. To achieve this, setcore.autocrlftotrue. - Julie (Mac/Linux): When Julie checks out code, she doesn't want the carriage return. Git should not add it. However, if a carriage return is accidentally introduced (e.g., by her editor), Git should remove it when storing code in the repository. To achieve this, set
core.autocrlftoinput.
- John (Windows): When John commits code, Git removes the carriage return (
- Command to set
core.autocrlf:- On Windows:
git config --global core.autocrlf true - On Mac or Linux:
git config --global core.autocrlf input
- On Windows:
Getting Help with Git Commands
You can get help for Git commands in several ways:
-
Online Documentation:
- Simply Google "git [command name]" (e.g., "git config") to find comprehensive online documentation with various options and their usage.
-
Terminal Help (Man Pages):
- For detailed help directly in your terminal, type
git [command name] --help(e.g.,git config --help). - This displays the full manual page for the command.
- Press
Spaceto navigate to the next page andqto quit.
- For detailed help directly in your terminal, type
-
Terminal Help (Short Summary):
- For a quick refresher or a short summary of a command's options, type
git [command name] -h(e.g.,git config -h).
- For a quick refresher or a short summary of a command's options, type
Project Snapshots and Basic Git Workflow
The first crucial skill in using Git effectively is taking snapshots of your project. This section will cover fundamental Git concepts that are often misunderstood. Even if you think you know the basics, pay close attention, as many people use Git commands without fully understanding their underlying mechanisms, leading to frequent confusion.
Creating a Project Directory and Initializing a Repository:
-
Create a directory for your project:
- You can name this directory anything and place it anywhere on your machine. For this example, if you are in a
projectsdirectory, create a new directory namedmoon:
mkdir moon cd moon - Imagine this
moondirectory as your project, potentially containing tens or hundreds of files.
- You can name this directory anything and place it anywhere on your machine. For this example, if you are in a
-
Initialize a new empty Git repository:
- Inside your project directory, run:
git init - You will see a message like
Initialized empty Git repository in /path/to/your/project/moon/.git/. This indicates that Git has created a hidden subdirectory named.gitinside yourmoondirectory. - Note: The
.gitsubdirectory is hidden by default because you are not supposed to touch its contents directly. - To see hidden files and directories:
- Run
ls -a(short for "all"). This will show the.gitsubdirectory. On Mac, you can view it in Finder, and on Windows, in File Explorer.
- Run
- Inside
.git: This directory (or Git repository) is where Git stores information about your project's history. It contains subdirectories likebranches,hooks,info,objects, andreferences. As a Git user, you don't need to understand this internal structure; it's an implementation detail and should not be modified. Corrupting or removing this directory will result in the loss of your project history.
- Inside your project directory, run:
-
Demonstrating Consequences of Deleting
.git:- Notice the green
gitmarker in your terminal prompt (if you have Zsh on Mac or Posh-Git on Windows for a colorful terminal). This indicates you are within a Git repository. - If you remove the
.gitsubdirectory:
rm -rf .git - The
gitmarker will disappear, indicating that the directory is no longer a Git repository, and your project history for that directory is lost. - To re-initialize:
git init - The
gitmarker will reappear.
- Notice the green
Basic Git Workflow
Now that you have a Git repository, let's explore the basic workflow you'll follow daily:
- Modify Files: As you work, you will modify one or more files in your project directory.
- Commit Changes: When your project reaches a significant state that you want to record, you will "commit" those changes into your repository. A commit is equivalent to taking a snapshot of your project at that specific moment.
- The Staging Area (or Index): Git introduces a special intermediate step called the staging area (or index), which is unique compared to most other version control systems. It represents what you are proposing for your next commit or snapshot.
- Once you finish making changes, you
addthe modified files to the staging area. - You then review these staged changes.
- If everything looks correct, you perform a
commit. The proposed snapshot is then permanently stored in your repository. - The staging area is crucial as it allows you to carefully review your work before permanently recording a snapshot. If some changes should not be part of the next snapshot, you can "unstage" them and commit them later as part of a different snapshot.
- Once you finish making changes, you
Example Walkthrough of the Basic Git Workflow:
- Initial State: Your project directory is empty.
- Add Files to Working Directory: Create
file1.txtandfile2.txt.- Initially, these files are untracked by Git.
- Add Files to Staging Area: Use the
git addcommand to move these files to the staging area. Now, these files are "staged," representing the state proposed for the next commit. - Commit Changes: Use the
git commitcommand to permanently store this snapshot in the repository. Provide a meaningful commit message explaining what this snapshot represents. This is vital for maintaining a useful project history. Each commit will clearly explain the project's state at that time.- At this point, you have one commit in your repository.
- Common Misconception: Many beginners believe the staging area becomes empty after a commit. This is incorrect. The staging area now contains the same snapshot that was just stored in the repository. It acts much like a staging environment in software releases, reflecting either the current production version or the next version destined for production.
- Modify Existing File: Suppose you fix a bug and modify
file1.txt.- The staging area still holds the old version of
file1.txtbecause the new changes haven't been staged yet.
- The staging area still holds the old version of
- Stage Modified File: Use
git addagain to stage the changes infile1.txt. Now, the staging area contains the updated content offile1.txtfrom your working directory. - Commit Changes: Commit these new changes with a message describing the bug fix.
- Now you have two commits in your repository.
- Delete File: You decide
file2.txtis no longer needed and delete it from your working directory.- However,
file2.txtstill exists in the staging area (as per the last commit).
- However,
- Stage Deletion: Use
git addto stage this deletion. Git intelligently recognizes thatfile2.txtwas deleted and will remove it from the staging area. - Commit Deletion: Commit this change to permanently record the deletion.
- You now have three commits in your repository.
Understanding Commits:
Each commit in Git has:
- A unique identifier (a 40-character hexadecimal string) generated by Git, akin to a revision number.
- Information about:
- Who made the changes (author).
- When the changes were made (date and time).
- A complete snapshot of your project's state at the time of creation.
Unlike many other VCS that only store deltas (what changed), Git stores the full content of your project with each snapshot. This allows for quick restoration to any earlier state without computing changes. Although storing full content might seem inefficient, Git is highly efficient in data storage, compressing file contents and avoiding duplicate content. As a Git user, you don't need to know the specifics of how Git stores data, as it's an implementation detail that might change. What's essential is knowing that each commit provides a complete project snapshot for easy restoration to previous states.
This basic workflow will be demonstrated in action over the next few lessons.
Adding Files to Your Project
Let's begin by adding a couple of files to our project directory. We will use the echo command, which is a standard Unix/Linux command for writing content to a file, not a Git command. This course primarily uses text files to ensure the workflow is applicable to any programming language.
-
Create
file1.txt:echo hello > file1.txt- The
>symbol writes "hello" tofile1.txt.
- The
-
Create
file2.txt:echo world > file2.txt- Now you have
file1.txtandfile2.txtin your project directory.
- Now you have
Checking Status (git status)
When you have new files in a Git-initialized directory, Git doesn't automatically track them. You need to explicitly instruct Git to track them.
- Check the status of your working directory and staging area:
git status- Initially, you will see
Untracked files:listed in red, showingfile1.txtandfile2.txt. This indicates they are not yet in the staging area.
- Initially, you will see
Adding Files to the Staging Area (git add)
To move file1.txt and file2.txt to the staging area, use the git add command.
-
Ways to add files to the staging area:
- Single file:
git add file1.txt - Multiple files:
git add file1.txt file2.txt(separate by space) - Patterns:
git add *.txt(adds all files with.txtextension) - Recursively add entire directory:
git add .(adds all files and directories recursively from the current directory)- Caution: Be careful with
git add .as it adds everything. You generally don't want to add large binary files or log files, as they increase repository size and are not meant for sharing across the team. (Ignoring files will be covered later.)
- Caution: Be careful with
- Single file:
-
Add
file1.txtandfile2.txt:git add .- After executing this, your terminal prompt's indicator might change (e.g., to yellow), signifying that there are changes in the staging area ready to be committed.
-
Check status again:
git status- You will now see
new file:listed in green for bothfile1.txtandfile2.txt, indicating they are in the staging area.
- You will now see
Modifying and Re-staging Files
What happens if you modify a file after adding it to the staging area? Git captures a snapshot when git add is run. If you change the file again, a new snapshot needs to be taken.
-
Modify
file1.txtby appending text:echo world >> file1.txt- Using
>>appends "world" tofile1.txt.
- Using
-
Check status:
git status- You will see both
file1.txt(greennew file:due to the earliergit add) andfile1.txt(redmodified:) listed. This means the staging area holds the first version offile1.txt, while your working directory has the second version with unstaged changes.
- You will see both
-
Re-stage the modified
file1.txt:git add file1.txtor
git add . -
Check status again:
git status- Both files should now be listed in green under
Changes to be committed:, and there should be no unstaged changes.
- Both files should now be listed in green under
Committing Changes (git commit)
Now, with a snapshot in the staging area, you are ready to permanently store it in your Git repository.
-
Commit with a short message:
git commit -m "Initial commit"-m(for message) allows you to provide a short, single-line description in double quotes.
-
Commit with a multi-line message (for detailed explanations):
- If a short message is insufficient for context (e.g., explaining bug fixes or constraints), omit the
-mflag:
git commit - This will open your default editor (VS Code, as configured earlier).
- In the editor, the first line is for a short description (ideally less than 80 characters).
- Add a line break, then type a longer description for more details.
- Lines starting with
#are comments and will be ignored. - Example message:
Initial commit This is our first commit. - Save the file and close the editor.
- Output: Git will report statistics about the commit, such as the number of files changed and insertions/deletions. For instance,
2 files changed, 3 insertions...indicatesfile1.txt(now "hello\nworld") andfile2.txt("world") contributed to 3 total lines inserted across the two files. - Your working directory will now be "clean" (e.g., terminal indicator turns green), meaning its content matches the staging area, which in turn matches the latest commit.
- If a short message is insufficient for context (e.g., explaining bug fixes or constraints), omit the
Best Practices for Committing Code
Adhering to these practices will result in a clean, useful project history:
-
Commit Size:
- Not too small: Avoid committing every single file update (e.g., "update file1," "update file2"). Such commits are useless.
- Not too big: Don't wait to implement an entire feature end-to-end before committing. The purpose of committing is to create checkpoints. If you make a mistake, you can easily revert.
- Commit Often: Strive to commit frequently. In a real-world scenario, you might commit 5 to 10 times a day or more, depending on your work. This is a guideline, not a strict rule. Commit when your code reaches a stable, recordable state.
-
Logical Change Sets:
- Each commit should represent a single, logically separate change set.
- Do not mix concerns: For example, if you fix a bug and then notice a typo, do not commit both in one go. Create two separate commits: one for the typo and one for the bug fix. (If you accidentally stage both, you can unstage them, which will be shown later).
-
Meaningful Commit Messages:
- Develop the habit of writing meaningful commit messages. These messages appear in your project's history and are crucial for you and your team members.
- If your commit represents a single unit of work (as advised above), it will be easier to craft a good message.
- Wording: Most developers prefer using the present tense for commit messages (e.g., "Fix the bug" instead of "Fixed the bug"). While this is a convention, consistency within your team is more important than strict adherence.
Skipping the Staging Area
While the staging area is generally recommended for reviewing changes, you can skip it if you are 100% confident that your changes don't need review.
- Modify
file1.txtand commit in one step:- Append "test" to
file1.txt:
echo test >> file1.txt - Your working directory will show changes (e.g., yellow indicator).
- Commit all modified files directly:
git commit -a -m "Fix the bug that prevented the users from signing up"-a(or--all) automatically stages all modified files before committing. Note that-adoes not stage newly created files; they must still be added withgit add.
- Output: Git confirms the commit, showing
1 file changed, 1 insertion.... - Caution: Use this only when you are certain. In 99% of cases, you should stage your code before committing.
- Append "test" to
Removing Files (git rm)
To remove a file from your project, you must remove it from both your working directory and the staging area.
-
Initial Method (Standard
rmcommand):- If you delete
file2.txtusing the standard Unixrmcommand:
rm file2.txt - Check status:
git statuswill showdeleted: file2.txtin red underChanges not staged for commit:. - Verify staging area: Running
git ls-files(lists files in the staging area) will showfile2.txtis still there. - Stage the deletion: You would then need to stage this change:
git add file2.txt git ls-fileswould now confirmfile2.txtis gone from the staging area.- Commit the deletion:
git commit -m "Remove unused code"
- If you delete
-
Recommended Method (Git's
git rmcommand):- Git provides a command that performs both the deletion from the working directory and the staging of that deletion in one step.
- Remove
file2.txtdirectly usinggit rm:
git rm file2.txt - This command removes the file from both the working directory and the staging area instantly.
- You can also specify multiple files or patterns (e.g.,
git rm *.txt).
Renaming and Moving Files (git mv)
Renaming or moving files in Git is conceptually a two-step operation: a deletion of the old file and an addition of a new file. Git provides a specialized command to simplify this.
-
Initial Method (Standard
mvcommand):- Suppose
file1.txtis the only file. Rename it tomain.jsusing the standard Unixmvcommand:
mv file1.txt main.js - Check status:
git statuswill showdeleted: file1.txtanduntracked files: main.js(both in red), because standardmvdoesn't inform Git about the logical rename. - Stage changes: You would then need to stage both the deletion and the addition:
git add file1.txt # Stages the deletion of file1.txt git add main.js # Stages the addition of main.js - Check status again:
git statuswould now recognize the rename:renamed: file1.txt -> main.js(in green, indicating staged).
- Suppose
-
Recommended Method (Git's
git mvcommand):- Git provides a command that handles the rename/move operation for both the working directory and the staging area automatically.
- Rename
main.jstofile1.jsdirectly usinggit mv:
git mv main.js file1.js - Check status:
git statuswill instantly showrenamed: main.js -> file1.js(in green, meaning staged). - Commit the rename:
git commit -m "Refactor code"- Statistics: A rename will result in
1 file changed, 0 insertions, 0 deletionsif only the name changed, demonstrating Git's efficiency in tracking.
- Statistics: A rename will result in
Ignoring Files and Directories (.gitignore)
In almost every project, you will need to tell Git to ignore certain files or directories, such as log files, temporary files, or compiled binaries, which are generated artifacts and don't need to be version-controlled or shared. Adding them would unnecessarily bloat your repository.
-
Create a log directory and file:
mkdir logs echo hello > logs/dev.log -
Check status:
git status- Git will report
Untracked files: logs/withdev.loginside. We don't want to add this to the staging area.
- Git will report
-
Create a
.gitignorefile:- To prevent Git from tracking the
logsdirectory, create a special file named.gitignorein the root of your project. This file has no name, only an extension.
echo logs/ > .gitignore- Open
.gitignore(optional): You can open this file in your editor (e.g.,code .gitignore). - Inside
.gitignore,logs/means ignore thelogsdirectory. You can add multiple entries, use patterns (e.g.,*.logto ignore all.logfiles), and comments (lines starting with#).
- To prevent Git from tracking the
-
Check status again:
git status- Git will no longer list
logs/as untracked. Instead, it will show.gitignoreitself as a new untracked file, as it is part of your project's configuration.
- Git will no longer list
-
Stage and commit
.gitignore:git add .gitignore git commit -m "Add .gitignore"
Important Note on .gitignore:
.gitignore only works for files or directories that Git is not already tracking. If you accidentally commit a file or directory, and later add it to .gitignore, Git will not ignore it. You must explicitly remove it from Git's tracking first.
Removing Accidentally Committed Files from Tracking:
Let's illustrate how to fix the issue where a file/directory was accidentally committed and is now being tracked despite being in .gitignore.
-
Create a
bindirectory and a binary file:mkdir bin echo hello > bin/app.bin -
Accidentally commit
bin:git add . git commit -m "Add bin"- Now, every time
app.binchanges (e.g., after a recompile), Git will report it as modified, which is undesirable.
- Now, every time
-
Add
bin/to.gitignore:echo bin/ >> .gitignore- Check status
git status: It will say.gitignoreis modified. - Commit
.gitignoreupdate:
git add . git commit -m "Include bin/ in .gitignore"
- Check status
-
Confirm the issue:
- Modify
app.bin:
echo hello world > bin/app.bin - Check status
git status: Git will still reportbin/app.binas modified. This is because Git is already tracking it.
- Modify
-
Remove from Staging Area (i.e., Git's tracking) using
git rm --cached:- We need to remove
bin/app.binfrom the staging area without deleting it from the working directory. Thegit rmcommand handles this with the--cachedoption. - View files in staging area:
git ls-fileswill showbin/app.bin. - Remove from staging area recursively:
git rm --cached -r bin/--cached: Removes only from the index (staging area).-r: Required for recursive removal of directories.
- Verify removal:
git ls-fileswill no longer listbin/app.bin. - Check status:
git statuswill now showdeleted: bin/app.bin(in green, indicating a staged deletion). This means the commit will record thatbin/app.binis no longer tracked.
- We need to remove
-
Commit the untracking:
git commit -m "Remove the bin directory that was accidentally committed"- From this point forward, Git will no longer track changes in the
bindirectory orapp.bin. - Test: If you modify
bin/app.binagain (e.g.,echo test > bin/app.bin),git statuswill show a clean working directory because Git is now ignoring it.
- From this point forward, Git will no longer track changes in the
.gitignore Templates:
You can find various .gitignore templates for different programming languages (e.g., Java, Python, Node.js) on GitHub directly (e.g., github.com/github/gitignore). These templates suggest common files to ignore (e.g., .class files in Java, node_modules in Node.js) that are typically generated during compilation or dependency installation. Lines starting with # are comments.
Displaying Status with git status --short (git status -s)
The default output of git status is comprehensive but often verbose. A shorter, more concise output is available using the --short or -s flag.
-
Modify an existing file and create a new one:
- Append
skytofile1.js:
echo sky >> file1.js - Create
file2.js:
echo sky > file2.js
- Append
-
Check full status (for comparison):
git status- This will show
modified: file1.js(red) andUntracked files:forfile2.js.
- This will show
-
Check short status:
git status --short- Alternatively,
git status -s. - Output interpretation:
- The output has two columns: the left column represents the staging area, and the right column represents the working directory.
M file1.js: TheMin the right column indicatesfile1.jsis modified in the working directory. There's no entry in the left column because these changes are not yet staged.?? file2.js: The??indicatesfile2.jsis a new untracked file, not in either the staging area or tracked by Git.
- Alternatively,
-
Add
file1.jsto staging and re-check short status:git add file1.js git status -s- Output:
M file1.js(greenMin left column) and?? file2.js.- The
Min the left column signifies thatfile1.jshas changes staged. The right column is now empty forfile1.jsbecause all its modifications are in the staging area.
- The
- Output:
-
Re-modify
file1.jsand re-check short status (demonstrating re-staging):- Append
oceantofile1.js:
echo ocean >> file1.js git status -s - Output:
MM file1.js.- The green
Min the left column indicates existing staged changes forfile1.js. - The red
Min the right column indicates further unstaged modifications in the working directory that need to be re-staged.
- The green
- Append
-
Re-stage
file1.jsagain:git add file1.js git status -s- Output:
M file1.js. All changes forfile1.jsare now in the staging area.
- Output:
-
Add
file2.jsto staging and re-check short status:git add file2.js git status -s- Output:
M file1.jsA file2.js(greenAin the left column): indicatesfile2.jswas newly added to the staging area.
- Output:
This detailed breakdown helps understand how git status -s conveniently summarizes the state of your files.
Reviewing Changes Before Committing (git diff)
Before committing, it's best practice to review what's in your staging area to avoid committing bad or broken code. While git status shows which files are affected, git diff shows the exact line-by-line changes.
-
View Staged Changes (what will go into the next commit):
git diff --staged- Output Analysis (
git diff):- Header:
diff --git a/file1.js b/file1.jsindicates a comparison betweenfile1.jsfrom the old version (a/) and the new version (b/). - Old vs. New: The "old copy" refers to what's in the last commit. The "new copy" refers to what's currently in the staging area.
- Index:
index ...is metadata and not typically important for users. - Legend:
- Lines prefixed with
-(red) denote changes in the old copy (removed lines). - Lines prefixed with
+(green) denote changes in the new copy (added lines).
- Lines prefixed with
- Chunk Headers (
@@):@@ -1,3 +1,5 @@signifies a "chunk" of changes.-1,3: From the old copy, starting at line 1, 3 lines were extracted.+1,5: From the new copy, starting at line 1, 5 lines were extracted.
- Content: The actual lines of code, with
+for new lines (e.g., "sky", "ocean"). - New File Diff: For
file2.js, you'd seediff --git a/dev/null b/file2.js.a/dev/nullindicates no old copy existed (it's a new file), and0,0 +1,1in the chunk header means 0 lines from line 0 in the old copy, vs 1 line from line 1 in the new copy.
- Header:
- Output Analysis (
-
View Unstaged Changes (what's in your working directory but not yet staged):
git diff- This command compares your working directory with your staging area.
- Example: If you modify
file1.js(e.g., change "hello world" to "hello world!") and don't stage it,git diffwill show:diff --git a/file1.js b/file1.js--- a/file1.js(old copy, which is the staged version)+++ b/file1.js(new copy, which is the working directory version)- Headers and content showing
hello(removed from staging) andhello world(added in working directory, implying a character change).
To Recap git diff:
git diff: Shows unstaged changes (Working Directory vs. Staging Area).git diff --staged: Shows staged changes (Staging Area vs. Last Commit).
Visual Diff Tools (git difftool)
While the terminal git diff is useful, visual diff tools offer a much better experience for comparing files.
-
Configure VS Code as your default diff tool:
- You need to set two global configuration settings.
- Name your diff tool:
git config --global diff.tool vscode- Here, "vscode" is just a chosen name for the tool.
- Define how to launch VS Code for diffing:
git config --global difftool.vscode.cmd "code --wait --diff \"$LOCAL\" \"$REMOTE\""code --wait --diff: Launches VS Code for diffing and waits until the VS Code instance is closed."$LOCAL"and"$REMOTE": These are placeholders that Git replaces with the paths to the old and new copies of the files being compared. Ensure these are accurately typed, including the double quotes.
- Verify configuration (optional):
git config --global -e- This opens your
~/.gitconfigfile. Look for[diff]and[difftool "vscode"]sections to confirm the settings.
- This opens your
-
Using
git difftool:-
View unstaged changes:
git difftool- If you have only one modified file (e.g.,
file1.js), Git will ask if you want to launch VS Code for that file. Typeyoryes. - VS Code will open side-by-side, showing the old copy (from staging area) on one side and the new copy (from working directory) on the other. This visual comparison makes it easy to see line deletions (red) and additions (green).
- Close VS Code to return control to the terminal.
- If you have only one modified file (e.g.,
-
View staged changes:
git difftool --staged- This will launch your visual diff tool to compare the files in the staging area against the last commit.
- Git will prompt you for each affected file. You can choose to view each diff or skip some.
-
Note: While git difftool is covered for completeness, many modern editors and IDEs (like VS Code) have built-in diff viewers that automatically show staged and unstaged changes within the environment, making git difftool less frequently used.
Viewing Commit History (git log)
To see the history of your commits, use the git log command.
-
View full history:
git log- Output:
- Commits are listed from newest to oldest.
- Each commit shows:
- Unique Identifier (SHA-1 hash): A 40-character hexadecimal string generated by Git (e.g.,
commit d601b90...). This acts like a revision number but is not sequential. HEAD -> master:masterrepresents the main branch (or main line of work).HEADis a pointer to the current branch you are working on. This will be explained further in the course's branching section.- Author: Name and email of the committer.
- Date: Date and time the commit was created.
- Commit Message: The one-line or multi-line description you provided.
- Unique Identifier (SHA-1 hash): A 40-character hexadecimal string generated by Git (e.g.,
- If there are many commits spanning multiple pages, press
Spaceto go to the next page, andqto quit.
- Output:
-
View concise history (
--oneline):git log --oneline- This shows a short summary: the first 7 characters of the commit ID and the one-line description. It omits author and date/time.
-
Reverse sort order (
--reverse):git log --oneline --reverse- This shows commits from oldest to newest.
The git log command is powerful and will be explored further in the "Browsing History" section. For now, focus on these basic views.
Inspecting Commits (git show)
To view the exact changes within a specific commit, use the git show command.
-
Inspect a commit by its ID:
- You can use the full 40-character commit ID or a shorter, unambiguous prefix (e.g., first 7 characters).
git show d601b90- Output: Displays the commit message, author, date, and a diff showing what changed in that commit. For example, if a
.gitignorefile was modified, it might show lines removed (-) and lines added (+).
-
Inspect a commit using
HEADreference:HEADalways points to the latest commit on your current branch.git show HEAD: Shows the latest commit.- Relative references (
~): To refer to previous commits:git show HEAD~1(orgit show HEAD~): Shows the commit one step beforeHEAD.git show HEAD~2: Shows the commit two steps beforeHEAD.
- This is useful for quickly navigating history without knowing commit IDs.
-
View the final version of a file in a specific commit:
- To see the exact content of a file as it existed in a particular commit, not just the diff:
git show HEAD~1:.gitignoreHEAD~1: Refers to the commit one step before the current HEAD.:.gitignore: Specifies the file path within that commit. This will display the content of.gitignoreat that specific historical point.
Understanding Git's Internal Structure (Blobs and Trees - git ls-tree)
Git stores a complete snapshot of your working directory in each commit, not just deltas. While git show displays differences, you can also view all files and directories within a commit. This brings us to the concept of "trees" in Git.
- Tree: In Git, a "tree" is a data structure representing hierarchical information, similar to how a directory structure works (directories contain files and subdirectories).
- Blob: A "blob" (Binary Large Object) is how Git stores the content of files.
-
List files and directories in a commit (
git ls-tree):git ls-tree HEAD- This command lists the contents of the commit pointed to by
HEAD. - Output:
- For each item, you'll see a type (e.g.,
blobfor files,treefor directories), its unique content-based identifier, and its filename/path. - Example:
100644 blob b2f0e0e0... file1.js,040000 tree d1c7e7e7... bin.
- For each item, you'll see a type (e.g.,
- This command lists the contents of the commit pointed to by
-
Inspect individual objects (Blobs or Trees) with
git show:- You can use
git showwith the unique identifier of a blob or tree to inspect its contents. - View a blob (file content):
git show b2f0e0e0- (Replace
b2f0e0e0with an actual blob ID from yourgit ls-treeoutput). This will display the content offile1.jsas it was stored in that blob.
- (Replace
- View a tree (directory content):
git show d1c7e7e7- (Replace
d1c7e7e7with an actual tree ID). This will show a list of files and subdirectories within that tree object.
- (Replace
- You can use
Thus, git show allows you to view various objects in Git's database: commits, blobs (files), and trees (directories).
Undoing Changes with git restore (and git clean)
It's common to make changes that you later decide to discard or revert. Git provides robust tools for this. git restore is a newer, less confusing command for undoing changes compared to the older git reset. (Ensure you are using Git version 2.28 or later for restore).
Undoing git add (Unstaging Changes):
Suppose you staged changes in file1.js but decide they shouldn't be part of the next commit. You want to "undo" the git add operation.
-
Unstage
file1.js(from staging area to working directory):git restore --staged file1.js--staged: Tells Git to restore the file in the staging area.- When you restore a file in the staging area, Git takes the copy from the next environment, which is the last commit in the repository, and places it into the staging area.
- Check status (
git status -s): The staged changes forfile1.jswill disappear, and the changes will reappear as unstaged modifications in your working directory.
-
Understanding
git restorewithnewly addedfiles:- Consider
file2.jsthat was newly added (git add .) and is now staged (A file2.jsingit status -s). - This file doesn't exist in the last commit.
- If you run
git restore --staged file2.js, Git will removefile2.jsfrom the staging area. Since there's no previous version in the repository, it effectively makesfile2.jsan untracked file again. - Check status (
git status -s):?? file2.js
- Consider
Discarding Local Changes (Undoing modifications in Working Directory):
Sometimes you make changes in your working directory that you want to completely throw away and revert to the last staged or committed version.
-
Example: Modify
file1.js(e.g., usingecho).git status -swill showM file1.js. -
Discard local changes in
file1.js:git restore file1.js- When you execute this, Git will take the version of
file1.jsfrom the staging area (or the last commit if not staged) and copy it into your working directory, overwriting your local modifications. - You can also use
git restore .to discard all local changes in the current directory.
- When you execute this, Git will take the version of
-
Handling Untracked Files after discarding local changes (
git clean):- After
git restore ., if you still have untracked files (e.g.,?? file2.js),git restorewon't remove them. This is because Git isn't tracking them and doesn't have a previous version to revert to. - To remove untracked files: Use the
git cleancommand. - Caution:
git cleanis a dangerous operation because discarded untracked files cannot be recovered. - View
git cleanhelp:git clean -h - Force remove untracked files and directories:
git clean -fd-f(force): Required to actually remove files.-d: Also removes untracked directories.
- Check status:
git status -swill now show a clean working directory (no untracked files).
- After
Restoring a Deleted File to a Previous Version
Git stores every version of a tracked file, so you can always restore a file to a previous version, even after deleting it.
-
Delete a tracked file:
- Use
git rm file1.jsto remove it from both the working directory and staging area, and stage the deletion. - Check status:
git status -swill showD file1.js. - Commit the deletion:
git commit -m "Delete file1.js"
- Use
-
Realize the mistake and restore
file1.js:- You want to restore
file1.jsfrom the commit before the deletion. - Check history:
git log --onelineto find the commit ID before the delete commit. - Restore the file:
git restore --source HEAD~1 file1.js--source HEAD~1: Tells Git to get the version offile1.jsfrom the commit one step before the currentHEAD(i.e., the commit before the deletion).
- Result:
file1.jswill reappear in your working directory as anuntrackedfile (?? file1.jsingit status -s). This is because Git restored the file's content but does not automatically re-track it; you would need togit addandgit commitit again if you want it tracked.
- You want to restore
This concludes the introductory section to Git, equipping you with fundamental concepts and commands to get started.
Step 2: Installing Git
First, you need to determine if Git is already installed on your machine and, if so, which version.
-
Check for Existing Git Installation
- Open your terminal or command prompt window.
- On Mac, press
Command + Spaceand typeterminal. - On Windows, click the search icon on the bottom navigation bar and type
cmd.
- On Mac, press
- Once the terminal or console window is open, type the following command and press Enter:
git --version - This command displays the installed Git version. For example, you might see
git version 2.19.2. It is highly recommended to download and install the latest stable version of Git, which at the time of this recording is2.27.0.
- Open your terminal or command prompt window.
-
Download and Install the Latest Git Version
- Go to the official Git website:
git-scm.com/download. - Follow the instructions provided on the website for installing Git on your specific operating system. The installation process is generally straightforward.
- For Windows Users: After installing Git, you will find an application called
Git Bash(short for Born Again SHell). This is a command prompt window that emulates Unix or Linux environments. It is recommended to use Git Bash throughout this course as it provides a consistent environment with the demonstrations.
- Go to the official Git website:
-
Configure User Identity
The first time you use Git, you must specify a few configuration settings, including your name, email, default text editor, and how Git should handle line endings. These settings can be configured at three levels:- System Level: Settings here apply to all users on the current computer.
- Global Level: Settings here apply to all repositories for the current user.
- Local Level: Settings here apply only to the current repository or the repository in the current folder. This allows for different settings for different projects.
To configure your user identity:
- In your terminal window (or Git Bash for Windows), enter the following commands to set your global username and email. The
--globalflag indicates that these settings should apply to all your repositories. - Set User Name:
git config --global user.name "Your Name"- Note: Use double quotes around your name if it contains spaces.
- Set User Email:
git config --global user.email your.email@example.com- Note: Double quotes are not necessary here unless your email address contains spaces.
-
Configure Default Text Editor
Git requires a default text editor for certain operations, such as writing commit messages that span multiple lines.- On Mac, if you don't set a default editor, Git will use
Vimby default, which can be challenging for beginners. - For this course, Visual Studio Code (VS Code) will be used as the default editor. If you want to follow along, download the latest version of VS Code from
code.visualstudio.com. Ensure VS Code is added to your system's PATH environment variable so you can launch it from any directory by typingcode. Ifcodedoes not work in your terminal, you might need to troubleshoot how to add VS Code to your PATH for your specific operating system. - To set VS Code as your default Git editor:
git config --global core.editor "code --wait"- Explanation:
core.editor: This is the setting for the default editor."code --wait": This tells Git to use thecodecommand (VS Code) and the--waitflag ensures the terminal waits until you close the VS Code instance that Git opened before returning control to the terminal.
- Explanation:
- On Mac, if you don't set a default editor, Git will use
-
Verify or Edit Global Configuration Settings
All global configuration settings are stored in a text file. You can open and edit this file using your default editor.- To open the global configuration file:
git config --global -e - This command will open the
.gitconfigfile (identified by its full path at the top) in VS Code. - Inside this file, you will see different sections. For example,
[user]will containnameandemailsettings, and[core]will contain editor settings. - After reviewing or making changes, save the file and close VS Code. The terminal (or Git Bash) will then resume accepting commands.
- To open the global configuration file:
-
Configure Line Ending Preferences (
core.autocrlf)
This is a crucial setting to prevent issues when collaborating across different operating systems.- Understanding Line Endings:
- On Windows, end-of-lines are marked with two special characters: "carriage return" (
\r) and "line feed" (\n), often represented as CRLF. - On Mac and Linux systems, end-of-lines are indicated with a single "line feed" (
\n), represented as LF.
- On Windows, end-of-lines are marked with two special characters: "carriage return" (
- Mismatched line endings can cause unexpected
diffresults and unnecessary changes when files are exchanged between different operating systems. - Scenario Example:
- Imagine John uses Windows and Julie uses Mac, working on the same repository.
- When John commits code from his Windows machine, Git should remove the
\rcharacter from line endings before storing the code in the repository. When he checks out code, Git should add the\rcharacter back. To achieve this, John should setcore.autocrlftotrue. - When Julie checks out code on her Mac, she does not want
\rcharacters. Git should not add them. However, if a\rcharacter is accidentally added (e.g., by her editor), Git should remove it when storing the code in the repository. To achieve this, Julie should setcore.autocrlftoinput.
- Set
core.autocrlf:- In your terminal, use the following command:
git config --global core.autocrlf [value] - Replace
[value]based on your operating system:- If you are on Windows: Set
core.autocrlftotrue. - If you are on Mac or Linux: Set
core.autocrlftoinput.
- If you are on Windows: Set
- In your terminal, use the following command:
- Understanding Line Endings:
-
Accessing Git Help
You can easily get help and documentation for Git commands:- Full Documentation: To view the full documentation for a command (e.g.,
config), use:
git config --helpThis command opens the man page (manual page) for
git configdirectly in your terminal, showing all options and their usage. PressSpaceto go to the next page andqto quit the viewer. - Quick Summary: For a short summary of a command and its options, use the
-hflag:
git config -hThis provides a concise overview of the command's functionality.
- Full Documentation: To view the full documentation for a command (e.g.,
Step 3: Basic Git Workflow
Basic Git Workflow
The first step in using Git effectively is understanding how to take snapshots of your project. This section will cover fundamental Git concepts that are often misunderstood.
How to Create a Git Repository
-
Create a Project Directory:
First, you need to create a directory for your project. You can name this directory anything and place it anywhere on your machine.
For example, if you are in yourprojectsdirectory, you can create a new directory namedmoonand then navigate into it:mkdir moon cd moonThis
moondirectory will serve as your project directory, which can contain tens or hundreds of files. -
Initialize a New Git Repository:
To add this directory to a Git repository for the first time, you must initialize a new empty repository within it.
Type the following command:git initYou will see a message similar to:
Initialized empty Git repository in /path/to/your/project/moon/.git/. -
Understand the
.gitSubdirectory:
Inside your project directory (moonin this example), Git creates a hidden subdirectory called.git. This directory is hidden by default because you are not supposed to directly interact with its contents.
If you list the files and directories (ls), you won't see it. To see all files, including hidden ones, use:ls -aYou will now see the
.gitsubdirectory. This is your Git repository; it's where Git stores all information about your project's history. It contains directories likebranches,hooks,info,objects, andreferences. As a Git user, you don't need to understand this internal structure; it's Git's implementation detail. Modifying or deleting this directory will result in the loss of your project history.Caution: If you remove the
.gitsubdirectory, you will lose your repository. For example:rm -rf .gitYou will notice that the green
(git)marker (if you have one in your terminal) disappears, indicating that you are no longer in a Git repository. To re-initialize it, rungit initagain.
Understanding the Staging Area (Index) and its Role in Committing
Now that you have a Git repository, let's discuss the basic Git workflow you'll follow daily.
-
Workflow Overview:
- Your project directory contains your files, and within it is the hidden
.gitrepository. - As you work, you modify one or more files.
- When your project reaches a desirable state, you commit those changes to your repository. A commit is like taking a snapshot of your project.
- Git has a special intermediate step called the "staging area" or "index," which doesn't exist in most other version control systems.
- The staging area is where you propose changes for your next commit or snapshot.
- After making changes, you add the modified files to the staging area.
- You then review these staged changes.
- If everything is satisfactory, you make a commit, and this proposed snapshot is permanently stored in your repository.
- The staging area allows you to review your work before permanently recording it. If some changes shouldn't be part of the next snapshot, you can "unstage" them and commit them later as part of a different snapshot.
- Your project directory contains your files, and within it is the hidden
-
Illustrative Example of the Staging Area:
-
Initial State: Your project directory is currently empty.
-
Step 1: Create Files:
You add a couple of files, for instance,file1.txtandfile2.txt.echo "hello" > file1.txt echo "hi" > file2.txt -
Step 2: Add Files to Staging Area:
These files are new and untracked by Git. To prepare them for the first commit, you use thegit addcommand.git add .(The
.adds all changes in the current directory and its subdirectories recursively.)
Now, these files are in the staging area. This represents the state you are proposing for your next commit. -
Step 3: Commit Changes:
You review the staged files. If everything looks good, you use thegit commitcommand to permanently store this snapshot in the repository. As part of this, you provide a meaningful message describing the snapshot.git commit -m "Initial commit"You now have one commit in your repository.
-
Common Misconception:
A common misconception is that the staging area becomes empty after a commit. This is incorrect. What you have in the staging area after a commit is the same snapshot that you just stored in the repository. The staging area can be thought of as a reflection of what's currently in your repository, or the next version destined for it. -
Step 4: Modify a File:
Suppose you fix a bug and make changes tofile1.txt.echo "world" >> file1.txtAt this point, the staging area still contains the old version of
file1.txtbecause you haven't staged these new changes. -
Step 5: Stage Modified File:
You usegit addagain to stage the latest changes tofile1.txt.git add file1.txtNow, the staging area contains the same content as your working directory for
file1.txt. -
Step 6: Commit New Changes:
You then make another commit to record this updated state, including a descriptive message about the bug fix.git commit -m "Fix: Add 'world' to file1"You now have two commits in your repository, each clearly explaining the state of the project at that point in time.
-
Step 7: Delete a File:
Imaginefile2.txtis no longer needed. You delete it from your working directory:rm file2.txtHowever,
file2.txtis still in the staging area. -
Step 8: Stage Delete Operation:
You must use thegit addcommand to stage this deletion. Even though you are runninggit add, Git understands that the file has been deleted and will remove it from the staging area for the next snapshot.git add file2.txt -
Step 9: Commit Deletion:
You commit this change to permanently record the state withoutfile2.txt.git commit -m "Remove unused file2"You now have three commits.
-
Commit Content:
Each commit has a unique identifier (a 40-character hexadecimal string) generated by Git, acting like a revision number. Each commit also includes information about what was changed, by whom, when, and a complete snapshot of your project at the time it was created. Unlike many other version control systems, Git stores the full content of the project in each snapshot, not just the deltas (changes). This allows for quick restoration to an earlier state without computing changes. Git is very efficient, compressing file contents and avoiding duplicate storage.
-
Adding and Committing Changes
Let's put the basic workflow into practice with a live example.
-
Add Files to Your Project:
Begin by creating two files within your project directory:echo "hello" > file1.txt echo "hi" > file2.txtAfter creating these files, you'll notice a question mark
?next to them if your terminal is configured to show Git status indicators. This means the files are new and not yet tracked by Git. Git does not automatically track new files. -
Check Working Directory Status (
git status):
Rungit statusto see the status of your working directory and the staging area:git statusThe output will indicate "No commits yet" and list
file1.txtandfile2.txtas "Untracked files" in red. Red indicates that they are not yet in the staging area. -
Add Files to the Staging Area (
git add):
To prepare these files for committing, you need to add them to the staging area usinggit add.
You have several options:git add file1.txt: Adds a single file.git add file1.txt file2.txt: Adds multiple specific files.git add *.txt: Adds all files with a.txtextension.git add .: Adds all new and modified files in the current directory and its subdirectories recursively. Be cautious withgit add .as you might not want to add all files (e.g., large binary files or log files). You'll learn how to ignore files later.
For this demo, add both files using
git add .:git add .If your terminal has status indicators, the question marks will change to yellow, indicating that files are staged and ready to be committed.
-
Verify Staging Area Status:
Rungit statusagain:git statusThe output will now show
file1.txtandfile2.txtunder "Changes to be committed" in green, indicating they are in the staging area. -
Modify a Staged File:
Now, let's modifyfile1.txtafter it has been staged.
Append "world" tofile1.txt:echo "world" >> file1.txt(Note:
>>appends to the file, while>overwrites it.) -
Observe Status After Modification:
Rungit statusagain:git statusYou'll see
file1.txtlisted twice:- Under "Changes to be committed" (green), it shows the original staged version of
file1.txt. - Under "Changes not staged for commit" (red), it shows the modified version of
file1.txtthat is currently in your working directory.
This demonstrates that Git took a snapshot offile1.txtwhen you first rangit add .. The subsequent change tofile1.txtcreated a new, unstaged difference.
- Under "Changes to be committed" (green), it shows the original staged version of
-
Re-stage Modified File:
To include the latest changes tofile1.txtin your next commit, you must stage it again:git add . -
Verify All Changes Staged:
Rungit statusone more time:git statusNow, both
file1.txtandfile2.txtshould be listed under "Changes to be committed" in green, and there should be no unstaged changes. -
Commit Staged Changes (
git commit):
With your snapshot prepared in the staging area, commit it permanently to the repository.
Provide a concise, descriptive message using the-mflag:git commit -m "Initial commit"The output will show statistics, such as "2 files changed," "3 insertions." The indicator in your terminal will turn green, signifying a clean working directory (no pending changes). What you have in your working directory is now identical to what's in your staging area, which is identical to your last commit.
-
Committing with a Multi-line Message:
Sometimes, a short one-liner description isn't enough, and you need to provide more context (e.g., explaining constraints for a bug fix). In such cases, omit the-mflag:git commitThis will open your default editor (e.g., VS Code, configured earlier in the course) to a file named
COMMIT_EDITMSG(or similar) in your.gitsubdirectory.-
Structure of a Multi-line Commit Message:
- The first line should be a short summary, ideally less than 80 characters.
- Add a line break (an empty line).
- After the empty line, you can type a longer, more detailed description.
- Lines starting with a pound sign (
#) are comments and will be ignored by Git.
-
Example:
Initial commit This is our first commit. It sets up the basic project structure and includes the initial files. -
Save the changes in your editor and then close the window.
-
Back in the terminal, Git will proceed with the commit, displaying statistics.
-
-
Skipping the Staging Area (Advanced - Use with Caution):
While the staging area is crucial for review, you can skip it in specific scenarios. This should only be done if you are 100% certain that your changes don't need review.- Modify a file:
echo "test" >> file1.txtYour working directory is now "dirty" (yellow indicator).
- Commit directly:
You can combine theaddandcommitsteps for modified (not new) files using the-a(or--all) option withgit commit:git commit -a -m "Fix the bug that prevented users from signing up"This command stages all modified (tracked) files and then commits them in one go. The output will confirm the commit, e.g., "1 file changed, 1 insertion."
- Warning: Most of the time, you should always stage your code before committing it to the repository. Use this shortcut only when you are certain.
- Modify a file:
-
Removing Files (
git rm):
If you determine a file is no longer needed (e.g.,file2.txt), you can remove it.- Standard Unix
rm(Not Recommended for tracked files):
If you userm file2.txt, it only deletes the file from your working directory.git statuswill show adeletedchange that is "not staged for commit." You would then need togit add file2.txtto stage the deletion, and thengit commit. The filefile2.txtwould still appear ingit ls-files(which shows files in the staging area) until committed. - Git
rm(Recommended for tracked files):
Git provides a command that removes the file from both your working directory and the staging area simultaneously:git rm file2.txtAfter this,
git statuswill immediately showfile2.txtasdeletedand "Changes to be committed" (green). - Commit the deletion:
git commit -m "Remove unused code"
- Standard Unix
-
Renaming or Moving Files (
git mv):
Renaming or moving files in Git is a two-step process if you use standard operating system commands: modify the working directory, then stage both the deletion of the old file and the addition of the new file. Git provides a single command for this:- Standard Unix
mv(Not Recommended for tracked files):
If you renamefile1.txttomain.jsusingmv file1.txt main.js,git statuswill show two unstaged changes:deleted: file1.txtanduntracked: main.js. You would then need to manuallygit add file1.txt(to stage the deletion) andgit add main.js(to stage the new file). After staging, Git will recognize it as a "rename." - Git
mv(Recommended for tracked files):
Git'smvcommand handles both the file system operation and staging:git mv main.js file1.jsAfter this,
git statuswill directly showrenamed: main.js -> file1.jsas "Changes to be committed" (green). - Commit the rename:
git commit -m "Refactor code"Note that during a rename, the commit statistics will show 0 insertions and 0 deletions because no file content was added or removed, only the name changed.
- Standard Unix
-
Ignoring Files (
.gitignore):
In most projects, you need to tell Git to ignore certain files or directories that should not be tracked (e.g., log files, compiled binaries, temporary files). Including these unnecessary files increases repository size without providing value.- Create Unwanted Files/Directories (Example):
Create a directorylogsand a filedev.loginside it:mkdir logs echo "hello" > logs/dev.log - Check Status:
git statuswill show "Untracked files: logs/". You don't want to add this. - Create
.gitignore:
To ignore files, you create a special file named.gitignorein the root of your project. This file has no name, only an extension.echo "logs/" > .gitignoreYou can also open this file in your editor:
code .gitignore(if using VS Code). - Content of
.gitignore:
Add entries for files or directories to ignore.logs/: Ignores thelogsdirectory.main.log: Ignores a specific filemain.log.*.log: Ignores all files ending with.log.
Save the.gitignorefile.
- Verify Ignoring:
Rungit statusagain. Git will no longer report thelogsdirectory as untracked. Instead, it will show a new untracked file:.gitignore. - Add and Commit
.gitignore:
You should commit your.gitignorefile so that all collaborators automatically ignore the same files.git add .gitignore git commit -m "Add .gitignore" - Important Note on Ignoring:
.gitignoreonly works for files that Git is not already tracking. If you accidentally commit a file (e.g., a compiled binary) and then later add it to.gitignore, Git will not ignore it. It will continue to track changes to that file.- Example (Accidentally tracking a binary):
mkdir bin echo "hello" > bin/app.bin git add . # Accidentally adds bin/app.bin git commit -m "Add bin"Now, if you later add
bin/to.gitignoreand modifybin/app.bin,git statuswill still showbin/app.binas modified. - Solution (Removing tracked files from index):
To tell Git to stop tracking a file that is already committed while keeping it in your working directory, you need to remove it from the staging area (index).- First, confirm the file is in the staging area:
git ls-files - Use
git rm --cachedto remove it from the index only:
git rm --cached bin/app.bin(If it's a directory, you need the
-rflag:git rm --cached -r bin/) - Verify it's removed from staging:
git ls-files - Now
git statuswill show the file asdeletedand ready for commit. - Commit this change:
git commit -m "Remove bin directory that was accidentally committed"
From this point, Git will no longer track changes in the
bindirectory, providedbin/is in your.gitignore. - First, confirm the file is in the staging area:
- Example (Accidentally tracking a binary):
- Git Ignore Templates:
You can find.gitignoretemplates for various programming languages on GitHub:github.com/github/gitignore. These templates help you ignore common files (e.g.,.classfiles in Java, compiled assets).
- Create Unwanted Files/Directories (Example):
Best Practices for Crafting Meaningful and Appropriately Sized Commits
Following best practices for commits is crucial for maintaining a clean and useful project history.
-
Commit Size:
- Not too small: Avoid committing every single time you update a file. This leads to useless commit messages like "Update file1," "Update file2," etc.
- Not too big: Don't wait to implement an entire feature end-to-end before committing. The purpose of commits is to record checkpoints as you progress. If you make a mistake, you can easily revert to an earlier state.
- Commit frequently: In a real-world scenario, you might commit 5 to 10 times a day or even more. As you code and reach a stable, recordable state, make a commit.
-
Logically Separate Changes:
- Each commit should represent a logically separate set of changes. Do not mix unrelated changes in a single commit.
- Example: If you are fixing a bug and accidentally discover a typo in the code, do not commit both changes in one commit. Make two separate commits: one for the typo and another for the bug fix. This keeps your history clear and easily traceable. (If you accidentally stage both changes, you can unstage them, which will be covered later.)
-
Meaningful Commit Messages:
- Make it a habit to create meaningful commit messages. These messages will appear in your project's history, and cryptic messages are unhelpful to both you and your team members.
- If you adhere to the practice of each commit representing a single unit of work, crafting a descriptive message becomes much easier. If a commit tries to do too many things, it will be difficult to write a clear message.
-
Wording Convention (Present Tense):
- Most developers prefer to use the present tense in commit messages.
- Instead of: "Fixed the bug"
- Use: "Fix the bug"
- While this is a common convention, if you prefer a different style, that's fine. The key is consistency within your team and project.
By following these best practices, you contribute to a clean, comprehensible, and effective Git history for your projects.
Viewing Status and Differences
-
Short Status (
git status -sorgit status --short):
The standardgit statuscommand provides comprehensive but verbose output. For a quicker summary, use the short status flag:git status -s- Output Structure: This command shows two columns:
- Left Column: Represents the staging area.
- Right Column: Represents the working directory.
- Example Usage:
- Modify
file1.js(example assumes it exists and is tracked):
echo "sky" >> file1.js - Create a new file
file2.js:
echo "sky" > file2.js - Run
git status -s:M file1.js: TheMin the right column (working directory) indicatesfile1.jsis modified but not yet staged.?? file2.js:??in both columns indicatesfile2.jsis a new, untracked file.
- Add
file1.jsto staging:
git add file1.js - Run
git status -sagain:M file1.js: A greenMin the left column (staging area) meansfile1.jsis modified and staged. The right column is empty because there are no further unstaged changes for this file.
Remember, when you stage a file, Git takes a snapshot. If you modify it again after staging, you need to restage those new changes.- Modify
file1.jsone more time:
echo "ocean" >> file1.js - Run
git status -s:MM file1.js: The firstM(green) indicates staged changes, while the secondM(red) indicates additional unstaged changes in the working directory.
- Re-stage
file1.js:
git add file1.js - Run
git status -s:M file1.js: All changes forfile1.jsare now staged.
- Add
file2.jsto staging:
git add file2.js - Run
git status -sagain:M file1.jsA file2.js: A greenAin the left column indicatesfile2.jsis a new file that has been added to the staging area.
- Modify
- Output Structure: This command shows two columns:
-
Viewing Staged Changes (
git diff --staged):
Before committing, it's a best practice to review what's in your staging area to avoid committing bad or broken code. Whilegit statusshows which files are affected,git diff --stagedshows the exact lines of code that are staged to go into the next commit.git diff --staged- Understanding the Output:
- The output shows
diff --git a/file1.js b/file1.js, indicating a comparison between two copies of the same file. a/file1.jsrepresents the old copy (what was in the last commit).b/file1.jsrepresents the new copy (what's currently in the staging area).- Lines prefixed with
-(red) indicate changes in the old copy (removed lines). - Lines prefixed with
+(green) indicate changes in the new copy (added lines). - Headers like
@@ -1,3 +1,5 @@indicate the chunk of the file being shown.-1,3: In the old copy, starting from line 1, 3 lines have been extracted.+1,5: In the new copy, starting from line 1, 5 lines have been extracted.
- For brand new files (
file2.jsin our example), the diff will show0,0for the old copy's header (e.g.,@@ -0,0 +1,1 @@) because there was no old version of the file.
- The output shows
- Understanding the Output:
-
Viewing Unstaged Changes (
git diff):
To see changes in your working directory that are not yet staged, usegit diffwithout any arguments:git diff- This command compares what you have in your working directory with what you have in the staging area.
- Example after
git add .and further modification:- If all changes are staged,
git diffwill show no output. - If you then modify
file1.jsagain (e.g., change "hello" to "hello world"):-
# Open file1.js in your editor and change 'hello' to 'hello world' # Save and close git diff - The output will show:
-hello(red, line removed from staging area's version)+hello world(green, line added in working directory's version)
- This diff compares the staged version of
file1.js(a/file1.js) with the unstaged version in your working directory (b/file1.js).
-
- If all changes are staged,
- Recap:
git diff: Shows unstaged changes (working directory vs. staging area).git diff --staged: Shows staged changes (staging area vs. last commit).
Using a Visual Diff Tool
While the terminal-based git diff is useful, visual diff tools provide a much better experience for comparing files.
-
Configure Git for a Visual Diff Tool (VS Code Example):
You need to tell Git which visual diff tool to use. For VS Code:- Set the tool name:
git config --global diff.tool vscodeThis sets
vscodeas the name for your default diff tool. - Define the launch command:
git config --global difftool.vscode.cmd "code --wait --diff \"\$LOCAL\" \"\$REMOTE\""code: The command to launch VS Code (ensurecodeis in your system's PATH).--wait: Tells the terminal to wait until you close the VS Code instance.--diff: Tells VS Code to open in diff mode."$LOCAL"and"$REMOTE": These are placeholders for the old and new copies of the file being compared. Ensure these are correctly typed, including the double quotes and backslashes for proper escaping in some shells. If you edit your global config withgit config --global -e, you might need to manually re-add these placeholders if they disappear.
- Set the tool name:
-
Verify Configuration:
To confirm your settings, open your global Git configuration file:git config --global -eThis opens the
.gitconfigfile in your default editor. Look for sections like[diff]and[difftool "vscode"]. -
Launch the Visual Diff Tool (
git difftool):
Instead ofgit diff, usegit difftool:git difftool- Without arguments,
git difftoolwill show your unstaged changes (working directory vs. staging area). - To see staged changes (staging area vs. last commit), use:
git difftool --staged
Git will prompt you to launch the diff tool for each affected file.
- When VS Code opens, it will display two panes: the old copy and the new copy, with changes highlighted, making it much easier to visualize differences.
- After reviewing, close the VS Code instance to return to the terminal.
While visual diff tools are powerful, many modern IDEs (like VS Code) have built-in Git integrations that allow you to view staged and unstaged changes directly within the editor environment, often making external diff tools less frequently used in daily workflows.
- Without arguments,
Browsing History
Git provides powerful tools to view your project's history.
-
Viewing Commit History (
git log):
Use thegit logcommand to see a list of all commits in your repository, sorted from the latest to the earliest:git log- Output Details:
- Commit ID: Each commit has a unique 40-character hexadecimal string, a unique identifier.
- HEAD -> master:
HEADis a pointer to your current branch.masteris typically the main branch or main line of work. Git allows multiple branches for parallel development. Further details on branching will be covered later. - Author: The name and email of the commit author.
- Date: The date and time the commit was created.
- Commit Message: The one-line description and any detailed message provided during the commit.
- Navigation: If the history spans multiple pages, press
spaceto go to the next page andqto quit.
- Output Details:
-
Short Summary (
git log --oneline):
For a concise summary of commits, showing only the shortened commit ID and the one-line description:git log --oneline -
Reverse Order (
git log --reverse):
To view commits from the earliest to the latest:git log --oneline --reverse -
Inspecting a Specific Commit (
git show):
To see what exactly was changed in a particular commit, usegit showfollowed by the commit identifier.- Referencing a Commit:
- Full or Partial ID: You can use the full 40-character commit ID or a shortened version as long as it's unique (e.g.,
d601b90from agit log --onelineoutput).
git show d601b90 - HEAD Pointer with Tilde (
~):HEADrefers to the latest commit on your current branch. You can reference previous commits relative toHEADusing~followed by a number.HEAD: The latest commit.HEAD~1: The commit before the latest one.HEAD~2: Two commits before the latest one, and so on.
git show HEAD~1
- Full or Partial ID: You can use the full 40-character commit ID or a shortened version as long as it's unique (e.g.,
- Output of
git show:- The author, date, and commit message.
- A diff showing what has changed in that commit. Similar to
git diff, it uses+for additions and-for deletions. - Example:
git show HEAD~1might show thatgit-ignorewas modified, with certain lines removed and others added.
- Referencing a Commit:
-
Viewing a File's Version in a Specific Commit:
Whilegit showdisplays the changes, you can also retrieve the exact content of a file as it existed in a specific commit.git show :- Example: To see the version of
.gitignoreas it was inHEAD~1:
git show HEAD~1:.gitignoreThis command will output the entire content of the
.gitignorefile from that specific commit.
- Example: To see the version of
-
Listing Files and Directories in a Commit (
git ls-tree):
Git stores a complete snapshot of your project in each commit, not just changes. You can view all files and directories for a given commit usinggit ls-tree.- Understanding "Tree": In Git, "tree" refers to a data structure representing hierarchical information, similar to a file system directory where nodes can have children (files and subdirectories).
- Command:
git ls-tree HEAD~1 - Output Details:
- It lists files (represented as "blobs") and directories (represented as "trees") with their unique identifiers (generated based on their content).
- Example: You might see
100644 blob .gitignoreor040000 tree bin. - Files are
blobobjects, and directories aretreeobjects. All are stored in Git's internal database.
-
Viewing Git Objects (
git show):
You can directly inspect the content of any Git object (blob, tree, commit) if you have its unique identifier.- Example: To view the content of the
.gitignoreblob identified by `` from thegit ls-treeoutput:
git showThis will display the plain text content of that file.
- Example: To view the content of the
bintree:
git showThis will show the contents of the
bindirectory, including files likeapp.binit contains.
- Example: To view the content of the
Undoing Changes
Git allows you to undo various types of changes, from unstaging files to recovering deleted ones.
-
Undoing
git add(Unstaging Files):
If you'vegit added changes to the staging area but decide they shouldn't be part of the next commit (e.g., they belong to a different task), you can undo theaddoperation.- Using
git restore --staged:
Git introduced therestorecommand for this purpose (ensure you are using Git version 2.28 or later).git restore --staged- Example: If
file1.jswas added to the staging area:
git restore --staged file1.js - After running this,
git status -swill showfile1.jswith a redMin the right column, meaning it's back in the working directory as an unstaged change. The staged version is now reverted to what was in the last commit.
- Example: If
- Understanding
git restore --staged: This command takes the copy of the file from the "next" environment, which for the staging area is the last commit (repository), and puts it back into the staging area. Essentially, it replaces the staged version with the version from the last commit. - Unstaging a New File
A(added): If yougit adda new file (Aingit status -s), and then rungit restore --staged, Git will effectively remove it from the staging area, returning it to an "untracked" (??) state, because it doesn't exist in the last commit for Git to restore from.
git restore --staged file2.js # If file2.js was a new, staged file. git status -s # file2.js will now show ??
- Using
-
Discarding Local Changes (
git restore):
Sometimes you make changes in your working directory that you want to completely discard and revert to the last committed or staged version.- Command:
git restore- This command takes the version of the file from the staging area (or the last commit if the file is not staged) and copies it into your working directory, overwriting your local changes.
- You can also discard changes for all files in the current directory:
git restore .
- Example: If you modified
file1.jslocally:
git restore file1.jsThe uncommitted changes in
file1.jswill be gone. - Note on New Untracked Files:
git restorewill not remove new, untracked files (??ingit status -s). This is because Git is not tracking them, so it doesn't have a previous version to restore from.
- Command:
-
Removing Untracked Files (
git clean):
To remove new, untracked files (thatgit restorecannot touch), usegit clean.- Warning: This is a dangerous operation. Once untracked files are removed with
git clean, there is no way to recover them. - Fatal Error by Default: If you run
git cleanby itself, it will give a fatal error and ask for--force. - Options:
-for--force: Forces the removal of untracked files.-d: Also removes untracked directories.git clean -fd: Commonly used to remove untracked files and directories.
- Example: To remove
file2.jsafter it's in??state:
git clean -fdfile2.jswill then be gone.
- Warning: This is a dangerous operation. Once untracked files are removed with
-
Restoring a Deleted File:
If you accidentally delete a file that was previously tracked and committed, you can restore it to a prior version.- Scenario: Assume
file1.jsexists and is already committed. - Delete the file:
Usinggit rm file1.jswill delete it from both working directory and staging area, andgit status -swill showD file1.js. - Commit the deletion:
git commit -m "Delete file1.js" - Restore the file:
To restorefile1.jsto the commit before the deletion (e.g.,HEAD~1):git restore --source HEAD~1 file1.js--source: This option tells Git to restore the file from a specific commit, overriding the default behavior of restoring from the next environment (staging area/last commit).
- After restoration,
git status -swill show?? file1.js, indicating it's back in your working directory as a new, untracked file. You will then need togit addandgit commitit if you want to re-add it to your repository history, or simply keep it as an untracked file if that's your intention.
- Scenario: Assume
You have now learned the basic Git workflow, including how to create a repository, understand the staging area, perform adds and commits, and apply best practices for clean and meaningful commit history. You can also view status, differences, browse history, and undo various changes.
Step 4: Viewing History
Viewing History
We have made a few commits so far, but where are these commits? We can view them using the git log command.
-
Using
git logto Browse Commit History
Typegit log.
You will see a list of all your commits, sorted from the latest to the earliest. Each commit entry typically includes:- A unique 40-character hexadecimal string, which is the commit's unique identifier (like a revision number, but not sequential).
HEAD -> master:HEADis a reference to the current branch, andmasteris the main branch or line of work. Git usesHEADto know which branch you are currently on.- Author: The name and email of the person who made the commit.
- Date and Time: When the commit was created.
- Commit Message: A one-line description of the commit.
If you have many commits that spread across multiple pages, you can press
spaceto go to the next page andqto quit the log view. -
git logOptions-
--oneline: This option provides a short summary of each commit.
Typegit log --oneline.
The output will show the unique identifier, shortened to seven characters, and only the one-line description. It omits the author, date, and time. -
--reverse: This option reverses the sort order, showing the first commit on top.
Typegit log --oneline --reverse.
This will show the commits from earliest to latest.
-
-
Inspecting Individual Commits with
git show
Whilegit logis great for viewing a list of commits,git showallows you to see the exact changes made in a specific commit.-
Referencing a commit by its unique identifier:
To inspect a commit, you need its unique identifier. For example, if you want to look at a commit with an ID starting withd601b90, you can type:
git show d601b90
You don't always need to type all 40 characters; fewer characters are usually sufficient as long as there's no ambiguity with other commit IDs. -
Referencing a commit using
HEAD:
HEADpoints to the latest commit on the current branch.
To view the last commit, you can typegit show HEAD.
To view a previous commit, you can use the tilde (~) operator followed by a number to specify how many steps back you want to go. For example, to go one step back fromHEAD:
git show HEAD~1
This command will display:- The author and date of that specific commit.
- The commit message.
- A diff (difference) of what files were changed and what specific lines were altered (added, removed, or modified). For example, it might show a
git ignorefile where a line was removed and two new lines were added.
-
Viewing the final version of a file in a commit:
If you want to see the exact version of a file as it was stored in a particular commit, rather than just the differences, use the following syntax:
git show :
For example, to view thegit ignorefile from the commit referenced byHEAD~1:
git show HEAD~1:.git-ignore
If the file is in a subdirectory, you would specify the full path, such asbin/app.bin.Git stores a complete snapshot of your project with each commit, not just the changes. The
git showcommand, by default, highlights the differences.
-
-
Understanding Git's Internal Object Model (Blobs, Trees, Commits)
To see all the files and directories in a specific commit, you use thegit ls-treecommand. This command is namedls-treebecause a tree is a data structure used to represent hierarchical information, similar to how directories contain files and subdirectories.-
git ls-tree:
Typegit ls-tree HEAD~1.
This will list all the files and directories stored in that commit. You will see:- File names (e.g.,
.git-ignore,bin/app.bin). - A unique identifier (a hash) generated based on the content of the file or directory. This ID refers to an object in Git's internal database.
- The type of the object:
blob: Represents a file.tree: Represents a directory.
- File names (e.g.,
-
Inspecting Git Objects with
git show:
You can usegit showto view the content of any Git object, including blobs and trees, by specifying their unique identifier.-
To view a
blob(file content):
git show(e.g.,git show)
This will display the exact content of that file as stored in Git's database. -
To view a
tree(directory content):
git show(e.g.,git showwherebinis a directory)
This will list the contents of that directory, including any files (blob) or subdirectories (tree) it contains.
Git's objects include
commits,blobs(files),trees(directories), andtags(which will be discussed later). -
-
-
Configuring and Using Visual Diff Tools
Comparing files using the terminal can be challenging. Visual diff tools provide a much better experience. This section will guide you on setting up VS Code as your default Git diff tool. If you prefer another tool like KDiff3 or P4Merge, you'll need to find their specific configuration instructions.-
Configure VS Code as the Default Diff Tool:
In your terminal, you need to set two Git configuration settings globally.- Specify the name of your diff tool:
git config --global diff.tool vscode
This command gives the namevscodeto your chosen diff tool. - Configure how Git should launch VS Code for diffing:
git config --global difftool.vscode.cmd "code --wait --diff \$LOCAL \$REMOTE"code: The command to launch VS Code. (Ensurecodeis added to your system's PATH, so it can be run from any directory. If not, you may need to troubleshoot this for your OS.)--wait: This flag tells the terminal to wait until you close the VS Code instance where the diff is shown.--diff: This flag tells VS Code that you intend to use it for comparing files.$LOCALand$REMOTE: These are placeholders that Git replaces with the paths to the old and new copies of the file being compared. Make sure to type these exactly, including the dollar signs and capitalization.
- Specify the name of your diff tool:
-
Verify Configuration:
To ensure the settings are correctly applied, you can open your global Git configuration file:
git config --global -e
This will open the.gitconfigfile in your default editor (VS Code, if you configured it previously). You should see a[diff]section withtool = vscodeand a[difftool "vscode"]section withcmd = code --wait --diff $LOCAL $REMOTE. Close the editor to return to the terminal. -
Using
git difftool:
Instead ofgit diff, you now usegit difftoolto launch your configured visual diff tool.-
View Unstaged Changes (Working Directory vs. Staging Area):
Typegit difftool
If you have unstaged changes (modifications in your working directory that are not yet in the staging area), Git will prompt you to launch VS Code to view them.
(Example: If you modifiedfile1.js, it will show1 of 1files being diffed.)
When VS Code opens, it will display two panes:- The old copy (what's currently in the staging area).
- The new copy (what's in your working directory).
You can easily see the changes, with replaced lines clearly highlighted. Close the VS Code window when you're done.
-
View Staged Changes (Staging Area vs. Last Commit):
Typegit difftool --staged
This will show you the changes that are currently in your staging area and are ready to be committed. Git will launch VS Code for each changed file in the staging area.
In this view:- The old copy is what you have in the last commit.
- The new copy is what you have in the staging area.
These are the changes that will become part of your next commit.
While visual diff tools are powerful, modern IDEs and code editors (like VS Code) often have built-in source control panels that allow you to view staged and unstaged changes directly within your development environment, reducing the need for separate diff tools in many workflows.
-
-
-
Analyzing Changes in Working Directory vs. Staging Area
To recap how to check changes within various Git environments:-
git diff(without arguments): Shows unstaged changes. This compares what is in your working directory with what is currently in your staging area.
(Example: If you have a filefile1.jswith "hello" in staging and change it to "hello world" in the working directory,git diffwill show "hello" as removed and "hello world" as added.) -
git diff --staged: Shows staged changes. This compares what is in your staging area with what was in the last commit. These are the changes that will be included in your next commit.
(Example: If "hello world" is in staging,git diff --stagedwill show "hello world" as an addition relative to the last commit.)
Note that the
git status --short(orgit status -s) command is still useful for a quick overview of which files are modified, added, or deleted in both the staging area and working directory, offering a concise representation of your project's current state. -
Step 5: Advanced Topics
Advanced Topics
Occasionally, you may make changes that you no longer need. This section will cover methods to undo modifications, discard unnecessary changes, manage untracked files, and restore files to previous historical versions.
Undoing git add using git restore --staged
You should always review what you have in the staging area before making a commit to avoid committing bad or broken code. You can use the git diff --staged command to review staged changes.
For example, if you have staged changes in a file, such as file1.js, and then discover that these changes should not be part of the next commit, you can undo the git add operation.
In the past, the git reset command was used for this purpose, but it was often confusing. A newer, simpler command, git restore, is now available (make sure you are using Git version 2.28 or later).
To undo the staging of a specific file:
- Type
git restore --staged file1.js.- You can list multiple files or use patterns (e.g.,
*.js). - To restore everything in the staging area, use a period (
.) instead of a file name.
- You can list multiple files or use patterns (e.g.,
- Run
git status -sto confirm.- You will see that
file1.jsno longer has a greenMin the left column (staging area). The changes are now in the working directory (redMin the right column if the file was modified, or noMif it was an addition that became untracked again).
- You will see that
The git restore command takes a copy of the specified file from "the next environment" and places it into the target environment.
- When restoring a file in the staging area, Git takes the last committed version of that file from the repository and places it into the staging area.
Consider file2.js, which was a new, untracked file that was then added to the staging area (indicated by a green A in git status -s).
- Since
file2.jsdid not exist in the last commit (repository), taking a copy from "the next environment" (the last commit) means there's no previous version to restore from the repository. - Therefore, when you run
git restore --staged file2.js, Git understands that this file was newly added and not yet committed. It will removefile2.jsfrom the staging area and return it to its previous state: an untracked file. - To verify this, run
git status -sagain. You will seefile2.jslisted with two question marks (??), indicating it is still an untracked file, meaning thegit addfor it has been undone.
Discarding Local Changes in the Working Directory
Sometimes, you make changes to files in your working directory that you decide to discard, either because you don't like them or they are no longer needed.
To undo local changes in file1.js:
- Type
git restore file1.js.- You can use a period (
.) to undo all local changes in the working directory.
- You can use a period (
- Execute the command.
- Git will take the version of
file1.jsfrom the staging area and copy it into your working directory, overwriting your local modifications.
- Git will take the version of
- Run
git status -sto confirm that the changes infile1.jshave been discarded.
If you have new, untracked files in your working directory (e.g., file2.js from the previous example, which is now untracked), git restore will not affect them. This is because Git is not tracking these files yet, so it has no "previous version" in the staging area or the repository to restore from.
To remove all new, untracked files:
- Type
git clean.- By default, Git will give a "fatal error: clean.requireForce defaults to true and neither -i nor -f given." This is a safeguard because
git cleanis a destructive operation; there's no way to recover files once removed.
- By default, Git will give a "fatal error: clean.requireForce defaults to true and neither -i nor -f given." This is a safeguard because
- Type
git clean --helpfor options.- The
--forceor-foption forces Git to remove untracked files and directories. - The
-doption allows you to remove untracked directories as well.
- The
- To remove untracked files and directories, run
git clean -fd. - Run
git status -sto verify thatfile2.js(or any other untracked files) is gone.
Managing Untracked Files with git clean
As demonstrated, git clean is used to remove untracked files from your working directory. It's distinct from git restore as git restore only deals with files that Git knows about (tracked files or files in the staging area).
Restoring Files to Specific Historical Versions
Git stores every version of a tracked file in its database. This means you can always restore a file or directory to a previous version, even if it has been deleted.
Let's illustrate by deleting a file:
- Delete
file1.js.- Instead of using the standard
rmcommand, which only removes the file from the working directory and would require you to then stage the deletion, usegit rm file1.js. git rmremoves the file from both the working directory and the staging area.
- Instead of using the standard
- Run
git status -s.- You'll see
D file1.js(greenD), indicating a deleted file in the staging area.
- You'll see
- Commit this change:
git commit -m "Delete file1.js".
Now, imagine you realize you shouldn't have deleted file1.js and want to restore it.
- Look at your commit history using
git log --oneline.- Identify the commit immediately before the deletion of
file1.js. This is the version you want to restore.
- Identify the commit immediately before the deletion of
- To restore
file1.jsto the version from the commit before the last commit:- Type
git restore --source HEAD~1 file1.js.HEAD~1refers to the commit that is one step back from the currentHEAD. You can also use the commit's unique identifier (e.g.,d601b90as shown in previous examples), butHEAD~1is often more convenient for recent history.- The
--sourceoption tellsgit restoreto get the file from the specified commit, overriding the default behavior of restoring from the next environment (staging area or last commit).
- Type
- Run
git status -s.- You will see
?? file1.js, indicating thatfile1.jshas been restored to your working directory but is now an untracked file. - You would then need to
git add file1.jsto re-track it and stage it for a new commit if you want to bring it back into your repository's tracked history.
- You will see
Key Concepts
- Git
- Version Control System (VCS)
- Repository
- Centralized vs. Distributed VCS
- Staging Area (Index)
- Commit
- Untracked Files
- Global, System, and Local Configuration
- HEAD (pointer)
- Master Branch
- Git Object Model (Blobs, Trees, Commits)
- Line Endings (CRLF, LF)
Conclusion
This tutorial covered the core principles of Git, from its basic workflow and essential commands to viewing project history. You now have a solid understanding of fundamental Git concepts, including repositories, commits, and the staging area. With this knowledge, you are ready to explore more intermediate to advanced Git concepts and enhance your version control skills.