Basic Git Commands: init, add, commit, status, log

Python Full Stack Web Developer Course - Week 1: Tuesday

The Foundation of Git Workflow

Git commands are like the vocabulary of a new language. While Git has over 150 commands with numerous options, mastering just a handful of essential commands will enable you to handle 90% of your version control needs. Today, we'll focus on five fundamental commands that form the backbone of the Git workflow: init, add, commit, status, and log.

Think of these commands as the basic movements in a dance. Just as a dancer must master the fundamental steps before creating elaborate choreography, a developer must understand these core Git commands before implementing complex version control strategies.

By the end of this lesson, you'll be able to create repositories, track changes, record snapshots of your code, check the status of your work, and review your project's history—essential skills for any developer working on projects of any size.

Git Init: Creating Your Repository

What is git init?

The git init command creates a new Git repository. It transforms a regular directory into a Git repository by creating a hidden .git subdirectory, which contains all the necessary metadata for the repository to function.

Think of git init as planting a seed that will grow into your project's history tree. It's the foundational step that enables Git to track the evolution of your project over time.

When to use git init

Use git init when:

Basic usage

$ git init

Initializes a new Git repository in the current directory

$ git init my_project

Creates a new directory called "my_project" and initializes a Git repository inside it

What happens behind the scenes

When you run git init, Git creates a hidden .git directory containing several files and subdirectories:

Real-world example: Creating a Python project repository

Let's create a repository for a new Python web application:

$ mkdir flask_blog_app $ cd flask_blog_app $ git init Initialized empty Git repository in /path/to/flask_blog_app/.git/

Now we can create the basic structure of our Flask blog application:

$ mkdir templates static $ touch app.py requirements.txt README.md .gitignore

Best practices for git init

Common mistakes and troubleshooting

Git Add: Staging Changes

What is git add?

The git add command adds changes from your working directory to Git's staging area (also known as the index). It tells Git which changes you want to include in your next commit.

Think of git add as a photographer selecting which elements to include in a photograph. You're not taking the picture yet (that's what git commit does), but you're composing the shot by deciding what will be in the frame.

Understanding the staging area

Git's staging area is an intermediate step between your working directory and the repository. It allows you to group related changes into distinct, logical commits—even if you made those changes across multiple files or at different times.

The staging area gives you fine-grained control over what gets committed, ensuring each commit represents a coherent unit of work. This is like a chef preparing all ingredients for a dish before cooking begins—everything is measured, chopped, and ready to go.

Basic usage

$ git add filename.py

Stages changes to a specific file

$ git add directory/

Stages changes to all files in a directory (and its subdirectories)

$ git add .

Stages all changes in the current directory (and subdirectories)

$ git add -p

Interactively stages changes in chunks, allowing you to review each change before staging

What can be staged?

Git can stage various types of changes:

Real-world example: Starting our Flask blog application

Let's continue with our Flask blog application example. First, let's add some basic content to our files:

For app.py:

from flask import Flask, render_template app = Flask(__name__) @app.route('/') def home(): return render_template('home.html', title='Flask Blog') if __name__ == '__main__': app.run(debug=True)

For requirements.txt:

Flask==2.0.1

For README.md:

# Flask Blog Application A simple blog application built with Flask. ## Setup 1. Install requirements: `pip install -r requirements.txt` 2. Run the application: `python app.py`

For .gitignore:

# Python __pycache__/ *.py[cod] *$py.class *.so .env venv/ ENV/ # Flask instance/ .webassets-cache # IDE .idea/ .vscode/ *.swp *.swo

Now, let's stage these files:

$ git add app.py requirements.txt README.md .gitignore

This selectively adds our initial files to the staging area, ready to be committed.

Advanced git add techniques

Interactive staging

The -p (or --patch) option allows you to interactively select portions of a file to stage. This is useful when you've made multiple unrelated changes to a single file:

$ git add -p app.py

Git will break the changes into "hunks" and ask whether you want to stage each one

Staging by pattern

You can use wildcards to stage multiple files that match a pattern:

$ git add *.py

Stages all Python files in the current directory (but not subdirectories)

$ git add "*.py"

Stages all Python files in the current directory and all subdirectories

Best practices for git add

Common mistakes and troubleshooting

Git Commit: Recording Changes

What is git commit?

The git commit command creates a snapshot of your staged changes, saving them permanently to your Git repository's history. Each commit is like a savepoint in your project, capturing the state of your files at a specific point in time.

Think of git commit as a photographer actually taking the picture after carefully composing the shot with git add. Once taken, this snapshot becomes a permanent part of your project's timeline that you can always return to.

