Python • Getting Started and Tooling

Using .gitignore — Use .gitignore to exclude venv and build artifacts (conceptual)

Keep your Git repositories clean by telling Git which files to ignore automatically.

Code braces with terminal and markup symbols representing Python programming.
Inside this lesson 10 sections 5 questions 5 figures

SECTION 1

Historical Context & Motivation

When developers first began collaborating on software projects, they needed a way to share code efficiently. Early version control systems like CVS and Subversion tracked every file in a project directory, but not every file actually belonged in the shared repository. Temporary files, compiled outputs, and environment-specific configurations would clutter the codebase and create confusion for other team members. The need for a mechanism to exclude certain files from version control became clear as projects grew larger and more complex.

When Linus Torvalds created Git in 2005 to manage the Linux kernel source code, he included a simple yet powerful feature: the .gitignore file. This plain text file tells Git which files and directories it should completely disregard. For Python developers specifically, this became essential as the ecosystem evolved to rely on virtual environments, package caches, and compiled bytecode files that should never be shared between machines.

2000 • Early Version Control Challenges

Systems like CVS and Subversion lacked elegant ways to exclude files. Developers manually avoided adding unwanted files, leading to frequent mistakes and bloated repositories.

2005 • Git Is Born with .gitignore

Linus Torvalds releases Git with built-in support for .gitignore files, providing a declarative way to specify which files Git should never track.

2008 • GitHub Launches

GitHub makes Git collaboration mainstream and later introduces a repository of official .gitignore templates for dozens of languages, including Python.

2012 • Virtual Environments Become Standard

Python's virtualenv and later venv (built into Python 3.3+) make isolated environments common, creating large directories that must be excluded from repositories.

2020s • Modern Python Tooling

Tools like Poetry, pipenv, and pyproject.toml generate additional build artifacts and cache directories, making a well-crafted .gitignore more important than ever.

The central question this lesson addresses is straightforward: How do you prevent Git from tracking files that don't belong in your repository? Understanding .gitignore is a foundational skill that will save you from accidentally uploading gigabytes of unnecessary data, exposing private credentials, or creating merge conflicts caused by machine-specific files.

SECTION 2

Core Principles & Definitions

Before diving into syntax, let's establish the core ideas behind .gitignore. A .gitignore file is a plain text file placed in the root of your Git repository (or in subdirectories) that contains patterns describing which files and folders Git should ignore. The leading dot in the filename means it is a hidden file on macOS and Linux systems, so you may need to enable "show hidden files" in your file explorer to see it. Every pattern you write in this file acts as a rule that Git checks before deciding whether to track a file.

1

Tracked vs. Untracked Files

A tracked file is one that Git has been told to monitor for changes. An untracked file exists in your folder but Git doesn't know about it yet. Files in .gitignore stay permanently untracked.
2

Glob Patterns

.gitignore uses glob patterns — a simplified form of pattern matching. The asterisk * matches any sequence of characters, and ** matches directories at any depth.
3

Virtual Environments (venv)

A virtual environment is an isolated Python installation specific to your project. The venv/ folder contains hundreds of files that are machine-specific and should never be committed.
4

Build Artifacts

Build artifacts are files generated during development — compiled bytecode (__pycache__/), distribution packages (dist/), and egg-info directories. They can always be regenerated and waste space in a repository.
5

Order of Precedence

If a file is already tracked by Git, adding it to .gitignore won't remove it. You must untrack it first with git rm --cached. This is a common pitfall for beginners.
✦

KEY TAKEAWAY

Think of .gitignore like a bouncer at a club entrance. The bouncer has a list of names (patterns) and won't let anyone on that list inside (into the repository). But if someone already snuck in before the bouncer was hired, the bouncer can't kick them out — you have to do that separately with git rm --cached. The key rule: set up your .gitignore before your first commit to avoid headaches.

SECTION 3

Visual Explanation — How .gitignore Filters Files

The following diagram illustrates how Git decides whether a file gets included in your repository. When you run git add . or git status, Git checks every file in your project directory against the patterns in .gitignore. Files that match a pattern are silently skipped, while all other files are eligible for tracking.

