Skip to main content
Git follows specific coding standards to maintain consistency and quality across the codebase.

General Principles

POSIX Compatibility

We never say “It’s in POSIX; we’ll ignore your needs.” We live in the real world and support practical platforms.

Avoid Non-POSIX

We often say “Let’s stay away from that construct, it’s not even in POSIX.”

Pragmatic Decisions

Sometimes we use non-POSIX features if they’re convenient and practically all platforms we care about support them.

Minimal Churn

Avoid style fixes for the sake of conforming. “Once it is in the tree, it’s not worth the patch noise to fix it up.”

C Language Standards

C99 Baseline

As of Git v2.35.0, Git requires C99 (checking __STDC_VERSION__).
These features are safe to use:
  • Initializer elements not computable at load time (since 2007)
    const char *args[] = { "constant", variable, NULL };
    
  • Trailing comma in enum definitions (since 2012)
    enum color { RED, GREEN, BLUE, };
    
  • Designated initializers for structs (since mid-2017)
    struct t v = { .val = 'a' };
    
  • Designated initializers for arrays (since mid-2017)
    int array[10] = { [5] = 2 };
    
  • Variadic macros (since early 2021)
    #define trace_printf(fmt, ...) trace2_printf(fmt, __VA_ARGS__)
    
  • Loop variable declarations (since late 2021)
    for (int i = 0; i < 10; i++)
    
  • bool type from <stdbool.h> (since late 2023)
    bool is_valid = true;
    
Under evaluation (do NOT use yet):
  • Compound literals (test balloon since v2.48.0-rc0~20)
    // DO NOT USE - still under evaluation
    (struct foo){ .member = value };
    
Official adoption expected mid-2026.
These C99 features cannot be used:
  • %z printf format for size_t - MinGW C library doesn’t support it
    // DON'T USE
    printf("%zu", size);
    
    // USE INSTEAD
    printf("%"PRIuMAX, (uintmax_t)size);
    
  • Nested designated initializers - IBM XLC v12.01 issue
    // DON'T USE
    .a.b = *c
    
    // USE INSTEAD  
    .a = { .b = *c }
    

Code Style

Indentation and Whitespace

// Use tabs for indentation
if (condition) {
	do_something();
}

Variable Declarations

Variables must be declared at the beginning of the block, before the first statement (per -Wdeclaration-after-statement).
void my_function(void) {
	int result;
	char *buffer;
	struct foo *data;
	// Blank line encouraged
	
	result = do_something();
	...
}

Pointers and NULL

// Star sides with variable name
char *string, c;

// NULL for pointers, not 0
if (ptr == NULL)  // verbose, avoid
if (!ptr)         // preferred

// Don't compare integers/pointers explicitly with 0/NULL
if (!count)       // good
if (count != 0)   // avoid

Whitespace in Expressions

// Spaces around operators and keywords
while (condition)
	func(bar + 1);

// NOT like this:
while( condition )
	func (bar+1);

Braces

// Avoid unnecessary braces
if (condition)
	x = 1;

Comments

/*
 * Multi-line comments have delimiters
 * on separate lines from the text.
 */

/*
 * TRANSLATORS: this comment explains the string below
 * for translators and starts with the magic token.
 */
_("Here is a translatable string");

// We do NOT use // comments

Naming Conventions

Functions and Structures

// Structure named 'struct S'
struct strbuf;

// Functions are 'S_<verb>()' and take 'struct S *' first
void strbuf_add(struct strbuf *buf, ...);
void strbuf_reset(struct strbuf *buf);

// NOT:
void add_string(struct strbuf *buf, ...);  // avoid
void reset_strbuf(struct strbuf *buf);      // avoid
  • S_init() - Initialize without allocating
  • S_release() - Release contents without freeing structure
  • S_clear() - Release + reinitialize for reuse
  • S_free() - Release contents and free structure
struct strbuf buf;
strbuf_init(&buf, 0);     // initialize
// ... use buf ...
strbuf_release(&buf);     // cleanup

struct strbuf *buf = malloc(sizeof(*buf));
strbuf_init(buf, 0);
// ... use buf ...
strbuf_free(buf);         // cleanup and free
Use only when:
  • Function handles one element among a group
  • Separating recursive function from setup
Prefer more descriptive names when possible.
// Acceptable use
static int process_entry_1(struct entry *e);

// Better
static int process_single_entry(struct entry *e);

Configuration Variables

// Section.subsection.variable pattern
core.abbrev
branch.master.remote
remote.origin.url

// Use subsection for unbounded sets (like branch names)
branch.<name>.description  // Good

// NOT variable name for unbounded sets
core.<branchname>.description  // Bad

Arrays

// Singular when items are used individually
char *dog[] = ...;
walk_dog(dog[0]);
walk_dog(dog[1]);

// Plural when array used as a whole  
char *dogs[] = ...;
walk_all_dogs(dogs);

Bit Fields

// No space around colon
unsigned my_field:1;
unsigned other_field:1;
unsigned field_with_longer_name:1;

Include Files

The first #include in C files must be <git-compat-util.h> (except in platform-specific compat/ and sha1dc/).
// Good
#include "git-compat-util.h"
#include "cache.h"
#include "config.h"

// Exceptions - these files include git-compat-util.h:
// - builtin.h (for builtin/*.c)
// - test-tool.h (for t/helper/*.c)  
// - xdiff/xinclude.h (for xdiff/*.c)
// - t/unit-tests/test-lib.h (for t/unit-tests/*.c)
// - reftable/system.h (for reftable/*.c)
C files should directly include headers for functions/types they use, except those provided by required headers.

Error Messages

// First word lowercase (unless proper noun)
die("unable to open '%s'", path);

// NOT:
die("Unable to open '%s'", path);

// Exception - proper nouns stay capitalized
die("SHA-3 not supported");
// Mark for translation
die(_("bad revision %s"), revision);

Shell Scripts

# Use tabs for indentation
case "$variable" in
pattern1)
	do this
	;;
pattern2)
	do that
	;;
esac
# "then" and "do" on next line
if test -f hello
then
	do this
fi

while test -n "$var"
do  
	do something
done

# NOT on same line:
if test -f hello; then  # avoid
# Space before, not after redirection
echo test >"$file"    # correct
cat hello >world <universe

# NOT:
echo test> $file      # wrong
echo test > $file     # wrong
# Use $(...), not backticks
result=$(git rev-parse HEAD)  # good
result=`git rev-parse HEAD`   # avoid - doesn't nest
if test -f file
then
	...
fi

# Avoid:
if [ -f file ]  # works but 'test' preferred

Best Practices

When in doubt, imitate existing code. Matching the surrounding style is more important than following these guidelines exactly.