The anatomy of a commit

A Git commit consists of:

Basic usage

$ git commit -m "Add initial Flask application structure"

Creates a commit with the specified message

$ git commit

Opens a text editor for a more detailed commit message

$ git commit -a -m "Update Flask routes"

Automatically stages all modified (but not new) files and commits them

Crafting meaningful commit messages

A good commit message is like a well-written chapter title in a book—it helps readers understand what's inside without having to read the whole thing. Effective commit messages follow these guidelines:

For more significant commits, use a multi-line message format:

Add user authentication system - Implement login and registration forms - Add password hashing with bcrypt - Create user model with validation - Set up session management for logged-in users Closes #42

Real-world example: Committing our Flask blog app

Let's commit the files we staged earlier for our Flask blog application:

$ git commit -m "Create initial Flask blog application structure" [main (root-commit) a1b2c3d] Create initial Flask blog application structure 4 files changed, 28 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 app.py create mode 100644 requirements.txt

Now let's continue building our application by creating a basic template:

$ mkdir -p templates static/css $ touch templates/home.html static/css/style.css

For templates/home.html:

<!DOCTYPE html> <html> <head> <title>{{ title }}</title> <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}"> </head> <body> <header> <h1>Flask Blog</h1> <nav> <ul> <li><a href="/">Home</a></li> <li><a href="/about">About</a></li> </ul> </nav> </header> <main> <h2>Welcome to Flask Blog</h2> <p>This is a simple blog built with Flask.</p> </main> <footer> <p>© 2025 Flask Blog</p> </footer> </body> </html>

For static/css/style.css:

body { font-family: Arial, sans-serif; line-height: 1.6; margin: 0; padding: 0; color: #333; } header { background: #333; color: #fff; padding: 1rem; } header h1 { margin: 0; } nav ul { padding: 0; list-style: none; display: flex; } nav ul li { margin-right: 1rem; } nav a { color: #fff; text-decoration: none; } main { padding: 1rem; } footer { background: #333; color: #fff; text-align: center; padding: 1rem; position: fixed; bottom: 0; width: 100%; }

Now let's stage and commit these new files:

$ git add templates/ static/ $ git commit -m "Add basic HTML template and CSS styling"

Advanced commit techniques

Amending commits

If you need to fix a mistake in your most recent commit or add forgotten changes, you can use the --amend option:

$ git commit --amend -m "Updated commit message"

Changes the message of the most recent commit

$ git add forgotten_file.py $ git commit --amend --no-edit

Adds a forgotten file to the most recent commit without changing the commit message

Important: Never amend commits that have been pushed to a shared repository unless you're absolutely sure no one has based work on them.

Empty commits

Sometimes you might want to create a commit without any actual code changes, such as marking the start of a new development phase:

$ git commit --allow-empty -m "Begin refactoring phase"

Creates a commit with a message but no content changes

Best practices for git commit

Common mistakes and troubleshooting

Git Status: Checking Repository State

What is git status?

The git status command shows the current state of your working directory and staging area. It lets you see which changes have been staged, which haven't, and which files aren't being tracked by Git.

Think of git status as a dashboard or control panel for your Git workflow. It provides real-time information about what's happening in your repository, helping you make informed decisions about what to do next.

Why git status is essential

Regular use of git status helps you:

Basic usage

$ git status

Shows the full status output

$ git status -s

Shows a simplified, compact status output

Understanding git status output

The output of git status includes several sections:

Branch information
On branch main

Shows which branch you're currently on

Changes to be committed
Changes to be committed: (use "git restore --staged <file>..." to unstage) new file: templates/home.html modified: app.py

Green files are staged and ready to be committed

Changes not staged for commit
Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: README.md

Red files have been modified but not yet staged

Untracked files
Untracked files: (use "git add <file>..." to include in what will be committed) static/js/main.js .env.example

Red files that Git doesn't yet track

Real-world example: Checking status of our Flask blog app

Let's continue with our Flask blog application. Let's add an about page and check the status:

First, let's create templates/about.html:

<!DOCTYPE html> <html> <head> <title>About - Flask Blog</title> <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}"> </head> <body> <header> <h1>Flask Blog</h1> <nav> <ul> <li><a href="/">Home</a></li> <li><a href="/about">About</a></li> </ul> </nav> </header> <main> <h2>About This Blog</h2> <p>This is a simple demonstration blog built with Flask.</p> <p>It was created as part of the Python Full Stack Developer Course.</p> </main> <footer> <p>© 2025 Flask Blog</p> </footer> </body> </html>

