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
b0ca1b18
Commit
b0ca1b18
authored
Jul 02, 2014
by
Vicent Marti
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #2452 from libgit2/cmn/clone-custom-repo
Provide a callback to customize the repository on clone
parents
de3cf801
6812afaf
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
118 additions
and
148 deletions
+118
-148
CHANGELOG.md
+7
-0
include/git2/clone.h
+36
-56
src/clone.c
+20
-5
tests/clone/local.c
+8
-20
tests/clone/nonetwork.c
+0
-17
tests/network/fetchlocal.c
+25
-10
tests/online/clone.c
+22
-40
No files found.
CHANGELOG.md
View file @
b0ca1b18
...
...
@@ -25,3 +25,10 @@ v0.21 + 1
The remote_callbacks member has been preserved for convenience, although it
is not used when a remote creation callback is supplied.
*
The git_clone_options struct now provides repository_cb and
repository_cb_payload to allow the user to create a repository with
custom options.
*
git_clone_into and git_clone_local_into have been removed from the
public API in favour of git_clone callbacks
include/git2/clone.h
View file @
b0ca1b18
...
...
@@ -74,6 +74,26 @@ typedef int (*git_remote_create_cb)(
void
*
payload
);
/**
* The signature of a function matchin git_repository_init, with an
* aditional void * as callback payload.
*
* Callers of git_clone my provide a function matching this signature
* to override the repository creation and customization process
* during a clone operation.
*
* @param out the resulting repository
* @param path path in which to create the repository
* @param bare whether the repository is bare. This is the value from the clone options
* @param payload payload specified by the options
* @return 0, or a negative value to indicate error
*/
typedef
int
(
*
git_repository_create_cb
)(
git_repository
**
out
,
const
char
*
path
,
int
bare
,
void
*
payload
);
/**
* Clone options structure
*
* Use the GIT_CLONE_OPTIONS_INIT to get the default settings, like this:
...
...
@@ -126,6 +146,19 @@ typedef struct git_clone_options {
git_signature
*
signature
;
/**
* A callback used to create the new repository into which to
* clone. If NULL, the 'bare' field will be used to determine
* whether to create a bare repository.
*/
git_repository_create_cb
repository_cb
;
/**
* An opaque payload to pass to the git_repository creation callback.
* This parameter is ignored unless repository_cb is non-NULL.
*/
void
*
repository_cb_payload
;
/**
* A callback used to create the git_remote, prior to its being
* used to perform the clone operation. See the documentation for
* git_remote_create_cb for details. This parameter may be NULL,
...
...
@@ -158,9 +191,9 @@ GIT_EXTERN(int) git_clone_init_options(
/**
* Clone a remote repository.
*
*
This version handles the simple case. If you'd like to create the
*
repository or remote with non-default settings, you can create and
* c
onfigure them and then use `git_clone_into()`
.
*
By default this creates its repository and initial remote to match
*
git's defaults. You can use the options in the callback to
* c
ustomize how these are created
.
*
* @param out pointer that will receive the resulting repository object
* @param url the remote repository to clone
...
...
@@ -177,59 +210,6 @@ GIT_EXTERN(int) git_clone(
const
char
*
local_path
,
const
git_clone_options
*
options
);
/**
* Clone into a repository
*
* After creating the repository and remote and configuring them for
* paths and callbacks respectively, you can call this function to
* perform the clone operation and optionally checkout files.
*
* @param repo the repository to use
* @param remote the remote repository to clone from
* @param co_opts options to use during checkout
* @param branch the branch to checkout after the clone, pass NULL for the
* remote's default branch
* @param signature The identity used when updating the reflog.
* @return 0 on success, any non-zero return value from a callback
* function, or a negative value to indicate an error (use
* `giterr_last` for a detailed error message)
*/
GIT_EXTERN
(
int
)
git_clone_into
(
git_repository
*
repo
,
git_remote
*
remote
,
const
git_checkout_options
*
co_opts
,
const
char
*
branch
,
const
git_signature
*
signature
);
/**
* Perform a local clone into a repository
*
* A "local clone" bypasses any git-aware protocols and simply copies
* over the object database from the source repository. It is often
* faster than a git-aware clone, but no verification of the data is
* performed, and can copy over too much data.
*
* @param repo the repository to use
* @param remote the remote repository to clone from
* @param co_opts options to use during checkout
* @param branch the branch to checkout after the clone, pass NULL for the
* remote's default branch
* @param link wether to use hardlinks instead of copying
* objects. This is only possible if both repositories are on the same
* filesystem.
* @param signature the identity used when updating the reflog
* @return 0 on success, any non-zero return value from a callback
* function, or a negative value to indicate an error (use
* `giterr_last` for a detailed error message)
*/
GIT_EXTERN
(
int
)
git_clone_local_into
(
git_repository
*
repo
,
git_remote
*
remote
,
const
git_checkout_options
*
co_opts
,
const
char
*
branch
,
int
link
,
const
git_signature
*
signature
);
/** @} */
GIT_END_DECL
#endif
src/clone.c
View file @
b0ca1b18
...
...
@@ -24,6 +24,8 @@
#include "repository.h"
#include "odb.h"
static
int
clone_local_into
(
git_repository
*
repo
,
git_remote
*
remote
,
const
git_checkout_options
*
co_opts
,
const
char
*
branch
,
int
link
,
const
git_signature
*
signature
);
static
int
create_branch
(
git_reference
**
branch
,
git_repository
*
repo
,
...
...
@@ -229,6 +231,13 @@ cleanup:
return
retcode
;
}
static
int
default_repository_create
(
git_repository
**
out
,
const
char
*
path
,
int
bare
,
void
*
payload
)
{
GIT_UNUSED
(
payload
);
return
git_repository_init
(
out
,
path
,
bare
);
}
static
int
default_remote_create
(
git_remote
**
out
,
git_repository
*
repo
,
...
...
@@ -322,7 +331,7 @@ static int checkout_branch(git_repository *repo, git_remote *remote, const git_c
return
error
;
}
int
git_
clone_into
(
git_repository
*
repo
,
git_remote
*
_remote
,
const
git_checkout_options
*
co_opts
,
const
char
*
branch
,
const
git_signature
*
signature
)
static
int
clone_into
(
git_repository
*
repo
,
git_remote
*
_remote
,
const
git_checkout_options
*
co_opts
,
const
char
*
branch
,
const
git_signature
*
signature
)
{
int
error
;
git_buf
reflog_message
=
GIT_BUF_INIT
;
...
...
@@ -396,6 +405,7 @@ int git_clone(
git_remote
*
origin
;
git_clone_options
options
=
GIT_CLONE_OPTIONS_INIT
;
uint32_t
rmdir_flags
=
GIT_RMDIR_REMOVE_FILES
;
git_repository_create_cb
repository_cb
;
assert
(
out
&&
url
&&
local_path
);
...
...
@@ -415,17 +425,22 @@ int git_clone(
if
(
git_path_exists
(
local_path
))
rmdir_flags
|=
GIT_RMDIR_SKIP_ROOT
;
if
((
error
=
git_repository_init
(
&
repo
,
local_path
,
options
.
bare
))
<
0
)
if
(
options
.
repository_cb
)
repository_cb
=
options
.
repository_cb
;
else
repository_cb
=
default_repository_create
;
if
((
error
=
repository_cb
(
&
repo
,
local_path
,
options
.
bare
,
options
.
repository_cb_payload
))
<
0
)
return
error
;
if
(
!
(
error
=
create_and_configure_origin
(
&
origin
,
repo
,
url
,
&
options
)))
{
if
(
git_clone__should_clone_local
(
url
,
options
.
local
))
{
int
link
=
options
.
local
!=
GIT_CLONE_LOCAL_NO_LINKS
;
error
=
git_
clone_local_into
(
error
=
clone_local_into
(
repo
,
origin
,
&
options
.
checkout_opts
,
options
.
checkout_branch
,
link
,
options
.
signature
);
}
else
{
error
=
git_
clone_into
(
error
=
clone_into
(
repo
,
origin
,
&
options
.
checkout_opts
,
options
.
checkout_branch
,
options
.
signature
);
}
...
...
@@ -485,7 +500,7 @@ static bool can_link(const char *src, const char *dst, int link)
#endif
}
int
git_
clone_local_into
(
git_repository
*
repo
,
git_remote
*
remote
,
const
git_checkout_options
*
co_opts
,
const
char
*
branch
,
int
link
,
const
git_signature
*
signature
)
static
int
clone_local_into
(
git_repository
*
repo
,
git_remote
*
remote
,
const
git_checkout_options
*
co_opts
,
const
char
*
branch
,
int
link
,
const
git_signature
*
signature
)
{
int
error
,
flags
;
git_repository
*
src
;
...
...
tests/clone/local.c
View file @
b0ca1b18
...
...
@@ -31,31 +31,24 @@ void test_clone_local__should_clone_local(void)
void
test_clone_local__hardlinks
(
void
)
{
git_repository
*
repo
;
git_remote
*
remote
;
git_signature
*
sig
;
git_clone_options
opts
=
GIT_CLONE_OPTIONS_INIT
;
git_buf
buf
=
GIT_BUF_INIT
;
struct
stat
st
;
/*
* In this first clone, we just copy over, since the temp dir
* will often be in a different filesystem, so we cannot
* link. It also allows us to control the number of links
*/
cl_git_pass
(
git_repository_init
(
&
repo
,
"./clone.git"
,
true
));
cl_git_pass
(
git_remote_create
(
&
remote
,
repo
,
"origin"
,
cl_fixture
(
"testrepo.git"
)));
cl_git_pass
(
git_signature_now
(
&
sig
,
"foo"
,
"bar"
));
cl_git_pass
(
git_clone_local_into
(
repo
,
remote
,
NULL
,
NULL
,
false
,
sig
));
git_remote_free
(
remote
);
opts
.
bare
=
true
;
opts
.
local
=
GIT_CLONE_LOCAL_NO_LINKS
;
cl_git_pass
(
git_clone
(
&
repo
,
cl_fixture
(
"testrepo.git"
),
"./clone.git"
,
&
opts
));
git_repository_free
(
repo
);
/* This second clone is in the same filesystem, so we can hardlink */
cl_git_pass
(
git_repository_init
(
&
repo
,
"./clone2.git"
,
true
));
cl_git_pass
(
git_buf_puts
(
&
buf
,
cl_git_path_url
(
"clone.git"
)));
cl_git_pass
(
git_remote_create
(
&
remote
,
repo
,
"origin"
,
buf
.
ptr
));
cl_git_pass
(
git_clone_local_into
(
repo
,
remote
,
NULL
,
NULL
,
true
,
sig
));
opts
.
local
=
GIT_CLONE_LOCAL
;
cl_git_pass
(
git_clone
(
&
repo
,
cl_git_path_url
(
"clone.git"
),
"./clone2.git"
,
&
opts
));
#ifndef GIT_WIN32
git_buf_clear
(
&
buf
);
...
...
@@ -65,14 +58,11 @@ void test_clone_local__hardlinks(void)
cl_assert_equal_i
(
2
,
st
.
st_nlink
);
#endif
git_remote_free
(
remote
);
git_repository_free
(
repo
);
git_buf_clear
(
&
buf
);
cl_git_pass
(
git_repository_init
(
&
repo
,
"./clone3.git"
,
true
));
cl_git_pass
(
git_buf_puts
(
&
buf
,
cl_git_path_url
(
"clone.git"
)));
cl_git_pass
(
git_remote_create
(
&
remote
,
repo
,
"origin"
,
buf
.
ptr
));
cl_git_pass
(
git_clone_local_into
(
repo
,
remote
,
NULL
,
NULL
,
false
,
sig
));
opts
.
local
=
GIT_CLONE_LOCAL_NO_LINKS
;
cl_git_pass
(
git_clone
(
&
repo
,
cl_git_path_url
(
"clone.git"
),
"./clone3.git"
,
&
opts
));
git_buf_clear
(
&
buf
);
cl_git_pass
(
git_buf_join_n
(
&
buf
,
'/'
,
4
,
git_repository_path
(
repo
),
"objects"
,
"08"
,
"b041783f40edfe12bb406c9c9a8a040177c125"
));
...
...
@@ -80,7 +70,6 @@ void test_clone_local__hardlinks(void)
cl_git_pass
(
p_stat
(
buf
.
ptr
,
&
st
));
cl_assert_equal_i
(
1
,
st
.
st_nlink
);
git_remote_free
(
remote
);
git_repository_free
(
repo
);
/* this one should automatically use links */
...
...
@@ -95,7 +84,6 @@ void test_clone_local__hardlinks(void)
#endif
git_buf_free
(
&
buf
);
git_signature_free
(
sig
);
git_repository_free
(
repo
);
cl_git_pass
(
git_futils_rmdir_r
(
"./clone.git"
,
NULL
,
GIT_RMDIR_REMOVE_FILES
));
...
...
tests/clone/nonetwork.c
View file @
b0ca1b18
...
...
@@ -279,23 +279,6 @@ void test_clone_nonetwork__clone_updates_reflog_properly(void)
assert_correct_reflog
(
"refs/heads/master"
);
}
void
test_clone_nonetwork__clone_into_updates_reflog_properly
(
void
)
{
git_remote
*
remote
;
git_signature
*
sig
;
cl_git_pass
(
git_signature_now
(
&
sig
,
"Me"
,
"foo@example.com"
));
cl_git_pass
(
git_repository_init
(
&
g_repo
,
"./foo"
,
false
));
cl_git_pass
(
git_remote_create
(
&
remote
,
g_repo
,
"origin"
,
cl_git_fixture_url
(
"testrepo.git"
)));
cl_git_pass
(
git_clone_into
(
g_repo
,
remote
,
NULL
,
NULL
,
sig
));
assert_correct_reflog
(
"HEAD"
);
assert_correct_reflog
(
"refs/heads/master"
);
git_remote_free
(
remote
);
git_signature_free
(
sig
);
}
static
void
cleanup_repository
(
void
*
path
)
{
if
(
g_repo
)
{
...
...
tests/network/fetchlocal.c
View file @
b0ca1b18
...
...
@@ -87,28 +87,43 @@ void test_network_fetchlocal__partial(void)
git_remote_free
(
origin
);
}
void
test_network_fetchlocal__clone_into_mirror
(
void
)
static
int
remote_mirror_cb
(
git_remote
**
out
,
git_repository
*
repo
,
const
char
*
name
,
const
char
*
url
,
void
*
payload
)
{
git_buf
path
=
GIT_BUF_INIT
;
git_repository
*
repo
;
int
error
;
git_remote
*
remote
;
git_reference
*
head
;
cl_git_pass
(
git_repository_init
(
&
repo
,
"./foo.git"
,
true
));
cl_git_pass
(
git_remote_create
(
&
remote
,
repo
,
"origin"
,
cl_git_fixture_url
(
"testrepo.git"
)));
GIT_UNUSED
(
payload
);
if
((
error
=
git_remote_create
(
&
remote
,
repo
,
name
,
url
))
<
0
)
return
error
;
git_remote_clear_refspecs
(
remote
);
cl_git_pass
(
git_remote_add_fetch
(
remote
,
"+refs/*:refs/*"
));
cl_git_pass
(
git_clone_into
(
repo
,
remote
,
NULL
,
NULL
,
NULL
));
if
((
error
=
git_remote_add_fetch
(
remote
,
"+refs/*:refs/*"
))
<
0
)
{
git_remote_free
(
remote
);
return
error
;
}
*
out
=
remote
;
return
0
;
}
void
test_network_fetchlocal__clone_into_mirror
(
void
)
{
git_clone_options
opts
=
GIT_CLONE_OPTIONS_INIT
;
git_repository
*
repo
;
git_reference
*
head
;
opts
.
bare
=
true
;
opts
.
remote_cb
=
remote_mirror_cb
;
cl_git_pass
(
git_clone
(
&
repo
,
cl_git_fixture_url
(
"testrepo.git"
),
"./foo.git"
,
&
opts
));
cl_git_pass
(
git_reference_lookup
(
&
head
,
repo
,
"HEAD"
));
cl_assert_equal_i
(
GIT_REF_SYMBOLIC
,
git_reference_type
(
head
));
cl_assert_equal_s
(
"refs/heads/master"
,
git_reference_symbolic_target
(
head
));
git_remote_free
(
remote
);
git_reference_free
(
head
);
git_repository_free
(
repo
);
git_buf_free
(
&
path
);
cl_fixture_cleanup
(
"./foo.git"
);
}
tests/online/clone.c
View file @
b0ca1b18
...
...
@@ -124,65 +124,49 @@ void test_online_clone__can_checkout_a_cloned_repo(void)
git_buf_free
(
&
path
);
}
void
test_online_clone__clone_into
(
void
)
static
int
remote_mirror_cb
(
git_remote
**
out
,
git_repository
*
repo
,
const
char
*
name
,
const
char
*
url
,
void
*
payload
)
{
git_buf
path
=
GIT_BUF_INIT
;
int
error
;
git_remote
*
remote
;
git_reference
*
head
;
git_checkout_options
checkout_opts
=
GIT_CHECKOUT_OPTIONS_INIT
;
git_remote_callbacks
callbacks
=
GIT_REMOTE_CALLBACKS_INIT
;
bool
checkout_progress_cb_was_called
=
false
,
fetch_progress_cb_was_called
=
false
;
checkout_opts
.
checkout_strategy
=
GIT_CHECKOUT_SAFE_CREATE
;
checkout_opts
.
progress_cb
=
&
checkout_progress
;
checkout_opts
.
progress_payload
=
&
checkout_progress_cb_was_called
;
git_remote_callbacks
*
callbacks
=
(
git_remote_callbacks
*
)
payload
;
cl_git_pass
(
git_repository_init
(
&
g_repo
,
"./foo"
,
false
));
cl_git_pass
(
git_remote_create
(
&
remote
,
g_repo
,
"origin"
,
LIVE_REPO_URL
));
callbacks
.
transfer_progress
=
&
fetch_progress
;
callbacks
.
payload
=
&
fetch_progress_cb_was_called
;
git_remote_set_callbacks
(
remote
,
&
callbacks
);
if
((
error
=
git_remote_create
(
&
remote
,
repo
,
name
,
url
))
<
0
)
return
error
;
cl_git_pass
(
git_clone_into
(
g_repo
,
remote
,
&
checkout_opts
,
NULL
,
NULL
));
cl_git_pass
(
git_buf_joinpath
(
&
path
,
git_repository_workdir
(
g_repo
),
"master.txt"
))
;
cl_assert_equal_i
(
true
,
git_path_isfile
(
git_buf_cstr
(
&
path
)));
if
((
error
=
git_remote_set_callbacks
(
remote
,
callbacks
))
<
0
)
{
git_remote_free
(
remote
);
return
error
;
}
cl_git_pass
(
git_reference_lookup
(
&
head
,
g_repo
,
"HEAD"
));
cl_assert_equal_i
(
GIT_REF_SYMBOLIC
,
git_reference_type
(
head
));
cl_assert_equal_s
(
"refs/heads/master"
,
git_reference_symbolic_target
(
head
));
git_remote_clear_refspecs
(
remote
);
cl_assert_equal_i
(
true
,
checkout_progress_cb_was_called
);
cl_assert_equal_i
(
true
,
fetch_progress_cb_was_called
);
if
((
error
=
git_remote_add_fetch
(
remote
,
"+refs/*:refs/*"
))
<
0
)
{
git_remote_free
(
remote
);
return
error
;
}
git_remote_free
(
remote
);
git_reference_free
(
head
);
git_buf_free
(
&
path
);
*
out
=
remote
;
return
0
;
}
void
test_online_clone__clone_mirror
(
void
)
{
git_buf
path
=
GIT_BUF_INIT
;
git_remote
*
remote
;
git_clone_options
opts
=
GIT_CLONE_OPTIONS_INIT
;
git_reference
*
head
;
git_remote_callbacks
callbacks
=
GIT_REMOTE_CALLBACKS_INIT
;
bool
fetch_progress_cb_was_called
=
false
;
cl_git_pass
(
git_repository_init
(
&
g_repo
,
"./foo.git"
,
true
));
cl_git_pass
(
git_remote_create
(
&
remote
,
g_repo
,
"origin"
,
LIVE_REPO_URL
));
callbacks
.
transfer_progress
=
&
fetch_progress
;
callbacks
.
payload
=
&
fetch_progress_cb_was_called
;
git_remote_set_callbacks
(
remote
,
&
callbacks
);
git_remote_clear_refspecs
(
remote
);
cl_git_pass
(
git_remote_add_fetch
(
remote
,
"+refs/*:refs/*"
));
opts
.
bare
=
true
;
opts
.
remote_cb
=
remote_mirror_cb
;
opts
.
remote_cb_payload
=
&
callbacks
;
cl_git_pass
(
git_clone
_into
(
g_repo
,
remote
,
NULL
,
NULL
,
NULL
));
cl_git_pass
(
git_clone
(
&
g_repo
,
LIVE_REPO_URL
,
"./foo.git"
,
&
opts
));
cl_git_pass
(
git_reference_lookup
(
&
head
,
g_repo
,
"HEAD"
));
cl_assert_equal_i
(
GIT_REF_SYMBOLIC
,
git_reference_type
(
head
));
...
...
@@ -190,9 +174,7 @@ void test_online_clone__clone_mirror(void)
cl_assert_equal_i
(
true
,
fetch_progress_cb_was_called
);
git_remote_free
(
remote
);
git_reference_free
(
head
);
git_buf_free
(
&
path
);
git_repository_free
(
g_repo
);
g_repo
=
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