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
ea9e2c1a
Unverified
Commit
ea9e2c1a
authored
Jul 20, 2018
by
Patrick Steinhardt
Committed by
GitHub
Jul 20, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #4692 from tiennou/examples/checkout
Add a checkout example
parents
0652abaa
b24202e1
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
309 additions
and
23 deletions
+309
-23
examples/checkout.c
+235
-0
examples/common.c
+44
-0
examples/common.h
+14
-0
examples/merge.c
+0
-23
include/git2/annotated_commit.h
+9
-0
src/annotated_commit.c
+7
-0
No files found.
examples/checkout.c
0 → 100644
View file @
ea9e2c1a
/*
* libgit2 "checkout" example - shows how to perform checkouts
*
* Written by the libgit2 contributors
*
* To the extent possible under law, the author(s) have dedicated all copyright
* and related and neighboring rights to this software to the public domain
* worldwide. This software is distributed without any warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication along
* with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include "common.h"
#include <assert.h>
/* Define the printf format specifer to use for size_t output */
#if defined(_MSC_VER) || defined(__MINGW32__)
# define PRIuZ "Iu"
# define PRIxZ "Ix"
# define PRIdZ "Id"
#else
# define PRIuZ "zu"
# define PRIxZ "zx"
# define PRIdZ "zd"
#endif
/**
* The following example demonstrates how to do checkouts with libgit2.
*
* Recognized options are :
* --force: force the checkout to happen.
* --[no-]progress: show checkout progress, on by default.
* --perf: show performance data.
*/
typedef
struct
{
int
force
:
1
;
int
progress
:
1
;
int
perf
:
1
;
}
checkout_options
;
static
void
print_usage
(
void
)
{
fprintf
(
stderr
,
"usage: checkout [options] <branch>
\n
"
"Options are :
\n
"
" --git-dir: use the following git repository.
\n
"
" --force: force the checkout.
\n
"
" --[no-]progress: show checkout progress.
\n
"
" --perf: show performance data.
\n
"
);
exit
(
1
);
}
static
void
parse_options
(
const
char
**
repo_path
,
checkout_options
*
opts
,
struct
args_info
*
args
)
{
if
(
args
->
argc
<=
1
)
print_usage
();
memset
(
opts
,
0
,
sizeof
(
*
opts
));
/* Default values */
opts
->
progress
=
1
;
for
(
args
->
pos
=
1
;
args
->
pos
<
args
->
argc
;
++
args
->
pos
)
{
const
char
*
curr
=
args
->
argv
[
args
->
pos
];
int
bool_arg
;
if
(
strcmp
(
curr
,
"--"
)
==
0
)
{
break
;
}
else
if
(
!
strcmp
(
curr
,
"--force"
))
{
opts
->
force
=
1
;
}
else
if
(
match_bool_arg
(
&
bool_arg
,
args
,
"--progress"
))
{
opts
->
progress
=
bool_arg
;
}
else
if
(
match_bool_arg
(
&
bool_arg
,
args
,
"--perf"
))
{
opts
->
perf
=
bool_arg
;
}
else
if
(
match_str_arg
(
repo_path
,
args
,
"--git-dir"
))
{
continue
;
}
else
{
break
;
}
}
}
/**
* This function is called to report progression, ie. it's called once with
* a NULL path and the number of total steps, then for each subsequent path,
* the current completed_step value.
*/
static
void
print_checkout_progress
(
const
char
*
path
,
size_t
completed_steps
,
size_t
total_steps
,
void
*
payload
)
{
(
void
)
payload
;
if
(
path
==
NULL
)
{
printf
(
"checkout started: %"
PRIuZ
" steps
\n
"
,
total_steps
);
}
else
{
printf
(
"checkout: %s %"
PRIuZ
"/%"
PRIuZ
"
\n
"
,
path
,
completed_steps
,
total_steps
);
}
}
/**
* This function is called when the checkout completes, and is used to report the
* number of syscalls performed.
*/
static
void
print_perf_data
(
const
git_checkout_perfdata
*
perfdata
,
void
*
payload
)
{
(
void
)
payload
;
printf
(
"perf: stat: %"
PRIuZ
" mkdir: %"
PRIuZ
" chmod: %"
PRIuZ
"
\n
"
,
perfdata
->
stat_calls
,
perfdata
->
mkdir_calls
,
perfdata
->
chmod_calls
);
}
/**
* This is the main "checkout <branch>" function, responsible for performing
* a branch-based checkout.
*/
static
int
perform_checkout_ref
(
git_repository
*
repo
,
git_annotated_commit
*
target
,
checkout_options
*
opts
)
{
git_checkout_options
checkout_opts
=
GIT_CHECKOUT_OPTIONS_INIT
;
git_commit
*
target_commit
=
NULL
;
int
err
;
/** Setup our checkout options from the parsed options */
checkout_opts
.
checkout_strategy
=
GIT_CHECKOUT_SAFE
;
if
(
opts
->
force
)
checkout_opts
.
checkout_strategy
=
GIT_CHECKOUT_FORCE
;
if
(
opts
->
progress
)
checkout_opts
.
progress_cb
=
print_checkout_progress
;
if
(
opts
->
perf
)
checkout_opts
.
perfdata_cb
=
print_perf_data
;
/** Grab the commit we're interested to move to */
err
=
git_commit_lookup
(
&
target_commit
,
repo
,
git_annotated_commit_id
(
target
));
if
(
err
!=
0
)
{
fprintf
(
stderr
,
"failed to lookup commit: %s
\n
"
,
giterr_last
()
->
message
);
goto
cleanup
;
}
/**
* Perform the checkout so the workdir corresponds to what target_commit
* contains.
*
* Note that it's okay to pass a git_commit here, because it will be
* peeled to a tree.
*/
err
=
git_checkout_tree
(
repo
,
(
const
git_object
*
)
target_commit
,
&
checkout_opts
);
if
(
err
!=
0
)
{
fprintf
(
stderr
,
"failed to checkout tree: %s
\n
"
,
giterr_last
()
->
message
);
goto
cleanup
;
}
/**
* Now that the checkout has completed, we have to update HEAD.
*
* Depending on the "origin" of target (ie. it's an OID or a branch name),
* we might need to detach HEAD.
*/
if
(
git_annotated_commit_ref
(
target
))
{
err
=
git_repository_set_head
(
repo
,
git_annotated_commit_ref
(
target
));
}
else
{
err
=
git_repository_set_head_detached_from_annotated
(
repo
,
target
);
}
if
(
err
!=
0
)
{
fprintf
(
stderr
,
"failed to update HEAD reference: %s
\n
"
,
giterr_last
()
->
message
);
goto
cleanup
;
}
cleanup:
git_commit_free
(
target_commit
);
return
err
;
}
/** That example's entry point */
int
main
(
int
argc
,
char
**
argv
)
{
git_repository
*
repo
=
NULL
;
struct
args_info
args
=
ARGS_INFO_INIT
;
checkout_options
opts
;
git_repository_state_t
state
;
git_annotated_commit
*
checkout_target
=
NULL
;
int
err
=
0
;
const
char
*
path
=
"."
;
/** Parse our command line options */
parse_options
(
&
path
,
&
opts
,
&
args
);
/** Initialize the library */
err
=
git_libgit2_init
();
if
(
!
err
)
check_lg2
(
err
,
"Failed to initialize libgit2"
,
NULL
);
/** Open the repository corresponding to the options */
check_lg2
(
git_repository_open_ext
(
&
repo
,
path
,
0
,
NULL
),
"Could not open repository"
,
NULL
);
/** Make sure we're not about to checkout while something else is going on */
state
=
git_repository_state
(
repo
);
if
(
state
!=
GIT_REPOSITORY_STATE_NONE
)
{
fprintf
(
stderr
,
"repository is in unexpected state %d
\n
"
,
state
);
goto
cleanup
;
}
if
(
args
.
pos
>=
args
.
argc
)
{
fprintf
(
stderr
,
"unhandled
\n
"
);
err
=
-
1
;
goto
cleanup
;
}
else
if
(
strcmp
(
"--"
,
args
.
argv
[
args
.
pos
]))
{
/**
* Try to checkout the given path
*/
fprintf
(
stderr
,
"unhandled path-based checkout
\n
"
);
err
=
1
;
goto
cleanup
;
}
else
{
/**
* Try to resolve a "refish" argument to a target libgit2 can use
*/
err
=
resolve_refish
(
&
checkout_target
,
repo
,
args
.
argv
[
args
.
pos
]);
if
(
err
!=
0
)
{
fprintf
(
stderr
,
"failed to resolve %s: %s
\n
"
,
args
.
argv
[
args
.
pos
],
giterr_last
()
->
message
);
goto
cleanup
;
}
err
=
perform_checkout_ref
(
repo
,
checkout_target
,
&
opts
);
}
cleanup:
git_annotated_commit_free
(
checkout_target
);
git_repository_free
(
repo
);
git_libgit2_shutdown
();
return
err
;
}
examples/common.c
View file @
ea9e2c1a
...
...
@@ -12,6 +12,8 @@
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include <assert.h>
#include "common.h"
void
check_lg2
(
int
error
,
const
char
*
message
,
const
char
*
extra
)
...
...
@@ -182,6 +184,25 @@ static int match_int_internal(
return
1
;
}
int
match_bool_arg
(
int
*
out
,
struct
args_info
*
args
,
const
char
*
opt
)
{
const
char
*
found
=
args
->
argv
[
args
->
pos
];
if
(
!
strcmp
(
found
,
opt
))
{
*
out
=
1
;
return
1
;
}
if
(
!
strncmp
(
found
,
"--no-"
,
strlen
(
"--no-"
))
&&
!
strcmp
(
found
+
strlen
(
"--no-"
),
opt
+
2
))
{
*
out
=
0
;
return
1
;
}
*
out
=
-
1
;
return
0
;
}
int
is_integer
(
int
*
out
,
const
char
*
str
,
int
allow_negative
)
{
return
match_int_internal
(
out
,
str
,
allow_negative
,
NULL
);
...
...
@@ -245,3 +266,26 @@ void *xrealloc(void *oldp, size_t newsz)
return
p
;
}
int
resolve_refish
(
git_annotated_commit
**
commit
,
git_repository
*
repo
,
const
char
*
refish
)
{
git_reference
*
ref
;
git_object
*
obj
;
int
err
=
0
;
assert
(
commit
!=
NULL
);
err
=
git_reference_dwim
(
&
ref
,
repo
,
refish
);
if
(
err
==
GIT_OK
)
{
git_annotated_commit_from_ref
(
commit
,
repo
,
ref
);
git_reference_free
(
ref
);
return
0
;
}
err
=
git_revparse_single
(
&
obj
,
repo
,
refish
);
if
(
err
==
GIT_OK
)
{
err
=
git_annotated_commit_lookup
(
commit
,
repo
,
git_object_id
(
obj
));
git_object_free
(
obj
);
}
return
err
;
}
examples/common.h
View file @
ea9e2c1a
...
...
@@ -91,6 +91,15 @@ extern int match_int_arg(
int
*
out
,
struct
args_info
*
args
,
const
char
*
opt
,
int
allow_negative
);
/**
* Check current `args` entry against a "bool" `opt` (ie. --[no-]progress).
* If `opt` matches positively, out will be set to 1, or if `opt` matches
* negatively, out will be set to 0, and in both cases 1 will be returned.
* If neither the positive or the negative form of opt matched, out will be -1,
* and 0 will be returned.
*/
extern
int
match_bool_arg
(
int
*
out
,
struct
args_info
*
args
,
const
char
*
opt
);
/**
* Basic output function for plain text diff output
* Pass `FILE*` such as `stdout` or `stderr` as payload (or NULL == `stdout`)
*/
...
...
@@ -108,3 +117,8 @@ extern void treeish_to_tree(
* A realloc that exits on failure
*/
extern
void
*
xrealloc
(
void
*
oldp
,
size_t
newsz
);
/**
* Convert a refish to an annotated commit.
*/
extern
int
resolve_refish
(
git_annotated_commit
**
commit
,
git_repository
*
repo
,
const
char
*
refish
);
examples/merge.c
View file @
ea9e2c1a
...
...
@@ -87,29 +87,6 @@ static void parse_options(const char **repo_path, merge_options *opts, int argc,
}
}
static
int
resolve_refish
(
git_annotated_commit
**
commit
,
git_repository
*
repo
,
const
char
*
refish
)
{
git_reference
*
ref
;
int
err
=
0
;
git_oid
oid
;
assert
(
commit
!=
NULL
);
err
=
git_reference_dwim
(
&
ref
,
repo
,
refish
);
if
(
err
==
GIT_OK
)
{
git_annotated_commit_from_ref
(
commit
,
repo
,
ref
);
git_reference_free
(
ref
);
return
0
;
}
err
=
git_oid_fromstr
(
&
oid
,
refish
);
if
(
err
==
GIT_OK
)
{
err
=
git_annotated_commit_lookup
(
commit
,
repo
,
&
oid
);
}
return
err
;
}
static
int
resolve_heads
(
git_repository
*
repo
,
merge_options
*
opts
)
{
git_annotated_commit
**
annotated
=
calloc
(
opts
->
heads_count
,
sizeof
(
git_annotated_commit
*
));
...
...
include/git2/annotated_commit.h
View file @
ea9e2c1a
...
...
@@ -104,6 +104,15 @@ GIT_EXTERN(const git_oid *) git_annotated_commit_id(
const
git_annotated_commit
*
commit
);
/**
* Get the refname that the given `git_annotated_commit` refers to.
*
* @param commit the given annotated commit
* @return ref name.
*/
GIT_EXTERN
(
const
char
*
)
git_annotated_commit_ref
(
const
git_annotated_commit
*
commit
);
/**
* Frees a `git_annotated_commit`.
*
* @param commit annotated commit to free
...
...
src/annotated_commit.c
View file @
ea9e2c1a
...
...
@@ -196,6 +196,13 @@ const git_oid *git_annotated_commit_id(
return
git_commit_id
(
annotated_commit
->
commit
);
}
const
char
*
git_annotated_commit_ref
(
const
git_annotated_commit
*
annotated_commit
)
{
assert
(
annotated_commit
);
return
annotated_commit
->
ref_name
;
}
void
git_annotated_commit_free
(
git_annotated_commit
*
annotated_commit
)
{
if
(
annotated_commit
==
NULL
)
...
...
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