Also, let's modify app.py to add the about route:

from flask import Flask, render_template app = Flask(__name__) @app.route('/') def home(): return render_template('home.html', title='Flask Blog') @app.route('/about') def about(): return render_template('about.html') if __name__ == '__main__': app.run(debug=True)

Now, let's run git status to see what Git reports:

$ git status On branch main Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: app.py Untracked files: (use "git add <file>..." to include in what will be committed) templates/about.html no changes added to commit (use "git add" and/or "git commit -a")

This tells us:

Advanced git status techniques

Short status format

For a more compact view, especially useful in larger repositories:

$ git status -s M app.py ?? templates/about.html

In the short format:

Status with ignored files

To see ignored files that match .gitignore patterns:

$ git status --ignored

Shows status including files that are being ignored

Best practices for git status

Common mistakes and troubleshooting

Git Log: Viewing Commit History

What is git log?

The git log command displays the commit history of your repository, showing who made changes, when they were made, and what was changed. It allows you to explore the evolution of your project over time.

Think of git log as a time machine that lets you travel through your project's past. It's like reading a journal of your project's development, with entries for each significant change along the way.

Why git log is powerful

Git log helps you:

Basic usage

$ git log

Shows the commit history with details

$ git log --oneline

Shows a compact commit history with one line per commit

$ git log -p

Shows the commit history with the diff (changes) for each commit

Understanding git log output

The standard git log output includes:

commit a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0 Author: Jane Doe <jane@example.com> Date: Mon Apr 15 12:34:56 2025 -0700 Create initial Flask blog application structure

Each commit shows: unique hash identifier, author, date, and commit message

Real-world example: Viewing history of our Flask blog app

Let's add and commit our changes to the Flask blog app, then examine the history:

$ git add app.py templates/about.html $ git commit -m "Add about page and route"

Now, let's view our commit history:

$ git log commit f1e2d3c4b5a6978685746352413f2g1h (HEAD -> main) Author: Jane Doe <jane@example.com> Date: Mon Apr 15 14:30:00 2025 -0700 Add about page and route commit b9c8d7e6f5a4b3c2d1e0f9g8h7i6j5k4l3m2n1 Author: Jane Doe <jane@example.com> Date: Mon Apr 15 13:45:00 2025 -0700 Add basic HTML template and CSS styling commit a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0 Author: Jane Doe <jane@example.com> Date: Mon Apr 15 12:34:56 2025 -0700 Create initial Flask blog application structure

For a more compact view:

$ git log --oneline f1e2d3c (HEAD -> main) Add about page and route b9c8d7e Add basic HTML template and CSS styling a1b2c3d Create initial Flask blog application structure

Advanced git log techniques

Viewing changes in commits

To see the actual code changes in each commit:

$ git log -p

Shows commits with the diff of changes

$ git log -p filename.py

Shows commits that affected a specific file

Limiting the output

In larger repositories, you might want to limit the output:

$ git log -n 5

Shows only the 5 most recent commits

$ git log --since="2 weeks ago"

Shows commits from the last two weeks

$ git log --author="Jane"

Shows commits by a specific author

Graphical representations

For visualizing branching and merging:

$ git log --graph --oneline --all

Shows a text-based graph of the commit history, including all branches

Customizing the output format

You can create custom formats for the log output:

$ git log --pretty=format:"%h - %an, %ar : %s"

Shows a customized log format with abbreviated hash, author name, relative date, and subject

Best practices for git log

Common aliases for git log

Many developers create aliases for common log formats:

$ git config --global alias.lg "log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"

Creates a colorized, graphical log alias that you can use with git lg

Putting It All Together: A Basic Git Workflow