How Git Uses .gitignore to Filter FilesProject Directorymain.pyutils.pyrequirements.txtvenv/__pycache__/dist/.gitignore.env.gitignore Filtervenv/__pycache__/dist/*.pyc.envMatch? → IgnoreNo matchMatch!Git Repository✓ main.py✓ utils.py✓ requirements.txtIgnored (Not Tracked)✗ venv/✗ __pycache__/✗ dist/✗ .envPattern Matching Rules*→ matches any characters (e.g., *.pyc)dir/→ matches an entire directory!→ negation (e.g., !important.log)#→ comment line (ignored by Git)**→ matches nested directories at any depth
Files from the project directory pass through the .gitignore filter. Files matching a pattern (shown in red) are ignored, while non-matching files (green) enter the Git repository. The pattern rules box summarizes the most common syntax.

Notice how the filter sits between your working directory and the Git repository. When you run git add, Git automatically consults the .gitignore file and skips any file that matches a listed pattern. The green path represents files that pass through and become part of your repository's history, while the red path shows files that Git pretends don't exist. This is why the .gitignore file itself should be committed — it's a set of rules your whole team needs to share.

SECTION 4

How .gitignore Pattern Matching Works

Unlike most programming languages, .gitignore doesn't use traditional code syntax. Instead, it uses glob patterns — a simple pattern language common in Unix-like operating systems. Each line in a .gitignore file represents one rule. Git reads these rules from top to bottom, and the last matching rule wins if there are conflicts. Understanding these patterns is the key to writing effective .gitignore files.

Pattern Syntax Reference

PatternMeaningExample Match
*.pycAll files ending in .pyc in any directorymodule.pyc, src/utils.pyc
venv/The entire venv directory and all contentsvenv/lib/python3.11/
__pycache__/Any __pycache__ directory at any levelsrc/__pycache__/main.cpython-311.pyc
!README.mdNegation — do NOT ignore this file even if a previous rule wouldForces README.md to be tracked
build/**/*.logAll .log files anywhere inside the build directorybuild/output/debug.log
# commentA comment line — Git ignores it entirelyNo match; used for human notes

Common .gitignore pattern syntax with examples

Processing Order Matters

Git processes .gitignore rules in order. If you write *.log on one line and then !important.log on the next, Git will first ignore all log files, then make an exception for important.log. Reversing the order would not work — the *.log rule would override the negation. This last-match-wins behavior is important to remember when debugging unexpected ignore behavior.

⚠

Common Mistake

A trailing slash matters! The pattern venv matches both a file named 'venv' and a directory named 'venv'. The pattern venv/ only matches the directory. For directories you want to exclude, always include the trailing slash for clarity.

SECTION 5

What Python Files Should Be Ignored

Python projects generate several categories of files that should never be committed to a Git repository. Understanding why each category is excluded is just as important as knowing which files to ignore. Each type of excluded file falls into one of three categories: machine-specific, regenerable, or sensitive.

Python Files to Ignore — CategorizedMachine-SpecificUnique to your computervenv/env/.vscode/.idea/Your teammate's paths,OS, and editor differ.RegenerableCan be rebuilt anytime__pycache__/*.pycdist/build/*.egg-info/Sensitive / SecretMust never be public.envsecrets.yaml*.pemconfig/local.iniAPI keys, passwords,and certificates.✓ What SHOULD Be Committed*.pySource coderequirements.txtDependencies list.gitignoreIgnore rulesREADME.mdDocumentation
Python files fall into three ignore categories: machine-specific files like virtual environments and IDE settings, regenerable files like bytecode and build outputs, and sensitive files like API keys. The green box at the bottom shows files that should always be committed.

The diagram above makes it clear that the vast majority of files generated by Python tooling fall outside what belongs in a repository. A typical venv/ folder can contain over 10,000 files and weigh hundreds of megabytes — committing that to Git would make your repository painfully slow to clone and wasteful of storage. Meanwhile, __pycache__/ directories contain compiled bytecode (.pyc files) that Python generates automatically when you import a module. These are CPU-architecture specific and regenerated on the fly, so tracking them adds zero value.

The sensitive category deserves special attention. A .env file often stores database passwords, API keys, and other secrets. If you accidentally commit this file and push it to GitHub, those secrets become visible to anyone who can see your repository — even if you delete the file later, it remains in Git's history. Adding .env to your .gitignore from day one is a critical security practice.

SECTION 6

Worked Example — Creating a .gitignore for a Python Project

Let's walk through setting up a .gitignore file for a brand-new Python project called "weather-app". This project uses a virtual environment, stores an API key in a .env file, and will eventually be packaged for distribution.

Setting Up .gitignore for weather-app

  1. 1

    Step 1 — Create the Project and Initialize Git

    First, create the project directory and initialize a Git repository. Open your terminal and run mkdir weather-app && cd weather-app && git init. At this point, your repo is empty and has no tracked files.
    An empty Git repository is created in weather-app/.git/
  2. 2

    Step 2 — Create .gitignore BEFORE Adding Files

    This is the most important step. Create the .gitignore file immediately, before creating the virtual environment or writing any code. Use your text editor or run touch .gitignore in the terminal. Open the file and begin adding patterns.
    Empty .gitignore file created in project root
  3. 3

    Step 3 — Add Virtual Environment Patterns

    Add lines to ignore common virtual environment directory names. Write the following lines in your .gitignore: venv/, env/, .venv/. Each pattern on its own line. This covers the three most common naming conventions.
    All virtual environment folders will be ignored regardless of the name used
  4. 4

    Step 4 — Add Build Artifact Patterns

    Add patterns for Python bytecode and build outputs. Include __pycache__/, *.pyc, dist/, build/, and *.egg-info/. These patterns handle the files generated by running Python modules and building packages.
    All compiled bytecode and packaging artifacts are now excluded
  5. 5

    Step 5 — Add Sensitive File Patterns

    Add .env to keep your API key secret. You might also add *.pem for SSL certificates and secrets.yaml for any configuration files containing credentials. Add a comment above this section using # Secrets so future developers understand the reasoning.
    Sensitive credentials are protected from accidental commits
  6. 6

    Step 6 — Commit .gitignore as Your First Commit

    Run git add .gitignore and then git commit -m "Add .gitignore for Python project". Making this your very first commit ensures that no future file additions will accidentally include ignored files. Now you can safely run python -m venv venv and Git will never bother tracking it.
    Your .gitignore is active and protecting your repository from the very start!
💡

Pro Tip

GitHub provides a ready-made Python .gitignore template. When you create a new repository on GitHub, you can select "Python" from the .gitignore template dropdown, and it will automatically include patterns for all common Python artifacts. You can also find it at github/gitignore.

SECTION 7

Common Patterns — Strengths & Pitfalls

Even though .gitignore is conceptually simple, there are some common mistakes and edge cases that trip up developers. The table below compares effective approaches with common pitfalls so you can avoid headaches down the road.

ScenarioGood Practice ✓Common Mistake ✗
Ignoring virtual environmentsList multiple names: venv/, env/, .venv/Only listing one name and assuming all teammates use the same convention
Timing of .gitignore creationCreate .gitignore as the very first file in the repoAdding .gitignore after already committing venv/ — the files remain tracked
Already-tracked filesRun git rm --cached <file> to untrack, then add to .gitignoreAdding pattern to .gitignore and expecting Git to auto-remove it
IDE settingsAdd .vscode/ and .idea/ to .gitignoreCommitting editor-specific settings that break other teammates' setups
Over-ignoringBe specific with patterns; use negation (!) when neededWriting * which ignores everything, including source files

Best practices vs. common mistakes with .gitignore

✦

KEY TAKEAWAY

Think of .gitignore like setting up a spam filter for your email before you subscribe to any newsletters. If you set the filter first, the spam never reaches your inbox. But if spam already made it into your inbox, you have to delete it manually — the filter only prevents future spam. Similarly, .gitignore only prevents future tracking; it doesn't remove files already in your Git history.

SECTION 8

Connection to Advanced Git Concepts

The .gitignore file is just the beginning of Git's file exclusion system. As you advance in software development, you'll encounter additional layers of ignore rules and more sophisticated ways to manage what Git tracks. The table below shows how the concepts you've learned connect to these advanced features.

FeatureWhat You Learned (Basic)Advanced Version
Ignore rules locationSingle .gitignore in project rootNested .gitignore files in subdirectories, and a global ~/.gitignore_global for user-wide rules
Secret managementAdding .env to .gitignoreUsing dedicated tools like git-crypt, environment variables in CI/CD, or vault services
Removing tracked filesgit rm --cachedRewriting history with git filter-branch or BFG Repo-Cleaner to purge sensitive data from all commits
Large binary filesIgnoring them in .gitignoreUsing Git LFS (Large File Storage) to track large binaries without bloating the repo
Dependency managementIgnoring venv/ and committing requirements.txtUsing lock files (poetry.lock, Pipfile.lock) and containerization with Docker

How basic .gitignore concepts connect to advanced Git features

One particularly useful advanced feature is the global gitignore. You can create a file like ~/.gitignore_global and configure Git to use it with git config --global core.excludesfile ~/.gitignore_global. This is the ideal place to put OS-specific files like .DS_Store (macOS) or Thumbs.db (Windows) so they're ignored across all your projects without cluttering each project's .gitignore.

SECTION 9

Practice Problems

Question 1: CONCEPTUAL

