# Code Style and Conventions Standards for Git
This document defines the coding style and conventions standards for contributing to the Git project. Adhering to these standards ensures consistency, readability, maintainability, and reduces the likelihood of errors and security vulnerabilities. These guidelines are tailored for the latest version of Git and leverage modern development practices.
## 1. General Principles
### 1.1. Consistency is Key
* **Do This:** Maintain a consistent style throughout the codebase. Follow the existing style of the file you are modifying.
* **Don't Do This:** Introduce new styles or deviate unnecessarily from established patterns.
**Why:** Consistent code is much easier to read and understand, reducing cognitive load for developers. Consistency also simplifies automated code analysis and refactoring.
### 1.2. Readability Matters
* **Do This:** Write code that is clear and easy to understand, even for someone unfamiliar with the specific functionality. Use meaningful variable and function names. Add comments to explain complex logic or non-obvious behavior.
* **Don't Do This:** Write overly clever or cryptic code that is difficult to decipher. Avoid excessive nesting or complicated expressions.
**Why:** Readable code is easier to maintain and debug. It reduces the time required to understand the code and minimizes the risk of introducing errors during modifications.
### 1.3. Simplicity is a Virtue
* **Do This:** Strive for simplicity in design and implementation. Choose the simplest approach that meets the requirements.
* **Don't Do This:** Over-engineer solutions or introduce unnecessary complexity.
**Why:** Simple code is easier to understand, test, and maintain. It reduces the risk of introducing bugs and makes it easier to adapt to future changes.
### 1.4. Security Conscious
* **Do This:** Always be mindful of potential security vulnerabilities. Follow secure coding practices to prevent common attacks such as buffer overflows, format string bugs, and command injection.
* **Don't Do This:** Assume that user input is safe or that internal functions are always called correctly.
**Why:** Security vulnerabilities can have serious consequences. Secure coding practices are essential to protect Git from malicious attacks.
### 1.5. Performance Aware
* **Do This:** Write code that is efficient and performs well. Consider the performance implications of your design choices.
* **Don't Do This:** Introduce performance bottlenecks or use inefficient algorithms.
**Why:** Git operates on very large repositories. Performance impacts the overall user experience. Inefficiencies can quickly become magnified.
## 2. Formatting
### 2.1. Indentation
* **Do This:** Use tabs for indentation. Set your editor to display tabs as 8 spaces.
* **Don't Do This:** Use spaces for indentation.
**Why:** Tabs provide flexibility, allowing each developer to configure their editor to display tabs as they prefer. This avoids issues with inconsistent indentation across different environments. The Git project has historically used tabs.
### 2.2. Line Length
* **Do This:** Keep lines of code reasonably short, ideally no more than 80 characters.
* **Don't Do This:** Write excessively long lines that are difficult to read on smaller screens or in diff views.
**Why:** Shorter lines are easier to read and improve code visibility in diffs.
### 2.3. Whitespace
* **Do This:** Use whitespace to improve readability. Add spaces around operators, after commas, and in other appropriate places.
* **Don't Do This:** Omit whitespace unnecessarily or use inconsistent spacing.
**Why:** Whitespace makes code easier to scan and understand, improving overall readability.
"""c
// Good:
int result = a + b * c;
// Bad:
int result=a+b*c;
"""
### 2.4. Braces
* **Do This:** Place opening braces on the same line as the statement they belong to, except for function definitions.
* **Don't Do This:** Place opening braces on a new line.
**Why:** This style is consistent with the historical conventions of the Git project.
"""c
// Good:
if (condition) {
// Code
}
int foo() {
// Code
}
// Bad:
if (condition)
{
// Code
}
int foo()
{
// Code
}
"""
### 2.5. Blank Lines
* **Do This:** Use blank lines to separate logical blocks of code and improve readability.
* **Don't Do This:** Omit blank lines or use them inconsistently.
**Why:** Blank lines help to visually separate different parts of the code, making it easier to follow the logic.
## 3. Naming Conventions
### 3.1. Variables
* **Do This:** Use descriptive and meaningful variable names.
* **Don't Do This:** Use single-character variable names (except for loop counters), or ambiguous abbreviations.
**Why:** Clear variable names make it easier to understand the purpose of each variable and how it is used.
"""c
// Good:
int num_bytes_read;
char *buffer;
// Bad:
int n;
char *buf;
"""
### 3.2. Functions
* **Do This:** Use descriptive function names that clearly indicate what the function does. Function names should typically start with a lowercase letter. Use verbs to describe the action performed by the function.
* **Don't Do This:** Use vague or ambiguous function names.
**Why:** Clear function names make it easier to understand the purpose of each function and how it is used.
"""c
// Good:
int read_data(char *buffer, int max_bytes);
void process_input(const char *input);
// Bad:
int do_something(char *buffer, int max_bytes);
void handle_stuff(const char *input);
"""
### 3.3. Constants
* **Do This:** Use uppercase letters with underscores to separate words for constants.
* **Don't Do This:** Use lowercase letters or mixed case for constants.
**Why:** This convention clearly distinguishes constants from variables.
"""c
// Good:
#define MAX_BUFFER_SIZE 1024
const int DEFAULT_TIMEOUT = 5;
// Bad:
#define maxBufferSize 1024
const int defaultTimeout = 5;
"""
### 3.4. Types
* **Do This:** Follow existing type naming conventions in the Git codebase. Use typedefs to create aliases for complex types.
* **Don't Do This:** Invent new type naming conventions or use inconsistent naming for types.
**Why:** Consistent type naming improves code readability and maintainability.
## 4. Comments
### 4.1. General Guidelines
* **Do This:** Write comments to explain complex logic, non-obvious behavior, or design decisions. Keep comments up-to-date with the code.
* **Don't Do This:** Write comments that simply repeat what the code does, or that are outdated or misleading.
**Why:** Comments should provide additional information that is not readily apparent from the code itself. They should explain *why* the code is written the way it is, not just *what* it does.
### 4.2. Comment Style
* **Do This:** Use "/* ... */" for multi-line comments and "//" for single-line comments (in newer C files where allowed, older files might predominantly use "/* ... */").
* **Don't Do This:** Use inconsistent comment styles.
"""c
// Good:
/*
* This function reads data from the input stream and
* stores it in the buffer.
*/
int read_data(char *buffer, int max_bytes) {
// Check for null pointer.
if (buffer == NULL) {
return -1;
}
...
}
// Older style, still acceptable when consistent within a file:
/*
* This function reads data from the input stream and
* stores it in the buffer.
*/
int read_data(char *buffer, int max_bytes) {
/* Check for null pointer. */
if (buffer == NULL) {
return -1;
}
...
}
// Bad:
// Reads data from input stream.
int read_data(char *buffer, int max_bytes) {
if (buffer == NULL) { // Check for null.
return -1;
}
...
}
"""
### 4.3. Header Comments
* **Do This:** Include a header comment at the beginning of each file describing the purpose of the file and any important design decisions. Include copyright and licensing information.
* **Don't Do This:** Omit header comments or include incomplete or inaccurate information.
"""c
/*
* Copyright (C) 2023 The Git Development Community
*
* This file contains functions for parsing Git objects.
*
* ... (more detailed description) ...
*/
"""
## 5. Error Handling
### 5.1. Check Return Values
* **Do This:** Always check the return values of functions that can fail. Handle errors gracefully.
* **Don't Do This:** Ignore return values or assume that functions always succeed.
**Why:** Failing to check return values can lead to unexpected behavior, data corruption, or security vulnerabilities.
"""c
// Good:
int result = read_data(buffer, max_bytes);
if (result < 0) {
// Handle error
fprintf(stderr, "Error reading data: %d\n", result);
return -1;
}
// Bad:
read_data(buffer, max_bytes); // Ignoring return value
"""
### 5.2. Error Messages
* **Do This:** Provide informative error messages that help users understand what went wrong and how to fix it.
* **Don't Do This:** Use generic or unhelpful error messages. Avoid exposing sensitive information in error messages.
**Why:** Informative error messages make it easier to diagnose and resolve problems.
### 5.3. Resource Management
* **Do This:** Always free allocated resources (memory, file descriptors, etc.) when they are no longer needed. Use "defer" or similar mechanisms for automatic resource cleanup where appropriate.
* **Don't Do This:** Leak resources, leading to memory leaks or other problems.
**Why:** Resource leaks can degrade performance and lead to system instability.
"""c
// Correct Resource allocation and release
int *ptr = malloc(sizeof(int));
if (ptr == NULL) {
perror("malloc failed");
return -1; // Or some other appropriate error handling
}
// Use ptr...
free(ptr);
ptr = NULL; // Prevent dangling pointer
"""
## 6. Data Structures
### 6.1. Choosing the Right Data Structure
* **Do This:** Select the most appropriate data structure for the task at hand, considering factors such as performance, memory usage, and ease of use. Use existing data structures in the Git codebase where possible.
* **Don't Do This:** Use inefficient or inappropriate data structures.
**Why:** Using the right data structure can significantly improve performance and reduce memory usage.
### 6.2. Memory Management
* **Do This:** Manage memory carefully to avoid leaks and fragmentation. Use "xmalloc", "xcalloc", and "xrealloc" from the "git" library instead of standard "malloc", "calloc", and "realloc".
* **Don't Do This:** Allocate memory without freeing it, or free memory multiple times.
**Why:** Git provides its own memory management functions that include error checking and can improve performance. Double frees, or use-after-free bugs are a major source of security vulnerabilities.
### 6.3. Avoiding Buffer Overflows
* **Do This:** Always check buffer sizes before writing to them. Use functions like "snprintf" to prevent buffer overflows.
* **Don't Do This:** Use functions like "sprintf" or "strcpy" that are vulnerable to buffer overflows.
**Why:** Buffer overflows are a common source of security vulnerabilities.
"""c
// Good:
snprintf(buffer, buffer_size, "The value is: %s", value);
// Bad:
sprintf(buffer, "The value is: %s", value); // Potential buffer overflow
"""
## 7. Git Specific Guidelines
### 7.1. Object Model
* **Do This:** When working with Git's object model (commits, trees, blobs), use the existing Git API functions for creating, reading, and writing objects. Use "oid" structures correctly for object IDs.
* **Don't Do This:** Manually manipulate object files or try to bypass the Git API.
**Why:** The Git API provides a consistent and reliable way to interact with the object model, ensuring data integrity and compatibility.
"""c
#include "cache.h" // For struct object_id and object functions
struct object_id oid;
if (get_oid("HEAD", &oid)) {
fprintf(stderr, "Failed to resolve HEAD\n");
return 1;
}
printf("HEAD's OID is %s\n", oid_to_hex(&oid));
"""
### 7.2. Index Files
* **Do This:** Use appropriate functions to work with the index file (staging area). Understand the format and structure of the index file.
* **Don't Do This:** Directly modify the index file without using the Git API.
**Why:** The index file is a core component of Git's architecture. Incorrect modification can lead to repository corruption.
### 7.3. Configuration
* **Do This:** Use the Git configuration API to read and write configuration values. Use appropriate scopes (system, global, local) for configuration settings.
* **Don't Do This:** Directly modify the configuration files.
**Why:** The Git configuration API provides a consistent and reliable way to manage configuration settings.
### 7.4. Command-Line Interface
* **Do This:** Adhere to the existing conventions for command-line options and arguments. Provide clear and concise help messages for new commands.
* **Don't Do This:** Introduce inconsistent or confusing command-line options.
**Why:** A consistent and well-designed command-line interface makes Git easier to use.
### 7.5. File System Interactions
* **Do This:** Use the appropriate Git API functions for interacting with the file system, such as "xstat", "xmkdir", and "xunlink". Be aware of potential security implications when handling file paths.
* **Don't Do This:** Use standard library functions like "stat", "mkdir", and "unlink" directly, as they may not be compatible with Git's internal workings or security requirements.
**Why:** The Git API functions provide a consistent and secure way to interact with the file system.
## 8. Testing
### 8.1. Unit Tests
* **Do This:** Write unit tests to verify the correctness of individual functions and modules. Cover all important code paths and edge cases.
* **Don't Do This:** Omit unit tests or write incomplete or inadequate tests.
**Why:** Unit tests help to ensure that the code works as expected and prevent regressions.
### 8.2. Integration Tests
* **Do This:** Write integration tests to verify the interaction between different parts of the system.
* **Don't Do This:** Rely solely on unit tests without verifying the overall system behavior.
**Why:** Integration tests help to ensure that the different parts of the system work together correctly.
### 8.3. Test-Driven Development (TDD)
* **Do This:** Consider using TDD to write tests before writing the code.
* **Don't Do This:** Treat testing as an afterthought.
**Why:** TDD can help to improve the design of the code and ensure that it is testable.
## 9. Deprecated Features and Anti-Patterns
### 9.1. Avoid Legacy Functions
* **Do This:** Prefer modern, safe alternatives to older, potentially unsafe functions. Specifically, avoid "strcpy", "sprintf", and similar functions prone to buffer overflows.
* **Don't Do This:** Continue using deprecated functions without a strong justification.
**Why:** Using newer functions and libraries usually provides better security and performance.
### 9.2. Avoid Global Variables
* **Do This:** Minimize the use of global variables. Prefer passing data explicitly between functions.
* **Don't Do This:** Rely heavily on global variables, as this makes code harder to understand and test.
**Why:** Global variables introduce tight coupling and make it harder to reason about code.
### 9.3. Avoid Magic Numbers
* **Do This:** Define constants for all literal values that have a specific meaning.
* **Don't Do This:** Use "magic numbers" directly in the code.
**Why:** Magic numbers make code harder to understand and maintain.
"""c
// Good:
#define MAX_CONNECTIONS 100
// Bad:
for (int i = 0; i < 100; i++) { // What does 100 mean?
...
}
"""
## 10. Security Best Practices
### 10.1. Input Validation
* **Do This:** Validate all input data to ensure that it is within the expected range and format.
* **Don't Do This:** Trust user input without validation.
**Why:** Input validation helps to prevent injection attacks and other security vulnerabilities.
### 10.2. Principle of Least Privilege
* **Do This:** Grant users only the minimum privileges necessary to perform their tasks.
* **Don't Do This:** Grant excessive privileges.
**Why:** The principle of least privilege helps to limit the impact of security breaches.
### 10.3. Secure Random Number Generation
* **Do This:** Use a cryptographically secure random number generator (CSRNG) for generating random numbers that are used for security purposes.
* **Don't Do This:** Use a standard pseudo-random number generator (PRNG) for security-sensitive applications.
**Why:** Standard PRNGs are not suitable for security purposes because their output is predictable.
### 10.4. Proper Encoding
* **Do This:** Encode data properly when passing it between different systems or components. This is especially important when dealing with web-based components and APIs.
* **Don't Do This:** Neglect encoding which could lead to Cross-Site Scripting (XSS) or other injection-based vulnerabilities.
**Why:** Encoding ensures data integrity and prevents misinterpretation or malicious manipulation.
This document will be updated periodically to reflect the latest best practices and changes in the Git project. Continuous learning and adaptation are essential for writing high-quality and secure code.
danielsogl
Created Mar 6, 2025
This guide explains how to effectively use .clinerules
with Cline, the AI-powered coding assistant.
The .clinerules
file is a powerful configuration file that helps Cline understand your project's requirements, coding standards, and constraints. When placed in your project's root directory, it automatically guides Cline's behavior and ensures consistency across your codebase.
Place the .clinerules
file in your project's root directory. Cline automatically detects and follows these rules for all files within the project.
# Project Overview project: name: 'Your Project Name' description: 'Brief project description' stack: - technology: 'Framework/Language' version: 'X.Y.Z' - technology: 'Database' version: 'X.Y.Z'
# Code Standards standards: style: - 'Use consistent indentation (2 spaces)' - 'Follow language-specific naming conventions' documentation: - 'Include JSDoc comments for all functions' - 'Maintain up-to-date README files' testing: - 'Write unit tests for all new features' - 'Maintain minimum 80% code coverage'
# Security Guidelines security: authentication: - 'Implement proper token validation' - 'Use environment variables for secrets' dataProtection: - 'Sanitize all user inputs' - 'Implement proper error handling'
Be Specific
Maintain Organization
Regular Updates
# Common Patterns Example patterns: components: - pattern: 'Use functional components by default' - pattern: 'Implement error boundaries for component trees' stateManagement: - pattern: 'Use React Query for server state' - pattern: 'Implement proper loading states'
Commit the Rules
.clinerules
in version controlTeam Collaboration
Rules Not Being Applied
Conflicting Rules
Performance Considerations
# Basic .clinerules Example project: name: 'Web Application' type: 'Next.js Frontend' standards: - 'Use TypeScript for all new code' - 'Follow React best practices' - 'Implement proper error handling' testing: unit: - 'Jest for unit tests' - 'React Testing Library for components' e2e: - 'Cypress for end-to-end testing' documentation: required: - 'README.md in each major directory' - 'JSDoc comments for public APIs' - 'Changelog updates for all changes'
# Advanced .clinerules Example project: name: 'Enterprise Application' compliance: - 'GDPR requirements' - 'WCAG 2.1 AA accessibility' architecture: patterns: - 'Clean Architecture principles' - 'Domain-Driven Design concepts' security: requirements: - 'OAuth 2.0 authentication' - 'Rate limiting on all APIs' - 'Input validation with Zod'
# Core Architecture Standards for Git This document outlines the core architectural standards for contributing to the Git project. It provides guidelines for maintaining consistency, readability, performance, and security across the codebase. These standards are designed to ensure that Git remains a robust and reliable tool for version control. It is imperative that you consult official Git documentation and release notes to stay up-to-date on the latest features and best practices. ## 1. Fundamental Architectural Patterns Git's core is built around a few fundamental architectural patterns. Understanding these is crucial for contributing effectively. ### 1.1. Content-Addressable Storage * **Description:** Git utilizes a content-addressable storage model built around SHA-1 (though transitioning towards SHA-256). Every object (blobs, trees, commits) is hashed, and the hash becomes its unique identifier. * **Why:** Ensures data integrity and efficient storage. Identical content is only stored once. **Do This:** * Always ensure that new data structures or objects are integrated with the content-addressable storage mechanism. * When refactoring existing code, preserve content-addressability. * Use Git's internal functions for hashing and object storage. **Don't Do This:** * Do not circumvent the content-addressable storage. * Avoid introducing duplicate storage of identical content. * Don't use custom hashing algorithms unless explicitly justified and approved by the Git maintainers. **Code Example:** """c // Example of storing a blob object in Git (simplified) #include "cache.h" #include "object.h" int store_blob(const void *data, size_t len) { struct object_id oid; enum object_type type = OBJ_BLOB; if (write_object_file(data, len, type, &oid) < 0) { return -1; // Error storing the object } printf("Stored blob with object ID: %s\n", oid_to_hex(&oid)); return 0; } // Usage int main() { const char *blob_content = "This is a blob of text."; size_t blob_len = strlen(blob_content); if (store_blob(blob_content, blob_len) == 0) { printf("Blob stored successfully.\n"); } else { printf("Failed to store blob.\n"); } return 0; } """ ### 1.2. Directed Acyclic Graph (DAG) * **Description:** The commit history is represented as a DAG. Commits link to their parent(s), forming a graph where cycles are impossible. * **Why:** Provides a clear and auditable history of changes. Facilitates branching and merging. **Do This:** * Preserve the DAG structure when implementing new commands or features related to history traversal. * Ensure that any modifications to the commit history (e.g., "git rebase") maintain the integrity of the DAG. **Don't Do This:** * Do not introduce cycles into the commit graph. * Avoid creating orphaned commits (commits not reachable from a reference). **Code Example (Conceptual):** """c // Simplified example of creating a new commit (Illustrative) struct commit { struct object_id oid; // SHA-1 hash of the commit object struct object_id *parents; // Array of parent commit OIDs char *message; // Commit message // ... other commit metadata }; // When creating a new commit: // 1. Create the commit object with pointers to parent commit(s). // 2. Hash the commit object to obtain its OID. // 3. Store the commit object. """ ### 1.3 Index (Staging Area) * **Description:** The index acts as a staging area between the working directory and the repository. It holds a list of files with their staged content and metadata. * **Why:** Allows users to selectively stage changes before committing. Optimizes commit creation. **Do This:** * When modifying the index structure or logic, carefully consider the performance implications. * Ensure that the index remains consistent with the working directory and the object database. **Don't Do This:** * Avoid introducing race conditions when updating the index concurrently. * Don't create inconsistencies between the index and committed objects. **Code Example (Conceptual):** """c // Example of an index entry (simplified) struct index_entry { struct object_id oid; // SHA-1 hash of the file content char *path; // Path to the file in the working directory unsigned int flags; // Metadata (e.g., file mode, stage) }; // The index is essentially an array of these entries, // sorted for efficient lookup. """ ## 2. Project Structure and Organization Git's codebase is modular and organized into several key directories. Understanding this structure is vital. ### 2.1. Core Directories * "./": Top-level directory containing the main Git executable ("git"), scripts, and documentation. * "./builtin": Contains built-in Git commands implemented in C. * "./contrib": Holds contributed tools and scripts that are not part of the core Git functionality. * "./Documentation": Contains documentation in various formats. * "./t": Test suite. * "./templates": Template files used when initializing a new repository. **Do This:** * Place new built-in commands in the "./builtin" directory and follow the existing naming conventions. * Add comprehensive tests to the "./t" directory for any new functionality. * Update the documentation in the "./Documentation" directory to reflect any changes. **Don't Do This:** * Do not add new core functionality as external scripts unless there is a strong justification. * Avoid modifying files directly in "contrib" to add non-core features. These should come as proposals for core features first, then added if approved via proper channels. ### 2.2. Code Organization Principles * **Modularity:** Keep code well-factored into reusable functions and modules. Limit the scope of functions to a single, well-defined task. * **Abstraction:** Use abstract data types and interfaces to hide implementation details and reduce dependencies. * **Error Handling:** Implement robust error handling and reporting. Use Git's existing error reporting mechanisms. **Do This:** * Create new functions and modules with clear interfaces and well-defined responsibilities. * Use Git's internal logging and error reporting functions consistently. * Favor small, focused functions over large, complex ones. **Don't Do This:** * Avoid global variables and excessive dependencies between modules. * Do not ignore error return values. Always check for errors and handle them appropriately. * Don't create overly complex, monolithic functions. **Code Example (Abstraction):** """c // Example of an abstract data type for handling object IDs // (object-id.h) #ifndef OBJECT_ID_H #define OBJECT_ID_H #include <stdint.h> #include <stdbool.h> #define OBJ_OID_SIZE 20 // Size of SHA-1 hash in bytes typedef struct object_id { unsigned char hash[OBJ_OID_SIZE]; } object_id; // Function prototypes for working with object IDs bool oid_equal(const object_id *oid1, const object_id *oid2); const char *oid_to_hex(const object_id *oid); int hex_to_oid(const char *hex, object_id *oid); void clear_oid(object_id *oid); #endif // (object-id.c) #include "object-id.h" #include <string.h> #include <stdio.h> bool oid_equal(const object_id *oid1, const object_id *oid2) { return memcmp(oid1->hash, oid2->hash, OBJ_OID_SIZE) == 0; } const char *oid_to_hex(const object_id *oid) { static char hex_str[OBJ_OID_SIZE * 2 + 1]; // Static buffer for hex representation for (int i = 0; i < OBJ_OID_SIZE; i++) { sprintf(hex_str + 2*i, "%02x", oid->hash[i]); } return hex_str; } int hex_to_oid(const char *hex, object_id *oid) { // Implementation to convert hex string to bytes and store in oid->hash // (Error checking omitted for brevity) sscanf(hex, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", (unsigned int *)&oid->hash[0], (unsigned int *)&oid->hash[1], (unsigned int *)&oid->hash[2], (unsigned int *)&oid->hash[3], (unsigned int *)&oid->hash[4], (unsigned int *)&oid->hash[5], (unsigned int *)&oid->hash[6], (unsigned int *)&oid->hash[7], (unsigned int *)&oid->hash[8], (unsigned int *)&oid->hash[9], (unsigned int *)&oid->hash[10], (unsigned int *)&oid->hash[11], (unsigned int *)&oid->hash[12], (unsigned int *)&oid->hash[13], (unsigned int *)&oid->hash[14], (unsigned int *)&oid->hash[15], (unsigned int *)&oid->hash[16], (unsigned int *)&oid->hash[17], (unsigned int *)&oid->hash[18], (unsigned int *)&oid->hash[19]); return 0; } void clear_oid(object_id *oid) { memset(oid->hash, 0, OBJ_OID_SIZE); } """ ## 3. Modern Approaches and Patterns Git development should leverage modern approaches to ensure performance, maintainability, and security are prioritised. ### 3.1 Asynchronous Operations Where applicable, implement asynchronous operations to prevent blocking the main thread. **Do This:** Use asynchronous mechanisms where lengthy operations like network requests or disk I/O are involved. **Don't Do This:** Avoid executing long running, synchronous operations directly on the main thread, especially when processing large repositories. **Code Example:** Consult the Git source code for implementations of fetching and pushing operations because specific async code examples would become outdated quickly. ### 3.2 Memory Management * **Description:** Git operates on potentially very large repositories. Efficient memory management is crucial to performance and stability. **Do This:** * Always free allocated memory when it is no longer needed. * Use Git's internal memory management functions (e.g., "xmalloc", "xcalloc", "xrealloc") which provide additional safety checks and diagnostics. * Use memory pools for frequently allocated and deallocated objects. **Don't Do This:** * Do not leak memory. Use memory leak detection tools during development. * Avoid using raw "malloc" and "free" directly. * Do not allocate large chunks of memory on the stack. **Code Example:** """c #include "utils.h" //Contains xmalloc etc void *allocate_and_use_memory(size_t size) { void *ptr = xmalloc(size); // Allocate memory using xmalloc if (ptr == NULL) { return NULL; // Handle allocation failure } // ... use the allocated memory ... ptr = xrealloc(ptr, size * 2); // Example reallocation //Free the allocated memory free(ptr); return ptr; } """ ### 3.3 Performance Optimization * **Description:** Git is used across a vast range of hardware. Optimizing frequently used operations is paramount. **Do This:** * Profile code to identify performance bottlenecks. * Use efficient data structures (e.g., hash tables, bitmaps). * Minimize disk I/O. * Leverage caching to avoid redundant computations. **Don't Do This:** * Avoid premature optimization. * Do not introduce performance regressions without thorough justification and testing. * Don't create unnecessary disk I/O operations. ### 3.4 Security Best Practices * **Description:** Security is paramount in Git development. Vulnerabilities can have far-reaching consequences. **Do This:** * Sanitize all user input. Prevent command injection and path traversal attacks. * Be wary of external dependencies. Regularly audit dependencies for security vulnerabilities. * Prefer using safe functions (e.g., "strncpy" instead of "strcpy"). * Follow the principle of least privilege. Avoid running Git processes with elevated privileges unless absolutely necessary. **Don't Do This:** * Do not trust user input blindly. * Avoid using deprecated or known-vulnerable functions. * Don't store sensitive information in plain text. """c #include <string.h> #include <stdio.h> // Vulnerable code (example) void process_path(const char *user_provided_path) { char buffer[256]; strcpy(buffer, user_provided_path); // Buffer overflow vulnerability printf("Processing path: %s\n", buffer); } // Secure code (example) void process_path_safe(const char *user_provided_path) { char buffer[256]; strncpy(buffer, user_provided_path, sizeof(buffer) - 1); // Safe copy buffer[sizeof(buffer) - 1] = '\0'; // Ensure null termination printf("Processing path: %s\n", buffer); } """ ### 3.5 Testing * **Description:** Thorough testing is essential to ensure the correctness and stability of Git. **Do This:** * Write comprehensive unit tests for all new code. * Add integration tests to verify the interaction of different components. * Use Git's existing test framework. * Run tests frequently during development. **Don't Do This:** * Do not commit code without adequate testing. * Avoid writing flaky or unreliable tests. * Don't ignore test failures. ### 3.6 Error Handling Explicitly handle potential errors and exceptions for a more robust and maintainable codebase. **Do This:** Employ well-structured error handling such as "if" to capture failed operations and use Git's error reporting mechanisms to handle these. **Don't Do This:** Avoid ignoring potential error return values. **Code Example:** """c int perform_operation() { int result = some_function(); if (result != SUCCESS) { error("Operation failed with code: %d", result); return FAILURE; } return SUCCESS; } """ ## 4. Deprecated Features Be aware of deprecated Git features and avoid using them in new code. Consult the Git release notes for a comprehensive list. ### 4.1. SHA-1 Transition * Git is in the process of transitioning from SHA-1 to SHA-256. Avoid relying solely on SHA-1. * Use the object ID abstraction layer to handle both SHA-1 and SHA-256 objects. **Do This:** * When working with object IDs, use the "object_id" structure and associated functions. * Test new code with repositories using both SHA-1 and SHA-256. **Don't Do This:** * Do not assume that all object IDs are SHA-1 hashes. * Avoid hardcoding the SHA-1 hash length (20 bytes). ## 5. Community Standards and Patterns * **Coding Style:** Follow Git's coding style (see "Documentation/CodingGuidelines"). Use consistent indentation, spacing, and naming conventions. * **Commit Messages:** Write clear and concise commit messages. Explain the *why* behind the changes. * **Patch Submission:** Submit patches using "git format-patch" and "git send-email". Follow the Git patch submission guidelines. * **Mailing List:** Engage in discussions on the Git mailing list to seek feedback and coordinate development efforts. This document provides a starting point for understanding the Core Architecture standards of Git. It is essential to complement this knowledge with in-depth study of the existing codebase, the official documentation, and active participation in the Git development community.
# Security Best Practices Standards for Git This document outlines security best practices for Git development, providing guidelines for developers to write secure, maintainable, and performant Git code. This guidance applies both to the core Git project as well as projects that utilize Git for version control. ## 1. Authentication and Authorization ### 1.1. Avoid Storing Credentials in Code or Configuration Files **Standard:** Never store sensitive information like passwords, API keys, or private keys directly in Git repositories, configuration files tracked by Git, or environment variables within a Git repository. **Why:** Exposing credentials can lead to unauthorized access, data breaches, and compromise of systems. Even if the repository is private, accidental exposure is possible. **Do This:** * Use environment variables (outside of Git) or configuration files that are *not* tracked by Git to store sensitive information. * Use credential management tools or secrets management solutions. * Leverage Git's credential storage capabilities with appropriate configuration. **Don't Do This:** * Hardcode credentials in scripts, configuration files checked into Git, or environment variables checked into Git. * Leave placeholder credentials in the codebase. **Example (Environment Variables):** """bash # Never commit this file or the credentials within it export API_KEY="your_secret_api_key" """ """python # Access the API key via environment variables in your code import os api_key = os.environ.get("API_KEY") if api_key: # Use api_key print("API Key loaded successfully") else: print("API Key not found in environment variables.") """ **Anti-Pattern:** """python # BAD PRACTICE: Storing credentials directly in code api_key = "your_secret_api_key" # DO NOT DO THIS! """ **Git Specific Notes:** Ensure ".gitignore" includes files such as ".env", "config.ini", and other such config files that may contain sensitive information. Regularly audit ".gitignore" to ensure it's up-to-date. ### 1.2. Enforce Multi-Factor Authentication (MFA) **Standard:** Enforce MFA for all Git users, especially those with write access to critical repositories. Use SSH keys where applicable and manage them securely. **Why:** MFA adds an extra layer of security, making it significantly harder for attackers to gain unauthorized access even if credentials are compromised. **Do This:** * Enable MFA on Git hosting platforms (GitHub, GitLab, Bitbucket). * Use SSH keys with passphrases for authentication where applicable. * Regularly review and rotate SSH keys. **Don't Do This:** * Rely solely on username/password authentication. * Share SSH keys. * Use weak or default SSH key passphrases. **Example (GitHub MFA Enforcement):** GitHub provides organization-level settings to enforce MFA. Configure these settings to require all members, billers, and outside collaborators to enable MFA. Navigate to your organization settings > Security > Authentication security > Require two-factor authentication for all members, billers, and outside collaborators. **Anti-Pattern:** Disabling MFA for convenience or perceived lack of risk. ### 1.3. Regularly Audit Access Controls **Standard:** Periodically review and update access control lists (ACLs) for Git repositories to ensure that only authorized users have access. **Why:** User roles and responsibilities change over time. Regular audits help identify and remove unnecessary access, reducing the attack surface. **Do This:** * Use Git hosting platform features to manage user permissions (e.g., GitHub roles, GitLab membership). * Implement the principle of least privilege, granting users only the access they need. * Remove access for users who no longer require it (e.g., departing employees). **Don't Do This:** * Grant broad access permissions without justification. * Fail to remove access when it's no longer needed. * Ignore inactive user accounts. **Example (GitHub Repository Permissions):** In a GitHub repository, go to Settings > Manage access to review collaborators and their roles (e.g., Admin, Write, Read). Remove collaborators who should no longer have access and adjust roles as needed. ### 1.4. Secure SSH Key Management **Standard:** Enforce best practices for generating, storing, and using SSH keys. **Why:** Compromised SSH keys can provide unauthorized access to repositories and servers. **Do This:** * Use strong key generation algorithms (e.g., Ed25519). * Use a strong passphrase for encrypting the private key. * Store private keys securely (e.g., using an SSH agent). * Avoid copying private keys to multiple machines. * Use "ssh-agent" or similar tools to manage keys instead of storing passwords in scripts **Don't Do This:** * Use weak key generation algorithms (e.g., RSA with small key size). * Store private keys in plain text. * Share private keys. * Use the same SSH key for multiple systems with differing levels of trust. **Example (Generating Ed25519 SSH key):** """bash ssh-keygen -t ed25519 -C "your_email@example.com" """ **Anti-Pattern:** Leaving SSH keys unprotected or failing to rotate them. ## 2. Commit Hygiene ### 2.1. Sanitize Commit History **Standard:** Avoid committing sensitive data (passwords, API keys, private keys) to the repository. If sensitive data is accidentally committed, rewrite the commit history to remove it. **Why:** Once committed, data persists in the repository's history, making it accessible to anyone with access and potentially discoverable through automated tools. **Do This:** * Use ".gitignore" to prevent accidental commits of sensitive files. * Use "git filter-branch" or tools like "BFG Repo-Cleaner" to remove sensitive data from the entire commit history. * Consider the implications of rewriting history on collaborative workflows; coordinate with team members. **Don't Do This:** * Commit sensitive data intentionally. * Rely on deleting the file after committing it; the data is still in the history. * Forget to notify collaborators when rewriting history. **Example (Using BFG Repo-Cleaner):** """bash # Download BFG Repo-Cleaner from: https://rtyley.github.io/bfg-repo-cleaner/ java -jar bfg-1.14.0.jar --delete-files id_rsa # Example: deleting private key files git reflog expire --expire=now --all && git gc --prune=now --aggressive git push origin --all --force # WARNING: Forces updates to all branches git push origin --tags --force # WARNING: Forces updates to all tags """ **Git Specific Notes:** Rewriting Git history is disruptive and should be done with caution, especially in collaborative environments. Communicate and coordinate such actions. ### 2.2. Commit Message Security **Standard:** Avoid including sensitive information (e.g., internal hostnames, detailed security vulnerabilities) in commit messages. **Why:** Commit messages are often公開された (public) and can be easily searched. Including sensitive information exposes it to a wider audience. **Do This:** * Write clear, concise, and informative commit messages that avoid revealing sensitive implementation details. * Review commit messages before pushing to public repositories. **Don't Do This:** * Include passwords, API keys, or other credentials in commit messages. * Describe specific security vulnerabilities in detail. **Example (Good Commit Message):** """ Fix: Resolve issue with user authentication """ **Example (Bad Commit Message):** """ Fix: Resolved issue with hardcoded password in user authentication mechanism. Password set to "P@$$wOrd123". """ ### 2.3. Signing Commits **Standard:** Sign commits with a GPG key for enhanced security and integrity. **Why:** Signing commits verifies that the commit was authored by the owner of the GPG key (or at least, someone who has access to it), adding increased trust and traceability. **Do This:** * Generate a GPG key pair. * Configure Git to use the GPG key for signing commits. * Add your public key to your Git hosting platform. * Sign commits using the "-S" flag. * Set "commit.gpgsign = true" in your git config. **Don't Do This:** * Share your private GPG key. * Use a weak passphrase for your GPG key. * Forget to sign your commits. **Example (Signing Commits):** """bash git config --global user.signingkey <your_gpg_key_id> git config --global commit.gpgsign true # Alternatively sign specific commits git commit -S -m "Fix: Resolve issue with user authentication" """ ## 3. Git Configuration Security ### 3.1. Secure Git Configuration Files **Standard:** Protect Git configuration files (".gitconfig", ".git/config") from unauthorized modification. Be cautious about using global configurations across multiple projects to avoid unexpected behaviors. **Why:** If an attacker gains control of your Git configuration, they can inject malicious commands or aliases that execute arbitrary code. **Do This:** * Set appropriate file permissions on Git configuration files (e.g., 600 for ".gitconfig"). * Be cautious about running scripts from untrusted sources that modify Git configuration. * Use separate configs, i.e., local configs where appropriate, to avoid unintended global changes. **Don't Do This:** * Make Git configuration files world-writable. * Blindly execute scripts that modify Git configuration without understanding their purpose. **Example (File Permissions):** """bash chmod 600 ~/.gitconfig """ ### 3.2. Avoid Shell Expansion in Git Aliases **Standard:** When defining Git aliases, avoid using shell expansion or command substitution, as these can be exploited for command injection. **Why:** Shell expansion can execute arbitrary commands if the alias contains user-controlled input. **Do This:** * Use Git's built-in alias functionality for simple commands. * If shell scripting is necessary, sanitize user input and use parameterized queries. **Don't Do This:** * Use backticks or "$()" for command substitution in aliases without careful input validation. * Pass user-controlled input directly to shell commands within aliases. **Example (Potentially unsafe alias):** """bash # POTENTIALLY UNSAFE: Avoid this pattern! git config --global alias.bad '!f() { git log -n 1 --pretty=format:"%H" "$1"; }; f' """ **Anti-Pattern:** Creating aliases that execute arbitrary commands directly based on user input. ### 3.3. Disable "core.autocrlf" if not needed **Standard**: When using Git on Windows, be mindful of the "core.autocrlf" setting. If not needed (e.g., working exclusively with Unix-style line endings), disable it. **Why**: "core.autocrlf" automatically converts line endings from CRLF (Windows) to LF (Unix) when committing and vice versa when checking out. This can lead to unexpected changes in files if not handled correctly and, in rare circumstances, potentially mask malicious changes. **Do This**: * Understand the implications of "core.autocrlf". * If working exclusively with Unix-style line endings, set "core.autocrlf" to "false". * If working in mixed environments, set "core.autocrlf" to "true" and configure the ".gitattributes" file to handle line endings correctly for different file types. **Don't Do This**: * Leave "core.autocrlf" enabled without understanding its effects. * Allow Git to modify line endings of binary files. **Example:** """bash # Disable autocrlf git config --global core.autocrlf false """ ## 4. Dependency Management ### 4.1. Use Dependency Scanning Tools **Standard:** Implement tools that automatically scan dependencies for known vulnerabilities. **Why:** Applications often depend on external libraries and frameworks. These dependencies may contain vulnerabilities that can be exploited by attackers. **Do This:** * Integrate dependency scanning tools into your CI/CD pipeline (e.g., OWASP Dependency-Check, Snyk, Dependabot). * Regularly update dependencies to the latest versions. * Monitor alerts from dependency scanning tools and address vulnerabilities promptly. **Don't Do This:** * Ignore alerts from dependency scanning tools. * Use outdated dependencies with known vulnerabilities. ### 4.2. Secure Git Submodules **Standard:** Be careful when including Git submodules, as vulnerabilities in submodules can affect the main project. **Why:** Git submodules allow you to include external repositories within your project. If a submodule is compromised, it can introduce vulnerabilities into your main project. **Do This:** * Use submodules from trusted sources. * Regularly update submodules to the latest versions. * Verify the integrity of submodules (e.g., by checking the commit hash). **Don't Do This:** * Use submodules from untrusted sources. * Ignore updates to submodules from upstream. * Automatically trust updates of submodules without verification ## 5. Threat Modeling and Security Reviews ### 5.1. Conduct Regular Threat Modeling **Standard:** Periodically conduct threat modeling exercises to identify potential security risks related to Git workflows and infrastructure. **Why:** Threat modeling helps uncover vulnerabilities that might not be apparent during code reviews or testing. **Do This:** * Involve security experts in threat modeling exercises. * Consider different attack vectors (e.g., unauthorized access, data breaches, code injection). * Document the identified threats and mitigation strategies. **Don't Do This:** * Treat threat modeling as a one-time activity. * Ignore identified threats. ### 5.2. Conduct Security Code Reviews **Standard:** Conduct thorough security code reviews to identify vulnerabilities and ensure adherence to secure coding practices. **Why:** Manual code reviews can detect subtle vulnerabilities that automated tools might miss. **Do This:** * Involve security experts in code reviews. * Focus on security-critical code (e.g., authentication, authorization, data handling). * Use checklists of common vulnerabilities to guide the review process (e.g., OWASP Top 10). **Don't Do This:** * Rely solely on automated tools for security testing. * Skip security code reviews for critical code changes. ## 6. Continuous Integration/Continuous Deployment (CI/CD) Security ### 6.1. Secure CI/CD Pipelines **Standard:** Protect CI/CD pipelines from unauthorized access and tampering. **Why:** CI/CD pipelines are critical infrastructure for software development and deployment. Compromising a CI/CD pipeline can lead to widespread damage. **Do This:** * Enforce strong authentication and authorization for CI/CD systems. * Use secure credentials management practices. * Monitor CI/CD logs for suspicious activity. * Implement code signing to verify the integrity of software artifacts. * Scan for vulnerabilities in the code being promoted. **Don't Do This:** * Use default credentials for CI/CD systems. * Store secrets in CI/CD configuration files. * Assume your CI/CD build environment is secure ### 6.2. Secure Branching Strategy **Standard**: Implement a secure branching strategy to isolate development efforts and protect the main codebase. **Why**: A well-defined branching strategy helps prevent accidental introduction of vulnerabilities, enforces code review processes, and manages feature development effectively. **Do This:** * Use feature branches for developing new features or bug fixes. * Enforce code reviews for pull requests/merge requests before merging into the main branch. * Use protected branches to prevent direct commits to critical branches (e.g., "main", "release"). **Don't Do This:** * Commit directly to the "main" branch without review. * Merge branches without proper testing and code review. --- This document is a living document and will be updated periodically to reflect the latest security threats and best practices. Developers should regularly review this document and adapt their coding practices accordingly.
# State Management Standards for Git This document outlines the coding standards for managing state within the Git codebase. It focuses on how Git internally tracks and manipulates state, including the index, working directory, object database, and reflog. These standards aim to improve code clarity, prevent race conditions, and ensure data integrity. These standards are designed to be used by Git developers and as context for AI coding assistants. ## 1. Introduction to Git State Management Git is essentially a state machine. Each Git command manipulates the state of the repository in a well-defined way. Understanding and managing this internal state correctly is crucial for maintaining a stable and reliable version control system. Because Git's state is distributed and potentially shared across multiple processes (client and server), correct design and implementation are critical for data integrity. ### 1.1 Key Git State Components * **Working Directory:** The set of actual files in your project on disk. * **Index (Staging Area):** A binary file containing a sorted list of file names, mode bits, and pointers to object contents. It represents the next commit. * **Object Database:** A content-addressable store containing Git objects (blobs, trees, commits, tags). * **Refs (References):** Pointers to commits (e.g., branches, tags, HEAD). * **Reflog:** A log of when the tips of refs were updated. * **Configuration:** Central configuration file including user settings which are often cached. ### 1.2 Overview of State Transitions Git's state transitions involve moving data between these key components. For example: * "git add": Moves changes from the working directory to the index. * "git commit": Creates a new commit object from the index and updates the ref (e.g., "HEAD"). * "git checkout": Updates the working directory and index to match a specific commit. * "git reset": Updates either the index or the working directory (or both) to a new state. * "git fetch": Retrieves objects and refs from a remote repository and updates local refs. * "git push": Sends objects and refs to a remote repository. ## 2. Core Principles for State Management in Git ### 2.1 Atomicity **Definition:** All state changes within a single operation should be atomic. Either all changes succeed, or none succeed. A partially completed operation is unacceptable. **Do This:** * Use transactions (e.g., via temporary files and rename operations) to ensure atomicity. * Implement rollback mechanisms for failed operations. **Don't Do This:** * Directly modify state files (index, refs) without a proper locking or transaction mechanism. * Leave the repository in an inconsistent state after an error. **Why:** Atomicity prevents data corruption and ensures the integrity of the Git repository. Git is a distributed system, and atomic operations support its goals of fault tolerance. **Example:** """c // Example of atomic file update using rename int atomic_write_file(const char *filename, const char *temp_suffix, void (*write_func)(FILE *)) { char *temp_filename = xstrfmt("%s%s", filename, temp_suffix); FILE *fp = fopen(temp_filename, "wb"); if (!fp) { free(temp_filename); return -1; // Error opening temporary file } write_func(fp); // Write data to the temporary file if (fclose(fp) != 0) { unlink(temp_filename); // Clean up on error free(temp_filename); return -1; // Error closing temporary file } if (rename(temp_filename, filename) != 0) { unlink(temp_filename); // Clean up on error free(temp_filename); return -1; // Error renaming file } free(temp_filename); return 0; // Success } //Atomic Update by writing tmp, synching/closing, and renaming """ **Anti-Pattern:** Directly writing to ".git/index" or ".git/refs/heads/main" without using "lock_file" APIs. ### 2.2 Concurrency Control **Definition:** Ensure that multiple processes accessing the same repository do not interfere with each other. **Do This:** * Use file locking (e.g., via "lock_file" APIs) to serialize access to shared resources (index, refs). * Implement appropriate locking strategies (e.g., shared vs. exclusive locks). * Consider using optimistic locking where appropriate. **Don't Do This:** * Assume that you are the only process accessing the repository. * Hold locks for extended periods. **Why:** Concurrency control prevents race conditions and data corruption in multi-user environments. **Example:** """c // Example of using lock_file #include "lockfile.h" int update_ref(const char *ref_name, const char *new_oid) { struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); lockfile_create(lock, ref_name, LOCK_DIE_ON_ERROR); if (hold_lock_file_for_update(lock, LOCK_DIE_ON_ERROR) < 0) { return -1; // Failed to get a lock } FILE *fp = fdopen(lock->fd, "w"); if (!fp) { lockfile_unlock(lock); return error_errno(_("cannot open %s for writing"), ref_name); } fprintf(fp, "%s\n", new_oid); if (fclose(fp) != 0) { lockfile_unlock(lock); return error_errno(_("cannot write to %s"), ref_name); } if (commit_lock_file(lock) < 0) { return -1; // Could not commit the lock file, data write has failed } return 0; } """ **Anti-Pattern:** Ignoring lock return codes or forgetting to release locks. Another anti-pattern is failing to check the lock file's creation timestamp for staleness and attempting to force an overwrite. ### 2.3 Data Integrity **Definition:** Ensure that the data stored in the repository is correct and consistent. **Do This:** * Use content-addressable storage (SHA-1 or SHA-256 hashing) to verify data integrity. * Implement checksums for data files. * Validate data before writing it to the object database. **Don't Do This:** * Assume that data read from disk is always correct. **Why:** Data integrity protects against corruption due to hardware failures, software bugs, or malicious attacks. **Example:** """c // Example of calculating SHA-1 hash #include "object.h" #include <git-compat-util.h> #include <openssl/sha.h> void calculate_sha1(const void *data, size_t len, unsigned char *hash) { SHA1((const unsigned char *)data, len, hash); } int verify_object(enum object_type type, const unsigned char *sha1, const char *path) { struct stat st; void *buf; size_t size; unsigned char actual_sha1[20]; if (stat(path, &st) < 0) return error(_("cannot stat '%s': %s"), path, strerror(errno)); size = st.st_size; buf = xmalloc(size); if (read_in_full(open(path, O_RDONLY), buf, size) != size) { free(buf); return error(_("cannot read '%s': %s"), path, strerror(errno)); } if (index_path(actual_sha1, type, buf, size, path, NULL)) { // Hashes the file to store/verify file contents free(buf); return -1; } if (hashcmp(actual_sha1, sha1)) { // Check if the hashes are equal free(buf); return error(_("hash mismatch for '%s'"), path); } free(buf); return 0; } """ **Anti-Pattern:** Storing data without calculating or verifying checksums. Assuming "fstat" and "read" functions are safe from reporting inconsistent values. ### 2.4 Error Handling **Definition:** Handle errors gracefully and provide informative error messages. **Do This:** * Check return codes for all system calls and library functions. * Use "die()" or "error()" functions to report errors. * Provide context in error messages. **Don't Do This:** * Ignore errors. * Use generic error messages. **Why:** Proper error handling prevents crashes and helps users diagnose problems. **Example:** """c // Example of error handling with die() #include "utils.h" int create_directory(const char *path) { if (mkdir(path, 0755) != 0) { //die("Failed to create directory '%s': %s", path, strerror(errno)); //Note: die() does not return return error("Failed to create directory '%s': %s", path, strerror(errno)); } return 0; } """ **Anti-Pattern:** Using "assert()" for error conditions that can occur in production. Printing errors to "stderr" without a consistent format. ## 3. Specific State Management Scenarios ### 3.1 Index Manipulation **Standards:** * Use functions in "cache.h" (e.g., "add_cacheinfo()", "remove_index_entry()", "write_cache()") to manipulate the index. * Always refresh the index (e.g., "read_cache()") before making changes if the index may have been modified by another process. * Use "the_index.cache_tree" for optimizing index operations. * Lock the index appropriately before major modifications. **Example:** """c // Example of adding an entry to the index #include "cache.h" #include "object.h" int add_file_to_index(const char *path) { struct stat st; struct cache_entry *ce; int fd; if (lstat(path, &st) < 0) { return error("lstat(%s) failed: %s", path, strerror(errno)); } fd = open(path, O_RDONLY); if (fd < 0) { return error("open(%s) failed: %s", path, strerror(errno)); } ce = make_cache_entry(&the_index, path, &st, 0); // 0 means default flags if (!ce) { close(fd); return error("make_cache_entry failed for %s", path); } if (add_cacheinfo(ce) < 0) { // Adds cache info in the index close(fd); return error("add_cacheinfo failed for %s", path); } close(fd); return 0; } """ **Anti-Pattern:** Modifying the "the_index" structure directly without using the provided functions. Doing incomplete reads of the cache entries, or using out-of-date file status information. ### 3.2 Ref Updates **Standards:** * Use functions in "refs.h" (e.g., "update_ref()", "resolve_ref()", "create_symref()") to manipulate refs. * Always use "update_ref()" with a proper "old_oid" check to prevent clobbering concurrent updates. Pay attention to the symbolic ref handling. * Update the reflog when updating refs (using the "UPDATE_REFS_DIE_ON_ERR" flag). * Use atomic ref updates via lockfiles, especially in multi-threaded or multi-process contexts. **Example:** """c // Example of updating a ref #include "refs.h" int update_branch_ref(const char *branch_name, const char *new_oid, const char *old_oid) { char ref_name[PATH_MAX]; snprintf(ref_name, sizeof(ref_name), "refs/heads/%s", branch_name); struct strbuf err = STRBUF_INIT; if (update_ref(ref_name, new_oid, old_oid, 0, UPDATE_REFS_MSG_ON_RESOLVE, &err) != REF_OK){ // Updates reference in the reflog strbuf_release(&err); return -1; // Error updating ref } strbuf_release(&err); return 0; } """ **Anti-Pattern:** Directly writing to files under ".git/refs/" folder. Not checking the return values of "update_ref" and ignoring errors. Not updating the reflog. Using shell commands ("system("git update-ref ...")") instead of the C API. ### 3.3 Object Database Access **Standards:** * Use functions in "object.h" and "loose-object.h" (e.g., "open_object_header()", "read_object_file()", "hash_object_file()") to access and manipulate objects. * Use "oid_to_hex()" and "hex_to_oid()" to convert between object IDs and their hexadecimal representations. * Avoid reading the entire object database into memory. Use streaming APIs when applicable. * Handle object corruption gracefully. * Do not assume every object exists locally and can be quickly accessed. Objects may need to be fetched over the wire. **Example:** """c // Example for converting OID to string #include "object.h" int print_object_id(const unsigned char *sha1) { struct object_id oid; oidread(sha1, &oid); char oid_str[GIT_OID_HEXSZ+1]; // +1 for null terminator oid_to_hex(oid_str, &oid); printf("Object ID: %s\n", oid_str); return 0; } """ **Anti-Pattern:** Manually constructing object paths based on the SHA-1 hash, which is error-prone and bypasses the object database API. Caching object contents indefinitely without considering memory constraints. ### 3.4 Configuration Management **Standards:** * Use "git_config()" to read configuration values. * Use appropriate configuration scopes (e.g., "GIT_CONFIG_SYSTEM", "GIT_CONFIG_GLOBAL", "GIT_CONFIG_LOCAL"). * Use "git_config_set()" with caution, as it can modify configuration files directly. Prefer using Git commands (e.g., "git config") for changing configuration settings. * Cache configuration values where appropriate, but invalidate the cache when the configuration changes. **Example:** """c // Example of reading a configuration value #include "config.h" int get_core_editor(char **editor) { return git_config_get_string("core.editor", editor); } """ **Anti-Pattern:** Parsing configuration files manually instead of using "git_config". Hardcoding default configuration values instead of allowing users to customize them. ## 4. Modern Git Features and State Management ### 4.1 Multi-pack Index (MIDX) Git 2.20 introduced multi-pack indexes, allowing Git to efficiently manage repositories with a large number of packfiles. When accessing objects, prioritize using functions that can handle MIDX files. This can significantly improve performance when dealing with large repositories. Be aware that some tools may not yet fully understand or support MIDX. ### 4.2 Commit Graph The commit graph feature (introduced in Git 2.18) provides a way to store commit topological information separately from the object database. This can speed up certain Git operations, such as reachability checks. When traversing the commit history, consider using the commit graph API (if available) to improve performance. Take into account memory consumption when dealing with commit graphs. They can significantly grow with the number of commits so they should be used judiciously. **Standards:** * When traversing commit history, consider using commit graph APIs (if available) to improve performance. * Implement object traversal using the reachability bitmap index when possible. * Keep memory footprint in mind when using commit graph functionalities. ### 4.3 Trace2 framework Git implemented a new tracing framework named "Trace2", a more robust and standardized tracing system than its predecessors. Use this when debugging, as it allows for recording Git's execution flow and inspecting the internal states during operation, providing valuable insights for problem-solving and performance analysis. Use this to enhance error reporting so that developers can understand the system state at the time of failure. ## 5. Security Considerations for State Management ### 5.1 Path Traversal Vulnerabilities **Definition:** Prevent attackers from accessing files outside the repository by manipulating paths. **Do This:** * Sanitize all paths received from user input or external sources. * Use "safe_create_leading_directories()" before creating or modifying files. * Use "repo_path()" and "absolute_path()" functions to resolve paths relative to the repository root. **Don't Do This:** * Directly use paths from untrusted sources without validation. ### 5.2 Object Injection Vulnerabilities **Definition:** Prevent attackers from injecting malicious objects into the repository. **Do This:** * Validate the type and content of all objects before storing them in the object database. * Use the object database API to create and access objects. **Don't Do This:** * Allow users to directly write to the object database. ### 5.3 Reflog Poisoning **Definition:** Prevent attackers from injecting arbitrary commands into the reflog, potentially leading to command execution vulnerabilities. **Do This:** * Sanitize reflog messages to prevent command injection. * Limit the characters allowed in reflog messages. ## 6. Testing All code that manipulates Git's internal state should be thoroughly tested. Write unit tests, integration tests, and end-to-end tests to ensure that the code is correct and robust. Pay close attention to testing error scenarios and concurrency issues. Use fuzzing techniques (e.g., libFuzzer) to discover potential vulnerabilities. ## 7. Code Review All code changes should be reviewed by at least one other developer. Pay close attention to state management aspects during code review, ensuring that the standards outlined in this document are followed. ## 8. Conclusion Adhering to these state management standards will result in a more robust, secure, and maintainable Git codebase. These standards should be considered a living document, evolving as Git evolves.
# Component Design Standards for Git This document outlines component design standards for Git development, focusing on creating reusable, maintainable, and performant code. These standards aim to ensure code consistency, reduce complexity, and promote collaboration among developers. This guide is geared towards developers working on Git itself and aims to leverage the latest version of Git. ## 1. Architectural Principles ### 1.1 Modularity and Separation of Concerns **Standard:** Design components with single, well-defined responsibilities. Adhere to the Single Responsibility Principle (SRP). Avoid creating "god classes" or components with overlapping functionalities. **Do This:** * Break down complex tasks into smaller, manageable components. * Ensure each component has a distinct purpose and minimal dependencies on other unrelated components. * Use clear interfaces to define interactions between components. **Don't Do This:** * Implement unrelated features within the same component. * Create tight coupling between components, making them difficult to test or reuse independently. * Mix high-level policies with low-level details. **Why:** Modularity improves code readability, testability, and reusability. Separation of concerns reduces the risk of introducing bugs when modifying one part of the code. **Example:** **Incorrect:** """c /* BAD: This component handles both index updates and conflict resolution. */ struct index_updater { struct index_state *index; int resolve_conflicts; int add_entry(const char *path, unsigned int mode, const unsigned char *sha1); int resolve_conflict(const char *path); }; """ **Correct:** """c /* GOOD: Separate components for index updates and conflict resolution */ struct index_updater { struct index_state *index; int add_entry(const char *path, unsigned int mode, const unsigned char *sha1); }; struct conflict_resolver { struct index_state *index; int resolve_conflict(const char *path); }; """ ### 1.2 Abstraction and Information Hiding **Standard:** Minimize exposure of internal implementation details. Use abstract interfaces to interact with components. **Do This:** * Use abstract data types (ADTs) and opaque pointers to hide internal structures. * Expose only essential functions through a well-defined API. * Use the "static" keyword to limit the scope of functions and variables to the compilation unit. **Don't Do This:** * Directly access or modify internal data structures from outside the component. * Expose internal functions in the public API. * Hardcode dependencies on specific data representations. **Why:** Abstraction reduces the impact of internal changes on external code, facilitating maintenance and evolution. Information hiding prevents accidental misuse and promotes stability. **Example:** **Incorrect:** """c /* BAD: Exposing internal structure details */ struct commit { unsigned char sha1[20]; char *message; int num_parents; struct commit **parents; }; """ **Correct:** """c /* GOOD: Hiding internal structure with opaque pointer */ typedef struct commit commit_t; /* API functions */ commit_t *commit_create(const char *message); const unsigned char *commit_get_sha1(const commit_t *commit); const char *commit_get_message(const commit_t *commit); void commit_add_parent(commit_t *commit, commit_t *parent); """ ### 1.3 Reusability and Composability **Standard:** Design components to be reusable in different contexts. Favor composition over inheritance. **Do This:** * Create generic components that can be customized through configuration or callbacks. * Use dependency injection to provide components with necessary dependencies. * Implement interfaces that promote loose coupling. **Don't Do This:** * Create highly specialized components tied to specific use cases. * Rely on global state or singleton patterns, which limit reusability. * Use deep inheritance hierarchies that can lead to fragile base class problems. **Why:** Reusability reduces code duplication and development effort. Composability enables flexible combination of components to achieve complex functionalities. **Example:** **Incorrect:** """c /* BAD: Hardcoded path in a helper utility */ int check_file_exists(const char *filename) { char full_path[MAX_PATH]; snprintf(full_path, sizeof(full_path), "%s/%s", get_git_directory(), filename); // tightly coupled to git dir return access(full_path, F_OK); } """ **Correct:** """c /* GOOD: Making the path configurable */ int check_file_exists(const char *base_path, const char *filename) { char full_path[MAX_PATH]; snprintf(full_path, sizeof(full_path), "%s/%s", base_path, filename); return access(full_path, F_OK); } """ The second implementation is reusable *anywhere* that requires checking for a file's existence, not exclusively within Git's working directory. ## 2. Implementation Guidelines ### 2.1 Naming Conventions **Standard:** Use descriptive and consistent names for components, functions, variables, and constants. **Do This:** * Use meaningful names that clearly indicate the purpose and functionality of the element. * Follow a consistent naming style (e.g., "snake_case" for functions and variables, "PascalCase" for types). * Prefix global constants with "GIT_" (e.g., "GIT_MAX_PATH"). **Don't Do This:** * Use cryptic or abbreviated names that are difficult to understand. * Use inconsistent naming styles within the same project. * Use reserved keywords as names. **Why:** Consistent naming improves code readability and maintainability. Clear names reduce ambiguity and make it easier to understand the code's intent. **Example:** **Incorrect:** """c /* BAD: Unclear naming */ int proc(int a, int b); """ **Correct:** """c /* GOOD: Descriptive naming */ int process_commits(int num_commits, int max_commits); """ ### 2.2 Error Handling **Standard:** Implement robust error handling to prevent unexpected behaviors and ensure data integrity. **Do This:** * Check return values of functions and handle errors appropriately. * Use return codes to indicate success or failure. * Use "errno" to provide more detailed error information. * Implement mechanisms for logging and reporting errors. * Use "die()" and "error()" macros provided by Git for consistent error reporting. **Don't Do This:** * Ignore error codes returned by functions. * Assume that functions always succeed. * Use "printf" for error messages; use Git's error reporting functions instead. **Why:** Proper error handling prevents crashes, data corruption, and security vulnerabilities. It also provides valuable information for debugging and diagnosing issues. **Example:** **Incorrect:** """c /* BAD: Ignoring return code */ FILE *fp = fopen("file.txt", "r"); fread(buffer, 1, 1024, fp); fclose(fp); """ **Correct:** """c /* GOOD: Checking return codes */ FILE *fp = fopen("file.txt", "r"); if (!fp) { die("Failed to open file: %s", strerror(errno)); } size_t bytes_read = fread(buffer, 1, 1024, fp); if (bytes_read != 1024) { if (feof(fp)) { fprintf(stderr, "End of file reached before reading full buffer.\n"); } else { die("Failed to read from file: %s", strerror(errno)); } } if (fclose(fp) != 0) { error("Failed to close file: %s", strerror(errno)); } """ ### 2.3 Memory Management **Standard:** Manage memory carefully to avoid memory leaks, dangling pointers, and buffer overflows. **Do This:** * Allocate memory using "xmalloc", "xcalloc", or "xrealloc", which provide error checking. * Free memory using "free" when it is no longer needed. * Use valgrind or other memory debugging tools to detect memory errors. * Be cautious with using buffers and always validate the sizes before performing any operations * Use "strbuf" for string manipulation and dynamic buffers, Git's customized wrapper for dynamic string management. **Don't Do This:** * Allocate memory without freeing it. * Free the same memory multiple times. * Access memory after it has been freed. * Write beyond the bounds of allocated memory. * Use standard memory management functions ("malloc", "calloc", "realloc") directly -- use Git's wrappers. **Why:** Memory errors can lead to crashes, unpredictable behavior, and security vulnerabilities. **Example:** **Incorrect:** """c /* BAD: Potential memory leak */ char *str = malloc(100); strcpy(str, "hello"); /* str is never freed */ """ **Correct:** """c /* GOOD: Allocating and freeing memory */ char *str = xmalloc(100); strcpy(str, "hello"); free(str); str = NULL; /* Set to NULL to prevent dangling pointer */ """ **Correct, Using "strbuf":** """c struct strbuf buf = STRBUF_INIT; strbuf_addstr(&buf, "hello"); printf("%s\n", buf.buf); strbuf_release(&buf); """ ### 2.4 Data Structures and Algorithms **Standard:** Choose appropriate data structures and algorithms to ensure optimal performance and scalability. **Do This:** * Use hash tables for fast lookups. * Use trees for hierarchical data. * Use dynamic arrays for variable-size lists. * Analyze the time and space complexity of algorithms. * Understand and leverage Git's internal data structures where appropriate (e.g. "packed-refs", "object database"). **Don't Do This:** * Use linear search for large datasets. * Use inefficient algorithms that degrade performance. * Ignore the trade-offs between different data structures. **Why:** Efficient data structures and algorithms are crucial for maintaining the performance of Git, especially when dealing with large repositories. **Example:** **Incorrect:** """c /* BAD: Inefficient linear search*/ int find_index(int *array, int size, int value) { for (int i = 0; i < size; i++) { if (array[i] == value) { return i; } } return -1; } """ **Correct:** """c /* GOOD: Using a hash table for faster lookups (example, not actual implementation) */ /* You would need to implement the hash table separately */ struct hash_table *create_hash_table(int size); void hash_table_insert(struct hash_table *table, int key, int value); int hash_table_lookup(struct hash_table *table, int key); /* Assumes you have a hash table implementation */ int find_index_hash(struct hash_table *table, int value) { return hash_table_lookup(table, value); } """ ### 2.5 Concurrency and Thread Safety **Standard:** Handle concurrency carefully and ensure components are thread-safe when necessary. **Do This:** * Use mutexes or other synchronization mechanisms to protect shared data. * Avoid shared mutable state when possible. * Use atomic operations for simple updates. * Consider using thread pools to manage threads efficiently. * Use the appropriate locking mechanisms: "pthread_mutex_t" if POSIX threads are available, or "CRITICAL_SECTION" on Windows. **Don't Do This:** * Access shared data without proper synchronization. * Create race conditions or deadlocks. * Assume that code is thread-safe without proper testing. **Why:** Concurrency can improve performance, but it also introduces the risk of race conditions and deadlocks. Thread safety is crucial for ensuring the stability of Git in multi-threaded environments. **Example:** **Incorrect:** """c /* BAD: Accessing shared data without synchronization */ int counter = 0; void increment_counter() { counter++; /* Race condition */ } """ **Correct:** """c /* GOOD: Using mutex to protect shared data */ #include <pthread.h> int counter = 0; pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER; void increment_counter() { pthread_mutex_lock(&counter_mutex); counter++; pthread_mutex_unlock(&counter_mutex); } """ ### 2.6 Input Validation **Standard:** Validate all input data to prevent security vulnerabilities such as buffer overflows and command injection. **Do This:** * Check the size and format of input data. * Sanitize input to remove harmful characters. * Use safe string handling functions (e.g., "strlcpy", "strlcat"). * Avoid using "system()" or other functions that execute external commands with untrusted input. * Use "xsnprintf" over "snprintf" to additionally zero-terminate the buffer. **Don't Do This:** * Trust input data without validation. * Use unsafe string handling functions (e.g., "strcpy", "strcat"). * Pass untrusted input directly to external commands. **Why:** Input validation is essential for preventing security vulnerabilities and ensuring the integrity of the system. **Example:** **Incorrect:** """c /* BAD: Using strcpy without validation */ char buffer[100]; strcpy(buffer, user_input); /* Buffer overflow possible */ """ **Correct:** """c /* GOOD: Using strlcpy to prevent buffer overflows */ char buffer[100]; strlcpy(buffer, user_input, sizeof(buffer)); """ ### 2.7 Logging and Debugging **Standard:** Implement comprehensive logging and debugging mechanisms to facilitate troubleshooting and performance analysis. **Do This:** * Use informative log messages to track program execution. * Include timestamps, function names, and other relevant information in log messages. * Use debug levels to control the verbosity of logging output. * Use conditional compilation to include debug code in development builds. * Use Git's provided debugging macros and functions. **Don't Do This:** * Use excessive logging that degrades performance. * Include sensitive information in log messages. * Leave debug code enabled in production builds. **Why:** Logging and debugging mechanisms are crucial for identifying and resolving issues in complex systems like Git. **Example:** """c #ifdef DEBUG #define dprintf(fmt, ...) fprintf(stderr, "DEBUG: %s(): " fmt "\n", __func__, ##__VA_ARGS__) #else #define dprintf(fmt, ...) /* noop */ #endif int process_data(int data) { dprintf("Processing data: %d", data); /* ... */ return 0; } """ ### 2.8 Third-Party Libraries **Standard:** Minimize dependencies on third-party libraries. When using third-party code, ensure it is well-maintained, secure, and compatible with Git’s licensing. **Do This:** * Carefully evaluate the necessity and impact of each dependency. * Use only well-established and reputable libraries. * Check the license compatibility of the library. * Keep third-party libraries up-to-date to address security vulnerabilities. * Prefer to statically link third-party dependencies to avoid runtime dependencies. **Don't Do This:** * Introduce unnecessary dependencies. * Use unmaintained or obscure libraries. * Ignore license restrictions. * Use dynamically linked libraries that can introduce compatibility issues. **Why:** Reducing dependencies simplifies the build process, reduces the risk of conflicts, and improves the overall stability of Git. ### 2.9 Code Style and Formatting **Standard:** Follow a consistent code style and formatting to improve readability and maintainability. Use Git's existing code formatting tools and conventions. **Do This:** * Use consistent indentation (e.g., 4 spaces). * Limit line length to 80 characters. * Use blank lines to separate logical blocks of code. * Add comments to explain complex or non-obvious code. * Run clang-format, or other automatic formatting tools, to enforce the code style. **Don't Do This:** * Use inconsistent indentation or spacing. * Write overly long lines of code. * Omit necessary comments. **Why:** Consistent code style improves readability and facilitates collaboration among developers. **Example:** Before formatting: """c int main(int argc, char *argv[]){ int i; for (i=0;i<argc;i++) { printf("Argument %d: %s\n",i,argv[i]); } return 0;} """ After formatting: """c int main(int argc, char *argv[]) { int i; for (i = 0; i < argc; i++) { printf("Argument %d: %s\n", i, argv[i]); } return 0; } """ ### 2.10 Testing **Standard:** Write comprehensive unit tests, integration tests, and end-to-end tests to verify the correctness of components. **Do This:** * Write unit tests for individual functions and components. * Write integration tests to verify the interaction between components. * Write end-to-end tests to verify the overall system behavior. * Use a test-driven development (TDD) approach. * Integrate testing into the continuous integration (CI) pipeline. **Don't Do This:** * Skip writing tests. * Write incomplete or inadequate tests. * Ignore failing tests. **Why:** Thorough testing is essential for ensuring the quality and reliability of Git. ### 2.11 Documentation **Standard:** Components must be well-documented, including API documentation and usage examples. **Do This:** * Document the purpose, usage, and limitations of each component. * Use a documentation generator (like Doxygen) to automatically generate API documentation if feasible . * Provide clear and concise examples of how to use the component. * Keep documentation up-to-date with the latest code changes. **Don't Do This:** * Omit documentation entirely. * Write ambiguous or incomplete documentation. * Fail to update documentation when code changes. **Why:** Good documentation is crucial for making components easy to understand and use. It reduces the learning curve for new developers and facilitates maintenance. These component design standards represent best practices for Git development. Adhering to these standards will contribute to a more maintainable, efficient, and secure codebase.
# Tooling and Ecosystem Standards for Git This document outlines standards for tooling and ecosystem usage within Git development. These standards aim to ensure maintainability, performance, security, and consistency across the codebase while leveraging the capabilities of the Git ecosystem. ## 1. Development Environment Setup ### 1.1. Recommended IDE/Editor **Do This:** * Use IDEs/editors with robust Git integration (e.g., VS Code, IntelliJ IDEA, Sublime Text with plugins). * Configure IDE/editor with Git-aware linters (e.g., "gitlint", "pre-commit" hooks). * Install version control plugins that enhance Git workflow (e.g., GitLens for VS Code). **Don't Do This:** * Rely solely on command-line Git without visual tools for complex operations. * Ignore IDE warnings related to Git configuration or potential conflicts. **Why:** A well-integrated IDE enhances code navigation, conflict resolution, and commit message quality. **Example (VS Code Settings):** """json // settings.json { "git.enableSmartCommit": true, "git.confirmSync": false, "git.autofetch": true, "editor.formatOnSave": true, "files.trimTrailingWhitespace": true } """ **Anti-Pattern:** Using a basic text editor without Git support, leading to manual error-prone workflows. ### 1.2. Configuration Management **Do This:** * Use ".gitconfig" for global Git settings and ".git/config" for repository-specific configurations. * Centralize configuration using include directives in ".gitconfig" for shared settings across projects. * Use environment variables for sensitive configurations like SSH keys or API tokens. **Don't Do This:** * Hardcode project-specific settings globally. * Store sensitive information directly in configuration files. **Why:** Proper configuration management ensures consistency and security across development environments. **Example (.gitconfig Includes):** """gitconfig [include] path = ~/.gitconfig.common [include] path = ~/.gitconfig.user """ **Example (.gitconfig.common):** """gitconfig [user] name = "John Doe" email = "john.doe@example.com" [core] editor = vim [alias] co = checkout br = branch ci = commit st = status df = diff """ **Anti-Pattern:** Duplicating settings across multiple repositories, leading to inconsistency and potential errors. ## 2. Pre-Commit Hooks and Linters ### 2.1. Automated Code Formatting **Do This:** * Implement pre-commit hooks using tools like "pre-commit" to automatically format code (e.g., using "black", "eslint"). * Configure Git to automatically format code on commit. * Use editor extensions like "editorconfig" to maintain consistent coding styles across different editors. **Don't Do This:** * Manually format code; rely on automated tools. * Skip pre-commit hooks during development or CI/CD pipelines. **Why:** Automated formatting enforces code style, improving readability and reducing merge conflicts. **Example (.pre-commit-config.yaml):** """yaml repos: - repo: https://github.com/psf/black rev: 24.3.0 # Use the latest version hooks: - id: black - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.5.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer - id: check-yaml - id: check-added-large-files """ **Anti-Pattern:** Allowing inconsistent code formatting, leading to visual noise and hindering collaboration. ### 2.2. Code Linting and Static Analysis **Do This:** * Integrate linters (e.g., "flake8", "pylint", "eslint") into the pre-commit workflow. * Run static analysis tools (e.g., "mypy", "sonarqube") during CI/CD to detect潛在缺陷. * Address linting and static analysis issues locally before pushing code. **Don't Do This:** * Ignore linting warnings or static analysis findings. * Introduce code with known linting or static analysis issues. **Why:** Linting and static analysis help identify potential errors, enforce coding standards, and improve code quality. **Example (flake8 configuration):** """ini # .flake8 [flake8] max-line-length = 120 ignore = E203, W503 exclude = .git, __pycache__, docs/source/conf.py, old, build, dist """ **Anti-Pattern:** Pushing code with unresolved linting issues, degrading overall code quality. ## 3. Commit Message Conventions ### 3.1. Standardized Commit Message Format **Do This:** * Follow the Conventional Commits specification (e.g., "feat: add new feature", "fix: resolve bug"). * Use a concise subject line (under 50 characters). * Include a detailed body explaining the motivation and changes in the commit. * Reference relevant issue trackers or pull requests in the commit message. **Don't Do This:** * Write vague or uninformative commit messages. * Include extraneous information or personal opinions. **Why:** Consistent commit messages improve project history readability and automate release notes generation. **Example (Conventional Commit):** """ feat: Implement user authentication This commit introduces user authentication functionality with JWT. It includes: - User registration endpoint - User login endpoint - JWT middleware - Authentication tests Refs: #123, #456 """ **Anti-Pattern:** Writing commit messages like "Fixed bug" or "Updated code", which provide no context. ### 3.2. Commit Message Scope **Do This:** * Specify the scope of the commit (e.g., "feat(auth): add login functionality"). * Ensure the scope aligns with the affected module or component. * Use consistent scoping across the project. **Don't Do This:** * Omit scope information or use generic scopes. * Use inconsistent scoping practices. **Why:** Scope improves the granularity of commit messages. **Example (Scoped Commit):** """ fix(api): Resolve rate limiting issue This commit fixes a rate limiting issue in the API endpoint. The issue was caused by an incorrect configuration setting in the rate limiting middleware. Fixes: #789 """ **Anti-Pattern:** Using inconsistent scope. ## 4. Branching Strategies ### 4.1. Gitflow **Do This:** * Utilize Gitflow for project with long-term releases. * Use "develop" for integrating feature branches. * Use "release" branches for preparing releases. * Use "hotfix" branches for addressing critical issues in production. **Don't Do This:** * Commit directly to "master" or "develop" without proper review. * Neglect to merge bug fixes from "release" back to "develop". **Why:** Gitflow provides a structured approach to releasing features and fixing bugs. **Example (Gitflow Workflow):** """bash # Starting a new feature git checkout -b feature/new-feature develop # Developing the feature # ... # Finishing the feature git checkout develop git merge --no-ff feature/new-feature git branch -d feature/new-feature git push origin develop # Starting a release git checkout -b release/1.0.0 develop # Preparing the release # Finishing the release git checkout master git merge --no-ff release/1.0.0 git tag -a 1.0.0 -m "Release 1.0.0" git checkout develop git merge --no-ff release/1.0.0 git branch -d release/1.0.0 git push origin master --tags git push origin develop # Starting hotfix git checkout -b hotfix/1.0.1 master # Fixing the bug # Finishing hotfix git checkout master git merge --no-ff hotfix/1.0.1 git tag -a 1.0.1 -m "Hotfix 1.0.1" git checkout develop git merge --no-ff hotfix/1.0.1 git branch -d hotfix/1.0.1 git push origin master --tags git push origin develop """ **Anti-Pattern:** Ignoring Gitflow conventions. ### 4.2. Feature Branching **Do This:** * Use feature branches to encapuslate changes * Keep feature branches small and focused on a single task or feature. * Regularly rebase feature branches onto the latest "develop" or "main". **Don't Do This:** * Create long-lived feature branches that diverge significantly from the main branch. * Merge large, complex feature branches without thorough review. **Why:** Encourages parallel development, code isolation, and easy revert. **Example (Feature Branching Workflow):** """bash # Create a new feature branch git checkout -b feature/new-feature develop # Develop the feature # ... # Regularly rebase onto develop git fetch origin git rebase origin/develop # Push the feature branch git push origin feature/new-feature # Create a pull request """ **Anti-Pattern:** Neglecting. ### 4.3. Pull Requests/Merge Requests **Do This:** * Create pull requests for all code changes, including bug fixes and enhancements. * Assign reviewers to ensure thorough code review. * Address all feedback and resolve conflicts before merging. * Use pull request templates to standardize the review process. **Don't Do This:** * Merge code without review or testing. * Ignore reviewer feedback or postpone addressing conflicts. **Why:** Pull requests provide a structured mechanism for code review, collaboration, and quality assurance. **Example (Pull Request Template):** """markdown ## Description Please include a summary of the change and which issue is fixed. ## Type of change Please delete options that are not relevant. - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update ## How Has This Been Tested? Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration - [ ] Test A - [ ] Test B ## Checklist: - [ ] My code follows the style guidelines of this project - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes - [ ] Any dependent changes have been merged and published in downstream modules """ **Anti-Pattern:** Bypassing pull request can lead to quality compromise. ## 5. Git Hooks Management ### 5.1. Centralized Hook Configuration **Do This:** * Use a hook management tool (e.g., "husky", "overcommit") to manage Git hooks centrally. * Store hook scripts in the repository to ensure they are version-controlled. * Distribute hooks automatically to all developers upon cloning the repository. **Don't Do This:** * Rely on manually copying hooks to individual ".git/hooks" directories. * Allow developers to modify hooks without proper review. **Why:** Centralized hook management ensures consistency and simplifies hook deployment across the team. **Example (husky configuration in package.json):** """json { "husky": { "hooks": { "pre-commit": "lint-staged", "pre-push": "npm test" } }, "lint-staged": { "*.{js,jsx,ts,tsx,json,md}": [ "prettier --write", "eslint --fix" ] } } """ **Explanation:** This configuration uses "husky" to run "lint-staged" before each commit and "npm test" before each push ensuring code remains within defined standards. **Anti-Pattern:** Individual changes to hooks can create inconsistencies. ### 5.2. Performance Considerations **Do This:** * Optimize hook scripts to execute quickly. * Avoid resource-intensive operations in hooks (e.g., running full test suites on every commit). * Use incremental processing techniques to minimize hook execution time. **Don't Do This:** * Implement slow or inefficient hook scripts that significantly delay Git operations. * Run unnecessary or redundant tasks in hooks. **Why:** Efficient hooks maintain a smooth developer experience and prevent performance bottlenecks. **Example (Incremental processing in a pre-commit hook):** """bash #!/bin/sh # Only lint staged files staged_files=$(git diff --cached --name-only) eslint --fix $staged_files """ **Explanation:** This hook only checks modified file, rather than checking the whole project on every commit. **Anti-Pattern:** Slow hooks will diminish developer productivity. ## 6. Git Attributes and Configuration ### 6.1. Handling Line Endings **Do This:** * Configure "core.autocrlf" and ".gitattributes" to manage line endings consistently across platforms. * Set "core.autocrlf" based on the operating system (e.g., "true" on Windows, "input" on Linux/macOS). * Use ".gitattributes" to specify line ending conversion rules for specific file types. **Don't Do This:** * Ignore line ending issues, leading to potential merge conflicts and file corruption. * Rely on manual line ending conversion or inconsistent settings. **Why:** Consistent line ending management ensures cross-platform compatibility. **Example (.gitattributes):** """ *.txt text eol=lf *.sh text eol=lf *.js text eol=lf *.html text eol=lf *.css text eol=lf *.jpg binary *.png binary """ **Explanation:** This configuration enforces "lf" line endings for text-based files. **Anti-Pattern:** Inconsistent line endings. ### 6.2. Large File Storage (LFS) **Do This:** * Use Git LFS for storing large binary assets (e.g., images, videos, audio files). * Track LFS files in ".gitattributes" using the "filter=lfs" attribute. * Ensure Git LFS is properly initialized and configured for the repository. **Don't Do This:** * Commit large binary files directly into the Git repository. * Neglect to install and configure Git LFS, leading to storage issues and performance degradation. **Why:** Git LFS optimizes storage and improves performance for large binary files. **Example (.gitattributes with LFS):** """ *.png filter=lfs diff=lfs merge=lfs -text *.jpg filter=lfs diff=lfs merge=lfs -text *.zip filter=lfs diff=lfs merge=lfs -text """ **Explanation:** Files with ".png", ".jpg", and ".zip" extensions are tracked using Git LFS. """bash # Initialize Git LFS git lfs install # Track files with LFS git lfs track "*.png" git lfs track "*.jpg" git lfs track "*.zip" # Commit .gitattributes git add .gitattributes git commit -m "Track large files with Git LFS" """ **Anti-Pattern:** Directly committing large binary files. ## 7. Release Management and Tagging ### 7.1. Semantic Versioning **Do This:** * Follow semantic versioning (SemVer) for releases (e.g., "MAJOR.MINOR.PATCH"). * Use tags to mark releases in the Git repository. * Automate the tagging process during the release pipeline. **Don't Do This:** * Use arbitrary or inconsistent versioning schemes. * Manually create tags without proper validation. **Why:** SemVer provides a standardized approach to versioning. **Example (Tagging a release):** """bash git tag -a v1.2.3 -m "Release version 1.2.3" git push origin v1.2.3 """ **Explanation:** It is to create and push a tag using Semantic Versioning **Anti-Pattern:** Not using standard ### 7.2. Release Branching **Do This:** * Create release branches for preparing releases. * Merge bug fixes into the release branch. * Tag the release branch once all changes are merged. **Don't Do This:** * Commit changes directly to the main branch during release preparation.". * Neglect to merge bug fixes from release branch. **Why:** Allows preparing a release without disrupting. **Example (Release Branch Workflow):** """bash # Create release branch git checkout -b release/1.2.3 develop # Make release preparations # Tag the release git checkout master git merge --no-ff release/1.2.3 git tag -a v1.2.3 -m "Release version 1.2.3" # Merge back to develop git checkout develop git merge --no-ff release/1.2.3 """ **Anti-Pattern:** Not using release branching. ## 8. Third-Party Tooling and Ecosystem ### 8.1. Dependency Management **Do This:** * Use a dependency management tool appropriate for the project (e.g., "npm" or "yarn" for "node.js" projects, "pip" for "python" projects). * Declare all dependencies in a manifest file (e.g., "package.json" or "requirements.txt"). * Pin dependency versions to specific releases or version ranges to ensure reproducibility. * Regularly update dependencies to the latest stable versions, keeping track of breaking changes. **Don't Do This:** * Skip dependency management leaving your project in the Stone Age * Commit dependencies directly into the repository * Use outdated or vulnerable dependencies * Use the "latest" tag without version pinning **Why:** Dependency management allows maintaining a predictable, easy-to-create-and-recreate environment. **Example (Python - pip with "requirements.txt"):** """text # requirements.txt requests==2.31.0 beautifulsoup4==4.12.3 Flask==3.0.0 """ """bash pip install -r requirements.txt """ **Example (Node.js - npm):** """json // package.json "dependencies": { " express ": " ^4.18.2 ", " lodash ": " ^4.17.21 ", " axios ": " ^1.6.7 " } """ """bash npm install """ **Anti-Pattern:** Randomly installing different versions of libraries. ### 8.2. Utilizing Git Hosting Platforms (GitHub, GitLab, Bitbucket) **Do This:** * Use Git hosting platforms for remote repository management, pull requests, code review, and CI/CD integration. * Use webhooks to communicate with external services, such as CI/CD pipelines or notification systems. * Leverage platform-specific features, such as GitHub Actions, GitLab CI, or Bitbucket Pipelines. **Don't Do This:** * Try to reinvent the wheel with custom solutions for common tasks that Git hosting platforms provide. * Fail to secure access and permissions to the Git hosting platform. **Git Hub Actions Example:** """yaml # .github/workflows/main.yml name: CI/CD Pipeline on: push: branches: - main pull_request: branches: - main jobs: build: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v3 - name: Set up Node.js uses: actions/setup-node@v3 with: node-version: 18 - name: Install dependencies run: npm install - name: Run linters and formatters run: | npm run lint npm run format - name: Build run: npm run build - name: Test run: npm test deploy: needs: [build] runs-on: ubuntu-latest steps: - name: Deploy run: echo "Deploying to production..." """ **Anti-Pattern:** Ignoring available tools on the git hosting platform. ### 8.3. Documentation Generators **Do This:** * Use tools like Doxygen (for C++), JSDoc (for JavaScript), Sphinx (for python) to automatically generate documentation. * Configure build process to include automatic documentation generation. **Don't Do This:** * Relying solely on manually written documentation. **Why:** Automated makes it easier. """python """ This module provides utility functions for string manipulation. """ def reverse_string(s): """ Reverses the input string. :param s: The input string. :type s: st :raises TypeError: if input is not a string. :returns: The reversed string. :rtype: str :Example: >>> reverse_string("hello") "olleh" """ #Implementation goes here pass """ ### 8.4 Containerization Technologies **Do This:** * Write a "Dockerfile" to package the application and dependencies for a consistent environment. * Use "docker-compose.yml" to orchestrate multi-container environments, especially for complex testing or development setups. **Don't Do This:** * Skip containerization and rely on manually configured environments, which may not be reproducible. * Expose sensitive data or ports without proper security configurations in the container. """dockerfile FROM python:3.11-slim-buster WORKDIR /usr/src/app COPY requirements.txt ./ RUN pip install --no-cache-dir -r requirements.txt COPY . . CMD ["python", "app.py"] """ ## 9. Security Best Practices ### 9.1. Secure Storage of Credentials **Do This:** * Use dedicated secret management tools (e.g., HashiCorp Vault, AWS Secrets Manager) to store sensitive information. * Encrypt secrets at rest and in transit. * Use environment variables instead of hardcoding credentials in code or configuration files. **Don't Do This:** * Store sensitive information (e.g., passwords, API keys) directly in the Git repository or configuration files. * Grant unnecessary access or permissions to sensitive resources. **Why:** Protects your repository from unauthorized access. **Anti-Pattern:** Hardcoding the password. """ my_password="SuperSecretPassword" # This is bad """ ### 9.2. Dependency Vulnerability Scanning **Do This:** * Integrate security scanning tools (e.g., Snyk, OWASP Dependency-Check) into the CI/CD pipeline. * Regularly scan dependencies for known vulnerabilities. * Update vulnerable dependencies to the latest secure versions. **Don't Do This:** * Ignore security vulnerabilities in dependencies. * Continue using outdated or unsupported dependencies with known security issues. **Why:** Stay safe with the updates ### 9.3. Code Review for Security **Do This:** * Conduct thorough code reviews with a focus on security best practices (e.g., input validation, output encoding, authentication, authorization). * Use static analysis tools to identify potential security vulnerabilities in code. * Educate developers about common security pitfalls and secure coding practices. **Don't Do This:** * Bypass code review or ignore potential security issues. ### 9.4. Repository Access Control **Do This:** * Implement granular access control policies based on the principle of least privilege. * Use multi-factor authentication (MFA) for all user accounts. * Regularly audit user access and permissions. * Disable or remove inactive user accounts. **Don't Do This:** * Grant overly permissive access or permissions unintentionally. * Share user accounts. Following these guidelines ensures that the Git environment is robust, consistent, and secure.