Now that we understand the five essential Git commands, let's see how they fit together in a typical workflow:

  1. Initialize a repository (once at the beginning):
    $ mkdir new_project $ cd new_project $ git init
  2. Create or modify files (make changes to your project):
    # Work on your files using your text editor or IDE
  3. Check status (see what's changed):
    $ git status
  4. Stage changes (prepare for commit):
    $ git add filename.py # Or to stage all changes: $ git add .
  5. Check status again (verify what's staged):
    $ git status
  6. Commit changes (save a snapshot):
    $ git commit -m "Add user authentication system"
  7. View history (review what's been done):
    $ git log
  8. Repeat steps 2-7 as you continue development.

Example: Complete workflow with our Flask blog

Let's add a new feature to our Flask blog: a contact page with a simple form.

  1. First, check the current status:
    $ git status On branch main nothing to commit, working tree clean
  2. Create a new template for the contact page:
    $ touch templates/contact.html

    Add content to templates/contact.html:

    <!DOCTYPE html> <html> <head> <title>Contact - Flask Blog</title> <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}"> </head> <body> <header> <h1>Flask Blog</h1> <nav> <ul> <li><a href="/">Home</a></li> <li><a href="/about">About</a></li> <li><a href="/contact">Contact</a></li> </ul> </nav> </header> <main> <h2>Contact Us</h2> <form method="POST" action="/contact"> <div> <label for="name">Name:</label> <input type="text" id="name" name="name" required> </div> <div> <label for="email">Email:</label> <input type="email" id="email" name="email" required> </div> <div> <label for="message">Message:</label> <textarea id="message" name="message" rows="5" required></textarea> </div> <button type="submit">Send Message</button> </form> </main> <footer> <p>© 2025 Flask Blog</p> </footer> </body> </html>
  3. Update the app.py file to add the contact route:
    from flask import Flask, render_template, request, redirect, url_for, flash app = Flask(__name__) app.secret_key = 'your_secret_key' # Required for flash messages @app.route('/') def home(): return render_template('home.html', title='Flask Blog') @app.route('/about') def about(): return render_template('about.html') @app.route('/contact', methods=['GET', 'POST']) def contact(): if request.method == 'POST': name = request.form.get('name') email = request.form.get('email') message = request.form.get('message') # In a real application, you would process the form data here # (e.g., send an email, save to database, etc.) flash('Thank you for your message! We will get back to you soon.') return redirect(url_for('contact')) return render_template('contact.html') if __name__ == '__main__': app.run(debug=True)
  4. Also update the home.html and about.html templates to include the contact link in the nav menu.
  5. Check the status to see our changes:
    $ git status On branch main Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: app.py modified: templates/about.html modified: templates/home.html Untracked files: (use "git add <file>..." to include in what will be committed) templates/contact.html no changes added to commit (use "git add" and/or "git commit -a")
  6. Stage all the changes:
    $ git add .
  7. Check status again to verify what's staged:
    $ git status On branch main Changes to be committed: (use "git restore --staged <file>..." to unstage) modified: app.py modified: templates/about.html modified: templates/home.html new file: templates/contact.html
  8. Commit the changes:
    $ git commit -m "Add contact page with form"
  9. View the commit history:
    $ git log --oneline a7b6c5d Add contact page with form f1e2d3c Add about page and route b9c8d7e Add basic HTML template and CSS styling a1b2c3d Create initial Flask blog application structure

Hands-on Exercises

Exercise 1: Basic Repository Setup

  1. Create a new directory called "python_exercises" on your computer
  2. Initialize a Git repository in this directory
  3. Create a README.md file with a description of what this repository will contain
  4. Create a simple Python script called calculator.py with a function to add two numbers
  5. Check the status of your repository
  6. Stage both files
  7. Commit the files with an appropriate message
  8. View your commit history

Exercise 2: Making Changes and Viewing Differences

  1. Continuing from the previous exercise, add a subtraction function to calculator.py
  2. Check the status to see the modified file
  3. Use git diff to see what changes you've made
  4. Stage the changes
  5. Commit with an appropriate message
  6. Add multiplication and division functions
  7. Stage and commit these changes
  8. Use git log -p to see the changes in each commit

Exercise 3: Selective Staging

  1. Add a docstring at the top of calculator.py describing the module
  2. Add a new file called test_calculator.py with basic tests for your functions
  3. Check the status to see all changes
  4. Stage only the docstring changes in calculator.py using git add -p
  5. Commit these changes with a message about adding documentation
  6. Stage and commit the test file separately
  7. View your commit history in a compact format using git log --oneline

Key Takeaways

By mastering these fundamental Git commands, you've established a solid foundation for version control in your development workflow. As you continue learning, you'll build upon these basics to leverage Git's more advanced features for branching, collaboration, and complex project management.

Assignment: Basic Git Commands Practice

Create a simple Python project with multiple files and track it using Git:

  1. Initialize a new Git repository
  2. Create the following files:
    • main.py - A simple menu-driven program that calls functions from other modules
    • math_operations.py - A module with basic math functions (add, subtract, multiply, divide)
    • string_operations.py - A module with basic string functions (reverse, count_vowels, is_palindrome)
    • README.md - Documentation about your project
    • .gitignore - Include patterns for Python-specific files to ignore
  3. Make at least 5 meaningful commits showing the progression of your project
  4. Use descriptive commit messages following best practices
  5. Include a screenshot or copy of your git log output showing your commit history

Bonus challenges:

Additional Resources