Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
G
git2
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lvzhengyang
git2
Commits
b2be62fd
Commit
b2be62fd
authored
Aug 16, 2013
by
Vicent Martí
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1790 from libgit2/examples-init
Add "git init"-like example
parents
68458e42
0ea41445
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
337 additions
and
2 deletions
+337
-2
examples/Makefile
+1
-1
examples/init.c
+245
-0
include/git2/signature.h
+13
-0
src/signature.c
+18
-1
tests-clar/repo/init.c
+60
-0
No files found.
examples/Makefile
View file @
b2be62fd
...
...
@@ -3,7 +3,7 @@
CC
=
gcc
CFLAGS
=
-g
-I
../include
-I
../src
-Wall
-Wextra
-Wmissing-prototypes
-Wno-missing-field-initializers
LFLAGS
=
-L
../build
-lgit2
-lz
APPS
=
general showindex diff rev-list cat-file status log rev-parse
APPS
=
general showindex diff rev-list cat-file status log rev-parse
init
all
:
$(APPS)
...
...
examples/init.c
0 → 100644
View file @
b2be62fd
/*
* This is a sample program that is similar to "git init". See the
* documentation for that (try "git help init") to understand what this
* program is emulating.
*
* This demonstrates using the libgit2 APIs to initialize a new repository.
*
* This also contains a special additional option that regular "git init"
* does not support which is "--initial-commit" to make a first empty commit.
* That is demonstrated in the "create_initial_commit" helper function.
*
* Copyright (C) the libgit2 contributors. All rights reserved.
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#include <stdio.h>
#include <git2.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
/* not actually good error handling */
static
void
fail
(
const
char
*
msg
,
const
char
*
arg
)
{
if
(
arg
)
fprintf
(
stderr
,
"%s %s
\n
"
,
msg
,
arg
);
else
fprintf
(
stderr
,
"%s
\n
"
,
msg
);
exit
(
1
);
}
static
void
usage
(
const
char
*
error
,
const
char
*
arg
)
{
fprintf
(
stderr
,
"error: %s '%s'
\n
"
,
error
,
arg
);
fprintf
(
stderr
,
"usage: init [-q | --quiet] [--bare] "
"[--template=<dir>] [--shared[=perms]] <directory>
\n
"
);
exit
(
1
);
}
/* simple string prefix test used in argument parsing */
static
size_t
is_prefixed
(
const
char
*
arg
,
const
char
*
pfx
)
{
size_t
len
=
strlen
(
pfx
);
return
!
strncmp
(
arg
,
pfx
,
len
)
?
len
:
0
;
}
/* parse the tail of the --shared= argument */
static
uint32_t
parse_shared
(
const
char
*
shared
)
{
if
(
!
strcmp
(
shared
,
"false"
)
||
!
strcmp
(
shared
,
"umask"
))
return
GIT_REPOSITORY_INIT_SHARED_UMASK
;
else
if
(
!
strcmp
(
shared
,
"true"
)
||
!
strcmp
(
shared
,
"group"
))
return
GIT_REPOSITORY_INIT_SHARED_GROUP
;
else
if
(
!
strcmp
(
shared
,
"all"
)
||
!
strcmp
(
shared
,
"world"
)
||
!
strcmp
(
shared
,
"everybody"
))
return
GIT_REPOSITORY_INIT_SHARED_ALL
;
else
if
(
shared
[
0
]
==
'0'
)
{
long
val
;
char
*
end
=
NULL
;
val
=
strtol
(
shared
+
1
,
&
end
,
8
);
if
(
end
==
shared
+
1
||
*
end
!=
0
)
usage
(
"invalid octal value for --shared"
,
shared
);
return
(
uint32_t
)
val
;
}
else
usage
(
"unknown value for --shared"
,
shared
);
return
0
;
}
/* forward declaration of helper to make an empty parent-less commit */
static
void
create_initial_commit
(
git_repository
*
repo
);
int
main
(
int
argc
,
char
*
argv
[])
{
git_repository
*
repo
=
NULL
;
int
no_options
=
1
,
quiet
=
0
,
bare
=
0
,
initial_commit
=
0
,
i
;
uint32_t
shared
=
GIT_REPOSITORY_INIT_SHARED_UMASK
;
const
char
*
template
=
NULL
,
*
gitdir
=
NULL
,
*
dir
=
NULL
;
size_t
pfxlen
;
git_threads_init
();
/* Process arguments */
for
(
i
=
1
;
i
<
argc
;
++
i
)
{
char
*
a
=
argv
[
i
];
if
(
a
[
0
]
==
'-'
)
no_options
=
0
;
if
(
a
[
0
]
!=
'-'
)
{
if
(
dir
!=
NULL
)
usage
(
"extra argument"
,
a
);
dir
=
a
;
}
else
if
(
!
strcmp
(
a
,
"-q"
)
||
!
strcmp
(
a
,
"--quiet"
))
quiet
=
1
;
else
if
(
!
strcmp
(
a
,
"--bare"
))
bare
=
1
;
else
if
((
pfxlen
=
is_prefixed
(
a
,
"--template="
))
>
0
)
template
=
a
+
pfxlen
;
else
if
(
!
strcmp
(
a
,
"--separate-git-dir"
))
gitdir
=
argv
[
++
i
];
else
if
((
pfxlen
=
is_prefixed
(
a
,
"--separate-git-dir="
))
>
0
)
gitdir
=
a
+
pfxlen
;
else
if
(
!
strcmp
(
a
,
"--shared"
))
shared
=
GIT_REPOSITORY_INIT_SHARED_GROUP
;
else
if
((
pfxlen
=
is_prefixed
(
a
,
"--shared="
))
>
0
)
shared
=
parse_shared
(
a
+
pfxlen
);
else
if
(
!
strcmp
(
a
,
"--initial-commit"
))
initial_commit
=
1
;
else
usage
(
"unknown option"
,
a
);
}
if
(
!
dir
)
usage
(
"must specify directory to init"
,
NULL
);
/* Initialize repository */
if
(
no_options
)
{
/* No options were specified, so let's demonstrate the default
* simple case of git_repository_init() API usage...
*/
if
(
git_repository_init
(
&
repo
,
dir
,
0
)
<
0
)
fail
(
"Could not initialize repository"
,
dir
);
}
else
{
/* Some command line options were specified, so we'll use the
* extended init API to handle them
*/
git_repository_init_options
opts
=
GIT_REPOSITORY_INIT_OPTIONS_INIT
;
if
(
bare
)
opts
.
flags
|=
GIT_REPOSITORY_INIT_BARE
;
if
(
template
)
{
opts
.
flags
|=
GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE
;
opts
.
template_path
=
template
;
}
if
(
gitdir
)
{
/* if you specified a separate git directory, then initialize
* the repository at that path and use the second path as the
* working directory of the repository (with a git-link file)
*/
opts
.
workdir_path
=
dir
;
dir
=
gitdir
;
}
if
(
shared
!=
0
)
opts
.
mode
=
shared
;
if
(
git_repository_init_ext
(
&
repo
,
dir
,
&
opts
)
<
0
)
fail
(
"Could not initialize repository"
,
dir
);
}
/* Print a message to stdout like "git init" does */
if
(
!
quiet
)
{
if
(
bare
||
gitdir
)
dir
=
git_repository_path
(
repo
);
else
dir
=
git_repository_workdir
(
repo
);
printf
(
"Initialized empty Git repository in %s
\n
"
,
dir
);
}
/* As an extension to the basic "git init" command, this example
* gives the option to create an empty initial commit. This is
* mostly to demonstrate what it takes to do that, but also some
* people like to have that empty base commit in their repo.
*/
if
(
initial_commit
)
{
create_initial_commit
(
repo
);
printf
(
"Created empty initial commit
\n
"
);
}
git_repository_free
(
repo
);
git_threads_shutdown
();
return
0
;
}
/* Unlike regular "git init", this example shows how to create an initial
* empty commit in the repository. This is the helper function that does
* that.
*/
static
void
create_initial_commit
(
git_repository
*
repo
)
{
git_signature
*
sig
;
git_index
*
index
;
git_oid
tree_id
,
commit_id
;
git_tree
*
tree
;
/* First use the config to initialize a commit signature for the user */
if
(
git_signature_default
(
&
sig
,
repo
)
<
0
)
fail
(
"Unable to create a commit signature."
,
"Perhaps 'user.name' and 'user.email' are not set"
);
/* Now let's create an empty tree for this commit */
if
(
git_repository_index
(
&
index
,
repo
)
<
0
)
fail
(
"Could not open repository index"
,
NULL
);
/* Outside of this example, you could call git_index_add_bypath()
* here to put actual files into the index. For our purposes, we'll
* leave it empty for now.
*/
if
(
git_index_write_tree
(
&
tree_id
,
index
)
<
0
)
fail
(
"Unable to write initial tree from index"
,
NULL
);
git_index_free
(
index
);
if
(
git_tree_lookup
(
&
tree
,
repo
,
&
tree_id
)
<
0
)
fail
(
"Could not look up initial tree"
,
NULL
);
/* Ready to create the initial commit
*
* Normally creating a commit would involve looking up the current
* HEAD commit and making that be the parent of the initial commit,
* but here this is the first commit so there will be no parent.
*/
if
(
git_commit_create_v
(
&
commit_id
,
repo
,
"HEAD"
,
sig
,
sig
,
NULL
,
"Initial commit"
,
tree
,
0
)
<
0
)
fail
(
"Could not create the initial commit"
,
NULL
);
/* Clean up so we don't leak memory */
git_tree_free
(
tree
);
git_signature_free
(
sig
);
}
include/git2/signature.h
View file @
b2be62fd
...
...
@@ -48,6 +48,19 @@ GIT_EXTERN(int) git_signature_new(git_signature **out, const char *name, const c
*/
GIT_EXTERN
(
int
)
git_signature_now
(
git_signature
**
out
,
const
char
*
name
,
const
char
*
email
);
/**
* Create a new action signature with default user and now timestamp.
*
* This looks up the user.name and user.email from the configuration and
* uses the current time as the timestamp, and creates a new signature
* based on that information. It will return GIT_ENOTFOUND if either the
* user.name or user.email are not set.
*
* @param out new signature
* @param repo repository pointer
* @return 0 on success, GIT_ENOTFOUND if config is missing, or error code
*/
GIT_EXTERN
(
int
)
git_signature_default
(
git_signature
**
out
,
git_repository
*
repo
);
/**
* Create a copy of an existing signature. All internal strings are also
...
...
src/signature.c
View file @
b2be62fd
...
...
@@ -74,7 +74,7 @@ int git_signature_new(git_signature **sig_out, const char *name, const char *ema
git_signature_free
(
p
);
return
signature_error
(
"Signature cannot have an empty name"
);
}
p
->
when
.
time
=
time
;
p
->
when
.
offset
=
offset
;
...
...
@@ -129,6 +129,23 @@ int git_signature_now(git_signature **sig_out, const char *name, const char *ema
return
0
;
}
int
git_signature_default
(
git_signature
**
out
,
git_repository
*
repo
)
{
int
error
;
git_config
*
cfg
;
const
char
*
user_name
,
*
user_email
;
if
((
error
=
git_repository_config
(
&
cfg
,
repo
))
<
0
)
return
error
;
if
(
!
(
error
=
git_config_get_string
(
&
user_name
,
cfg
,
"user.name"
))
&&
!
(
error
=
git_config_get_string
(
&
user_email
,
cfg
,
"user.email"
)))
error
=
git_signature_now
(
out
,
user_name
,
user_email
);
git_config_free
(
cfg
);
return
error
;
}
int
git_signature__parse
(
git_signature
*
sig
,
const
char
**
buffer_out
,
const
char
*
buffer_end
,
const
char
*
header
,
char
ender
)
{
...
...
tests-clar/repo/init.c
View file @
b2be62fd
...
...
@@ -530,3 +530,63 @@ void test_repo_init__can_reinit_an_initialized_repository(void)
git_repository_free
(
reinit
);
}
void
test_repo_init__init_with_initial_commit
(
void
)
{
git_index
*
index
;
cl_set_cleanup
(
&
cleanup_repository
,
"committed"
);
/* Initialize the repository */
cl_git_pass
(
git_repository_init
(
&
_repo
,
"committed"
,
0
));
/* Init will be automatically created when requested for a new repo */
cl_git_pass
(
git_repository_index
(
&
index
,
_repo
));
/* Create a file so we can commit it
*
* If you are writing code outside the test suite, you can create this
* file any way that you like, such as:
* FILE *fp = fopen("committed/file.txt", "w");
* fputs("some stuff\n", fp);
* fclose(fp);
* We like to use the help functions because they do error detection
* in a way that's easily compatible with our test suite.
*/
cl_git_mkfile
(
"committed/file.txt"
,
"some stuff
\n
"
);
/* Add file to the index */
cl_git_pass
(
git_index_add_bypath
(
index
,
"file.txt"
));
cl_git_pass
(
git_index_write
(
index
));
/* Make sure we're ready to use git_signature_default :-) */
{
git_config
*
cfg
,
*
local
;
cl_git_pass
(
git_repository_config
(
&
cfg
,
_repo
));
cl_git_pass
(
git_config_open_level
(
&
local
,
cfg
,
GIT_CONFIG_LEVEL_LOCAL
));
cl_git_pass
(
git_config_set_string
(
local
,
"user.name"
,
"Test User"
));
cl_git_pass
(
git_config_set_string
(
local
,
"user.email"
,
"t@example.com"
));
git_config_free
(
local
);
git_config_free
(
cfg
);
}
/* Create a commit with the new contents of the index */
{
git_signature
*
sig
;
git_oid
tree_id
,
commit_id
;
git_tree
*
tree
;
cl_git_pass
(
git_signature_default
(
&
sig
,
_repo
));
cl_git_pass
(
git_index_write_tree
(
&
tree_id
,
index
));
cl_git_pass
(
git_tree_lookup
(
&
tree
,
_repo
,
&
tree_id
));
cl_git_pass
(
git_commit_create_v
(
&
commit_id
,
_repo
,
"HEAD"
,
sig
,
sig
,
NULL
,
"First"
,
tree
,
0
));
git_tree_free
(
tree
);
git_signature_free
(
sig
);
}
git_index_free
(
index
);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment