Git Best Practices

Now that you've learned the basics of Git and how to collaborate with others, it's time to refine your skills with some best practices. These guidelines help maintain a clean, efficient, and professional Git workflow.

Writing Good Commit Messages

Let it be this if you take one thing from this entire section. Clear and descriptive commit messages are crucial for maintaining a readable and useful Git history.

A typical Git commit message consists of two parts: a short summary line (I'll call this the "subject line") and an optional, more detailed explanatory text (the "body"). Let's go through some key guidelines for writing effective commit messages:

  1. Use imperative language in the summary line

    • The summary line is the first line of your commit message. It's what appears in the compact log view and should succinctly describe the change.
    • Good: "Add user authentication" or "Fix memory leak in image processing"
    • Bad: "Added user authentication" or "Fixing memory leak in image processing"
    • The imperative mood encourages you to describe what the commit does at a higher level, focusing on the purpose of the commit rather than just listing changes.
    • It completes the sentence: "If applied, this commit will..."
    • This approach aligns with Git's own commit messages (e.g., "Merge branch 'feature-x'")
  2. Limit the summary line to 50 characters

    • This ensures readability in various Git tools, especially those with limited display space.
    • If you're struggling to summarize in 50 characters, your commit might be too large and should be split into smaller, more focused commits.
    • Example: Instead of "Implement user authentication system with password reset functionality", use "Implement user authentication" and make a separate commit for password reset.
  3. Capitalize the summary line

    • Correct: "Add login functionality"
    • Incorrect: "add login functionality"
    • This is a simple way to maintain consistency and readability across all commits.
  4. Don't end the summary line with a period

    • Correct: "Update user profile page"
    • Incorrect: "Update user profile page."
    • The summary line is like a title or headline; it doesn't need ending punctuation.
  5. For longer messages, separate the summary from body with a blank line

    • Not all commits require a body, but when they do, the blank line is crucial for separating the summary from the body.
    • This separation is important for tools that use the Git history, as it allows them to show just the summary in compact views. Example:
    Refactor user authentication module
    
    - Extract password hashing into separate function
    - Implement password strength checker
    - Update tests to cover new functionality
    
  6. Wrap the body at 72 characters

    • This ensures proper display in various Git tools, particularly in terminal windows.
    • It improves readability by preventing long lines that require horizontal scrolling.
    • Most text editors can be configured to automatically wrap text at 72 characters for Git commit messages.
  7. Use the body to explain what and why, not how

    • The code itself shows how the changes were made, so focus on explaining the reasons for the changes and their potential impacts.
    • This is especially important for complex changes that might not be immediately obvious from the code. Example:
    Upgrade to React 18
    
    This upgrade brings performance improvements through automatic batching 
    and introduces new features like Suspense on the server.
    
    Note: This change requires updating several dependencies and modifying
    our build process. See UPGRADING.md for details.
    

What Not to Store in Git

Although most data should be backed up and saved in Git, some things should not be stored in your Git repository.

Keeping certain items out of Git helps maintain security, reduces repository bloat, and prevents conflicts. Here are some key things to avoid committing to Git:

  1. Sensitive Information

    • Passwords and API keys
    • Private encryption keys
    • Personal data (e.g., user information, email addresses)
    • Configuration files with sensitive details

    Accidentally committing these can lead to security breaches if your repository is made public or compromised.

  2. Compiled Code and Dependencies

    • Compiled binaries (.exe, .dll, .class files)
    • Dependencies and packages (e.g., node_modules for Node.js projects)

    These can be regenerated from source code and are often platform-specific. Including them bloats your repository and can cause conflicts.

  3. Large Binary Files

    • Large media files (images, videos, audio)
    • Database dumps
    • Archive files (.zip, .tar, etc.)

    Git isn't optimized for large binary files. They increase repository size and slow down cloning and pulling.

  4. Operating System and IDE-specific Files

    • .DS_Store (macOS)
    • Thumbs.db (Windows)
    • .idea/ (JetBrains IDEs)
    • .vscode/ (Visual Studio Code)

    These files are specific to individual environments and aren't necessary for the project itself.

  5. Temporary and Cache Files

    • Log files
    • Temporary files created during build processes
    • Cache directories

    These files are typically regenerated and don't need to be version controlled.

  6. User-specific Configuration Files

    • Local configuration files that vary between team members

    These often contain machine-specific paths or settings that wouldn't work for other team members.

Instead of storing these items in Git, consider these alternatives:

  • Use environment variables or secure secret management tools for sensitive information
  • Document dependencies and how to install them
  • Use Git Large File Storage (LFS) for necessary large files
  • Store large media assets on a separate file hosting service
  • Use build tools to compile code and generate necessary files

By keeping these items out of your Git repository, you maintain a cleaner, more secure, and more efficient version control system. In the next section, we'll learn how to use .gitignore to automatically prevent these types of files from being committed.

Using .gitignore

Now that we understand what shouldn't be stored in Git, let's learn how to automatically prevent these files from being committed using .gitignore. Remembering not to commit things is asking for trouble, so luckily, this will make it easy.

The .gitignore file specifies which files or directories Git should ignore. This is useful for excluding files that don't need to be version-controlled, such as compiled code, temporary files, or sensitive information.

Best Practices for .gitignore:

  1. Create a .gitignore file in your project root

    touch .gitignore
    
  2. Use global patterns

    • *.log ignores all files with the .log extension
    • build/ ignores the entire build directory
  3. Ignore OS-specific files

    • .DS_Store for macOS
    • Thumbs.db for Windows
  4. Ignore editor and IDE specific files

    • .vscode/ for Visual Studio Code
    • .idea/ for JetBrains IDEs
  5. Ignore dependency directories

    • node_modules/ for Node.js projects
    • venv/ for Python virtual environments
  6. Don't ignore .gitignore itself

    • This file should be committed to the repository

Example .gitignore file:

# This is a comment!

# Compiled source #
###################
*.com
*.class
*.dll
*.exe
*.o
*.so

# Packages #
############
# it's better to unpack these files and commit the raw source
# git has its own built in compression methods
*.7z
*.dmg
*.gz
*.iso
*.jar
*.rar
*.tar
*.zip

# Logs and databases #
######################
*.log
*.sql
*.sqlite

# OS generated files #
######################
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db

# IDE specific files #
######################
.vscode/
.idea/

# Dependency directories #
##########################
node_modules/
venv/

When to Commit and Push

Knowing when to commit and push your changes is crucial for maintaining a clean and useful Git history.

Guidelines for Committing:

  1. Commit often

    • Make small, focused commits that encompass a single logical change
  2. Commit at logical stopping points

    • When you complete a feature, fix a bug, or reach a milestone
  3. Commit when you want to record a specific state

    • Before trying an experimental change that you might want to roll back
  4. Separate refactoring and feature changes

    • This makes it easier to review and potentially revert changes

Guidelines for Pushing:

  1. Push when you're ready to share your work

    • When you want others to see or review your changes
  2. Push at the end of your workday

    • This ensures your work is backed up and accessible to team members
  3. Push before switching to a different branch

    • This prevents your unpushed work from getting mixed up with other changes

Remember, while committing is a local operation, pushing shares your changes with others. This isn't a problem most of the time, so I usually air on the side of push often so your code is safely backed up away from your computer.

Additional Best Practices

  1. Use branches for new features and bug fixes

    • This keeps the main branch stable and allows for easier code reviews
  2. Keep your branches short-lived

    • Merge or delete branches once their purpose has been fulfilled
  3. Regularly pull changes from the remote repository

    • This helps prevent merge conflicts and keeps your local copy up-to-date
  4. Use meaningful and consistent branch names

    • e.g., feature/add-login, bugfix/fix-memory-leak
  5. Don't commit generated files

    • Use .gitignore to exclude files that can be regenerated from source

Remember, these are guidelines, not strict rules. As you gain more experience with Git, you'll understand when and how to apply these practices in your projects.

In the next chapter, we'll explore advanced Git features that can further enhance your version control skills.

GitBeginner
Avatar for Niall Maher

Written by Niall Maher

Founder of Codú - The web developer community! I've worked in nearly every corner of technology businesses: Lead Developer, Software Architect, Product Manager, CTO, and now happily a Founder.

Loading

Fetching comments

Hey! 👋

Got something to say?

or to leave a comment.