Explain in your own words why a venv/ directory should never be committed to a Git repository. What would happen if two teammates with different operating systems both committed their virtual environments?
Show answer
A virtual environment contains a full copy of the Python interpreter and all installed packages, which are specific to the operating system and file paths on the machine where they were created. If two teammates on different systems (say Windows and macOS) both committed their venv/ folders, Git would see constant merge conflicts because the binary files differ between platforms. The repository would also balloon in size by hundreds of megabytes, slowing down cloning and pulling. Instead, teammates should commit a requirements.txt file and each create their own local virtual environment using pip install -r requirements.txt.

Question 2: BASIC CALCULATION

You have a Python project with 15 source files (.py), 15 corresponding bytecode files (.pyc in __pycache__), a venv/ folder containing 8,500 files, a .env file with your API key, and a README.md. Write the complete .gitignore file that would ensure only the source files, README.md, and the .gitignore itself are tracked. How many files does .gitignore prevent from being tracked?
Show answer
Your .gitignore file should contain at minimum these lines: venv/, __pycache__/, *.pyc, and .env. This would ignore 8,500 files from venv/, 15 .pyc files, and 1 .env file, totaling 8,516 files excluded. Only 17 files would be tracked: 15 .py source files, README.md, and the .gitignore file itself. The (*.pyc pattern is technically redundant with __pycache__/ since all .pyc files live inside __pycache__, but including both is a common safety practice.

Question 3: INTERMEDIATE

A classmate accidentally committed their venv/ folder before creating a .gitignore file. Now they've added venv/ to .gitignore, but when they run git status, Git still shows changes inside venv/. What went wrong, and what exact commands should they run to fix this?
Show answer
The problem is that .gitignore only prevents Git from tracking NEW files. Since venv/ was already committed, Git continues to track it regardless of .gitignore rules. To fix this, your classmate needs to run two commands. First: git rm -r --cached venv/ which removes venv/ from Git's tracking index without deleting the actual files from disk (the --cached flag is critical here). Second: git commit -m "Remove venv from tracking" to save this change. From this point forward, the .gitignore rule will prevent venv/ from being re-added. Note that the venv/ files will still exist in the project's Git history in previous commits.

Question 4: APPLIED

You're building a Python web app for a school project with a team of three. The project uses Flask, has a virtual environment, stores database credentials in a .env file, generates logs in a logs/ directory, and two teammates use VS Code while one uses PyCharm. Write a complete .gitignore file with comments explaining each section. Include at least four categories of ignored files.
Show answer
A well-organized .gitignore for this scenario would look like this: (1) Virtual Environment section with venv/, env/, .venv/. (2) Python Bytecode section with __pycache__/ and *.pyc. (3) Secrets section with .env. (4) IDE Settings section with .vscode/ and .idea/ to cover both VS Code and PyCharm users. (5) Logs section with logs/ or *.log. Each section should have a comment line starting with # explaining the purpose. Using comments makes the file self-documenting for your team.

Question 5: CRITICAL THINKING

Consider this .gitignore file: *.log !important.log logs/ A developer places a file called important.log inside the logs/ directory. Will Git track it? Explain the order-of-operations logic that determines the outcome, and propose a fix if the developer's intent was to keep that one file tracked.
Show answer
Git will NOT track logs/important.log. Here's the reasoning: Git processes the rules in order. First, *.log ignores all .log files. Then !important.log makes an exception for important.log at the root level. However, logs/ ignores the entire logs directory. When a parent directory is ignored, Git won't even look inside it to check for negation rules. The negation !important.log cannot override the directory-level ignore rule. To fix this, the developer could remove the logs/ line and instead use logs/*.log followed by !logs/important.log. This ignores individual .log files inside logs/ while allowing the exception to work, because the directory itself is not being ignored.

SUMMARY

Summary

Summary

A .gitignore file is a plain text file in your project root that tells Git which files and directories to exclude from tracking. It uses glob patterns like * (wildcard) and dir/ (directory match) to specify exclusion rules. For Python projects, the three main categories of ignored files are machine-specific files (like venv/ and IDE settings), regenerable build artifacts (like __pycache__/ and dist/), and sensitive files (like .env containing API keys and passwords).

The most important practice is to create .gitignore before your first commit, because .gitignore only prevents future tracking — it cannot automatically untrack files already committed. If a file was committed by mistake, use git rm --cached to remove it from tracking without deleting it from disk. Remember that the last matching pattern wins when rules conflict, and that ignoring a parent directory overrides any negation rules for files inside it. With these fundamentals, you can keep your repositories clean, secure, and efficient for collaboration.

Varsity Tutors • Python • Using .gitignore — Use .gitignore to exclude venv and build artifacts (conceptual)