Hash :
68a3c0b1
Author :
Date :
2018-03-22T09:20:43
We like to keep the source consistent and readable. Herein are some guidelines that should help with that.
We have a few rules to avoid surprising ways of calling functions and some rules for consumers of the library to avoid stepping on each other’s toes.
Property accessors return the value directly (e.g. an int
or
const char *
) but if a function can fail, we return a int
value
and the output parameters go first in the parameter list, followed
by the object that a function is operating on, and then any other
arguments the function may need.
If a function returns an object as a return value, that function is
a getter and the object’s lifetime is tied to the parent
object. Objects which are returned as the first argument as a
pointer-to-pointer are owned by the caller and it is responsible
for freeing it. Strings are returned via git_buf
in order to
allow for re-use and safe freeing.
Most of what libgit2 does relates to I/O so as a general rule you should assume that any function can fail due to errors as even getting data from the filesystem can result in all sorts of errors and complex failure cases.
Paths inside the Git system are separated by a slash (0x2F). If a function accepts a path on disk, then backslashes (0x5C) are also accepted on Windows.
Do not mix allocators. If something has been allocated by libgit2, you do not know which is the right free function in the general case. Use the free functions provided for each object type.
libgit2
runs on many different platforms with many different compilers.
The public API of libgit2
is ANSI C
(a.k.a. C89) compatible.
Internally, libgit2
is written using a portable subset of C99 - in order
to maximize compatibility (e.g. with MSVC) we avoid certain C99
extensions. Specifically, we keep local variable declarations at the tops
of blocks only and we avoid //
style comments.
Also, to the greatest extent possible, we try to avoid lots of #ifdef
s
inside the core code base. This is somewhat unavoidable, but since it can
really hamper maintainability, we keep it to a minimum.
If there is one rule to take away from this document, it is new code should match the surrounding code in a way that makes it impossible to distinguish the new from the old. Consistency is more important to us than anyone’s personal opinion about where braces should be placed or spaces vs. tabs.
If a section of code is being completely rewritten, it is okay to bring it in line with the standards that are laid out here, but we will not accept submissions that contain a large number of changes that are merely reformatting.
All external types and functions start with git_
and all #define
macros
start with GIT_
. The libgit2
API is mostly broken into related
functional modules each with a corresponding header. All functions in a
module should be named like git_modulename_functioname()
(e.g. git_repository_open()
).
Functions with a single output parameter should name that parameter out
.
Multiple outputs should be named foo_out
, bar_out
, etc.
Parameters of type git_oid
should be named id
, or foo_id
. Calls that
return an OID should be named git_foo_id
.
Where a callback function is used, the function should also include a
user-supplied extra input that is a void *
named “payload” that will be
passed through to the callback at each invocation.
Wherever possible, use typedef
. In some cases, if a structure is just a
collection of function pointers, the pointer types don’t need to be
separately typedef’d, but loose function pointer types should be.
All exported functions must be declared as:
GIT_EXTERN(result_type) git_modulename_functionname(arg_list);
Functions whose modulename is followed by two underscores,
for example git_odb__read_packed
, are semi-private functions.
They are primarily intended for use within the library itself,
and may disappear or change their signature in a future release.
Out parameters come first.
Whenever possible, pass argument pointers as const
. Some structures (such
as git_repository
and git_index
) have mutable internal structure that
prevents this.
Callbacks should always take a void *
payload as their last parameter.
Callback pointers are grouped with their payloads, and typically come last
when passed as arguments:
int git_foo(git_repository *repo, git_foo_cb callback, void *payload);
Some APIs allocate memory which the caller is responsible for freeing; others return a pointer into a buffer that’s owned by some other object. Make this explicit in the documentation.
Most public APIs should return an int
error code. As is typical with most
C library functions, a zero value indicates success and a negative value
indicates failure.
Some bindings will transform these returned error codes into exception
types, so returning a semantically appropriate error code is important.
Check
include/git2/errors.h
for the return codes already defined.
In your implementation, use giterr_set()
to provide extended error
information to callers.
If a libgit2
function internally invokes another function that reports an
error, but the error is not propagated up, use giterr_clear()
to prevent
callers from getting the wrong error message later on.
Most public types should be opaque, e.g.:
typedef struct git_odb git_odb;
…with allocation functions returning an “instance” created within the library, and not within the application. This allows the type to grow (or shrink) in size without rebuilding client code.
To preserve ABI compatibility, include an int version
field in all opaque
structures, and initialize to the latest version in the construction call.
Increment the “latest” version whenever the structure changes, and try to only
append to the end of the structure.
If a function’s parameter count is too high, it may be desirable to package up the options in a structure. Make them transparent, include a version field, and provide an initializer constant or constructor. Using these structures should be this easy:
git_foo_options opts = GIT_FOO_OPTIONS_INIT;
opts.baz = BAZ_OPTION_ONE;
git_foo(&opts);
Typedef all enumerated types. If each option stands alone, use the enum
type for passing them as parameters; if they are flags to be OR’ed together,
pass them as unsigned int
or uint32_t
or some appropriate type.
Try to keep lines less than 80 characters long. This is a loose requirement, but going significantly over 80 columns is not nice.
Use common sense to wrap most code lines; public function declarations can use a couple of different styles:
/** All on one line is okay if it fits */
GIT_EXTERN(int) git_foo_simple(git_oid *id);
/** Otherwise one argument per line is a good next step */
GIT_EXTERN(int) git_foo_id(
git_oid **out,
int a,
int b);
Indent with tabs; set your editor’s tab width to 4 for best effect.
Avoid trailing whitespace and only commit Unix-style newlines (i.e. no CRLF
in the repository - just set core.autocrlf
to true if you are writing code
on a Windows machine).
All comments should conform to Doxygen “javadoc” style conventions for formatting the public API documentation. Try to document every parameter, and keep the comments up to date if you change the parameter list.
Use this template when creating a new public header.
#ifndef INCLUDE_git_${filename}_h__
#define INCLUDE_git_${filename}_h__
#include "git/common.h"
/**
* @file git/${filename}.h
* @brief Git some description
* @defgroup git_${filename} some description routines
* @ingroup Git
* @{
*/
GIT_BEGIN_DECL
/* ... definitions ... */
/** @} */
GIT_END_DECL
#endif
All inlined functions must be declared as:
GIT_INLINE(result_type) git_modulename_functionname(arg_list);
GIT_INLINE
(or inline
) should not be used in public headers in order
to preserve ANSI C compatibility.
libgit2
uses the clar testing framework.
All PRs should have corresponding tests.
When adding new tests, we prefer if you attempt to reuse existing test data
(in tests-clar/resources/
) if possible. If you are going to add new test
repositories, please try to strip them of unnecessary files (e.g. sample
hooks, etc).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
# Libgit2 Conventions
We like to keep the source consistent and readable. Herein are some
guidelines that should help with that.
## External API
We have a few rules to avoid surprising ways of calling functions and
some rules for consumers of the library to avoid stepping on each
other's toes.
- Property accessors return the value directly (e.g. an `int` or
`const char *`) but if a function can fail, we return a `int` value
and the output parameters go first in the parameter list, followed
by the object that a function is operating on, and then any other
arguments the function may need.
- If a function returns an object as a return value, that function is
a getter and the object's lifetime is tied to the parent
object. Objects which are returned as the first argument as a
pointer-to-pointer are owned by the caller and it is responsible
for freeing it. Strings are returned via `git_buf` in order to
allow for re-use and safe freeing.
- Most of what libgit2 does relates to I/O so as a general rule
you should assume that any function can fail due to errors as even
getting data from the filesystem can result in all sorts of errors
and complex failure cases.
- Paths inside the Git system are separated by a slash (0x2F). If a
function accepts a path on disk, then backslashes (0x5C) are also
accepted on Windows.
- Do not mix allocators. If something has been allocated by libgit2,
you do not know which is the right free function in the general
case. Use the free functions provided for each object type.
## Compatibility
`libgit2` runs on many different platforms with many different compilers.
The public API of `libgit2` is [ANSI C](http://en.wikipedia.org/wiki/ANSI_C)
(a.k.a. C89) compatible.
Internally, `libgit2` is written using a portable subset of C99 - in order
to maximize compatibility (e.g. with MSVC) we avoid certain C99
extensions. Specifically, we keep local variable declarations at the tops
of blocks only and we avoid `//` style comments.
Also, to the greatest extent possible, we try to avoid lots of `#ifdef`s
inside the core code base. This is somewhat unavoidable, but since it can
really hamper maintainability, we keep it to a minimum.
## Match Surrounding Code
If there is one rule to take away from this document, it is *new code should
match the surrounding code in a way that makes it impossible to distinguish
the new from the old.* Consistency is more important to us than anyone's
personal opinion about where braces should be placed or spaces vs. tabs.
If a section of code is being completely rewritten, it is okay to bring it
in line with the standards that are laid out here, but we will not accept
submissions that contain a large number of changes that are merely
reformatting.
## Naming Things
All external types and functions start with `git_` and all `#define` macros
start with `GIT_`. The `libgit2` API is mostly broken into related
functional modules each with a corresponding header. All functions in a
module should be named like `git_modulename_functioname()`
(e.g. `git_repository_open()`).
Functions with a single output parameter should name that parameter `out`.
Multiple outputs should be named `foo_out`, `bar_out`, etc.
Parameters of type `git_oid` should be named `id`, or `foo_id`. Calls that
return an OID should be named `git_foo_id`.
Where a callback function is used, the function should also include a
user-supplied extra input that is a `void *` named "payload" that will be
passed through to the callback at each invocation.
## Typedefs
Wherever possible, use `typedef`. In some cases, if a structure is just a
collection of function pointers, the pointer types don't need to be
separately typedef'd, but loose function pointer types should be.
## Exports
All exported functions must be declared as:
```c
GIT_EXTERN(result_type) git_modulename_functionname(arg_list);
```
## Internals
Functions whose *modulename* is followed by two underscores,
for example `git_odb__read_packed`, are semi-private functions.
They are primarily intended for use within the library itself,
and may disappear or change their signature in a future release.
## Parameters
Out parameters come first.
Whenever possible, pass argument pointers as `const`. Some structures (such
as `git_repository` and `git_index`) have mutable internal structure that
prevents this.
Callbacks should always take a `void *` payload as their last parameter.
Callback pointers are grouped with their payloads, and typically come last
when passed as arguments:
```c
int git_foo(git_repository *repo, git_foo_cb callback, void *payload);
```
## Memory Ownership
Some APIs allocate memory which the caller is responsible for freeing; others
return a pointer into a buffer that's owned by some other object. Make this
explicit in the documentation.
## Return codes
Most public APIs should return an `int` error code. As is typical with most
C library functions, a zero value indicates success and a negative value
indicates failure.
Some bindings will transform these returned error codes into exception
types, so returning a semantically appropriate error code is important.
Check
[`include/git2/errors.h`](https://github.com/libgit2/libgit2/blob/development/include/git2/errors.h)
for the return codes already defined.
In your implementation, use `giterr_set()` to provide extended error
information to callers.
If a `libgit2` function internally invokes another function that reports an
error, but the error is not propagated up, use `giterr_clear()` to prevent
callers from getting the wrong error message later on.
## Structs
Most public types should be opaque, e.g.:
```C
typedef struct git_odb git_odb;
```
...with allocation functions returning an "instance" created within
the library, and not within the application. This allows the type
to grow (or shrink) in size without rebuilding client code.
To preserve ABI compatibility, include an `int version` field in all opaque
structures, and initialize to the latest version in the construction call.
Increment the "latest" version whenever the structure changes, and try to only
append to the end of the structure.
## Option Structures
If a function's parameter count is too high, it may be desirable to package
up the options in a structure. Make them transparent, include a version
field, and provide an initializer constant or constructor. Using these
structures should be this easy:
```C
git_foo_options opts = GIT_FOO_OPTIONS_INIT;
opts.baz = BAZ_OPTION_ONE;
git_foo(&opts);
```
## Enumerations
Typedef all enumerated types. If each option stands alone, use the enum
type for passing them as parameters; if they are flags to be OR'ed together,
pass them as `unsigned int` or `uint32_t` or some appropriate type.
## Code Layout
Try to keep lines less than 80 characters long. This is a loose
requirement, but going significantly over 80 columns is not nice.
Use common sense to wrap most code lines; public function declarations
can use a couple of different styles:
```c
/** All on one line is okay if it fits */
GIT_EXTERN(int) git_foo_simple(git_oid *id);
/** Otherwise one argument per line is a good next step */
GIT_EXTERN(int) git_foo_id(
git_oid **out,
int a,
int b);
```
Indent with tabs; set your editor's tab width to 4 for best effect.
Avoid trailing whitespace and only commit Unix-style newlines (i.e. no CRLF
in the repository - just set `core.autocrlf` to true if you are writing code
on a Windows machine).
## Documentation
All comments should conform to Doxygen "javadoc" style conventions for
formatting the public API documentation. Try to document every parameter,
and keep the comments up to date if you change the parameter list.
## Public Header Template
Use this template when creating a new public header.
```C
#ifndef INCLUDE_git_${filename}_h__
#define INCLUDE_git_${filename}_h__
#include "git/common.h"
/**
* @file git/${filename}.h
* @brief Git some description
* @defgroup git_${filename} some description routines
* @ingroup Git
* @{
*/
GIT_BEGIN_DECL
/* ... definitions ... */
/** @} */
GIT_END_DECL
#endif
```
## Inlined functions
All inlined functions must be declared as:
```C
GIT_INLINE(result_type) git_modulename_functionname(arg_list);
```
`GIT_INLINE` (or `inline`) should not be used in public headers in order
to preserve ANSI C compatibility.
## Tests
`libgit2` uses the [clar](https://github.com/vmg/clar) testing framework.
All PRs should have corresponding tests.
* If the PR fixes an existing issue, the test should fail prior to applying
the PR and succeed after applying it.
* If the PR is for new functionality, then the tests should exercise that
new functionality to a certain extent. We don't require 100% coverage
right now (although we are getting stricter over time).
When adding new tests, we prefer if you attempt to reuse existing test data
(in `tests-clar/resources/`) if possible. If you are going to add new test
repositories, please try to strip them of unnecessary files (e.g. sample
hooks, etc).