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
4d7b9939
Commit
4d7b9939
authored
Apr 01, 2014
by
Jacques Germishuys
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added cherry-pick support
parent
399f2b62
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
320 additions
and
0 deletions
+320
-0
include/git2.h
+1
-0
include/git2/cherrypick.h
+88
-0
include/git2/errors.h
+1
-0
src/cherrypick.c
+230
-0
No files found.
include/git2.h
View file @
4d7b9939
...
...
@@ -14,6 +14,7 @@
#include "git2/branch.h"
#include "git2/buffer.h"
#include "git2/checkout.h"
#include "git2/cherrypick.h"
#include "git2/clone.h"
#include "git2/commit.h"
#include "git2/common.h"
...
...
include/git2/cherrypick.h
0 → 100644
View file @
4d7b9939
/*
* 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.
*/
#ifndef INCLUDE_git_cherrypick_h__
#define INCLUDE_git_cherrypick_h__
#include "common.h"
#include "types.h"
#include "merge.h"
/**
* @file git2/cherrypick.h
* @brief Git cherry-pick routines
* @defgroup git_cherrypick Git cherry-pick routines
* @ingroup Git
* @{
*/
GIT_BEGIN_DECL
typedef
struct
{
unsigned
int
version
;
/** For merge commits, the "mainline" is treated as the parent. */
unsigned
int
mainline
;
git_merge_options
merge_opts
;
git_checkout_options
checkout_opts
;
}
git_cherry_pick_options
;
#define GIT_CHERRY_PICK_OPTIONS_VERSION 1
#define GIT_CHERRY_PICK_OPTIONS_INIT {GIT_CHERRY_PICK_OPTIONS_VERSION, 0, GIT_MERGE_OPTIONS_INIT, GIT_CHECKOUT_OPTIONS_INIT}
/**
* Initializes a `git_cherry_pick_options` with default values. Equivalent to
* creating an instance with GIT_CHERRY_PICK_OPTIONS_INIT.
*
* @param opts the `git_cherry_pick_options` instance to initialize.
* @param version the version of the struct; you should pass
* `GIT_CHERRY_PICK_OPTIONS_VERSION` here.
* @return Zero on success; -1 on failure.
*/
GIT_EXTERN
(
int
)
git_cherry_pick_init_opts
(
git_cherry_pick_options
*
opts
,
int
version
);
/**
* Cherry-picks the given commit against the given "our" commit, producing an
* index that reflects the result of the cherry-pick.
*
* The returned index must be freed explicitly with `git_index_free`.
*
* @param out pointer to store the index result in
* @param repo the repository that contains the given commits
* @param cherry_pick_commit the commit to cherry-pick
* @param our_commit the commit to revert against (eg, HEAD)
* @param mainline the parent of the revert commit, if it is a merge
* @param merge_tree_opts the merge tree options (or null for defaults)
* @return zero on success, -1 on failure.
*/
GIT_EXTERN
(
int
)
git_cherry_pick_commit
(
git_index
**
out
,
git_repository
*
repo
,
git_commit
*
cherry_pick_commit
,
git_commit
*
our_commit
,
unsigned
int
mainline
,
const
git_merge_options
*
merge_options
);
/**
* Cherry-pick the given commit, producing changes in the index and working directory.
*
* @param repo the repository to cherry-pick
* @param commit the commit to cherry-pick
* @param cherry_pick_options the cherry-pick options (or null for defaults)
* @return zero on success, -1 on failure.
*/
GIT_EXTERN
(
int
)
git_cherry_pick
(
git_repository
*
repo
,
git_commit
*
commit
,
const
git_cherry_pick_options
*
cherry_pick_options
);
/** @} */
GIT_END_DECL
#endif
include/git2/errors.h
View file @
4d7b9939
...
...
@@ -86,6 +86,7 @@ typedef enum {
GITERR_FILTER
,
GITERR_REVERT
,
GITERR_CALLBACK
,
GITERR_CHERRYPICK
,
}
git_error_t
;
/**
...
...
src/cherrypick.c
0 → 100644
View file @
4d7b9939
/*
* 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 "common.h"
#include "repository.h"
#include "filebuf.h"
#include "merge.h"
#include "vector.h"
#include "git2/types.h"
#include "git2/merge.h"
#include "git2/cherrypick.h"
#include "git2/commit.h"
#include "git2/sys/commit.h"
#define GIT_CHERRY_PICK_FILE_MODE 0666
static
int
write_cherry_pick_head
(
git_repository
*
repo
,
const
char
*
commit_oidstr
)
{
git_filebuf
file
=
GIT_FILEBUF_INIT
;
git_buf
file_path
=
GIT_BUF_INIT
;
int
error
=
0
;
if
((
error
=
git_buf_joinpath
(
&
file_path
,
repo
->
path_repository
,
GIT_CHERRY_PICK_HEAD_FILE
))
>=
0
&&
(
error
=
git_filebuf_open
(
&
file
,
file_path
.
ptr
,
GIT_FILEBUF_FORCE
,
GIT_CHERRY_PICK_FILE_MODE
))
>=
0
&&
(
error
=
git_filebuf_printf
(
&
file
,
"%s
\n
"
,
commit_oidstr
))
>=
0
)
error
=
git_filebuf_commit
(
&
file
);
if
(
error
<
0
)
git_filebuf_cleanup
(
&
file
);
git_buf_free
(
&
file_path
);
return
error
;
}
static
int
write_merge_msg
(
git_repository
*
repo
,
const
char
*
commit_msg
)
{
git_filebuf
file
=
GIT_FILEBUF_INIT
;
git_buf
file_path
=
GIT_BUF_INIT
;
int
error
=
0
;
if
((
error
=
git_buf_joinpath
(
&
file_path
,
repo
->
path_repository
,
GIT_MERGE_MSG_FILE
))
<
0
||
(
error
=
git_filebuf_open
(
&
file
,
file_path
.
ptr
,
GIT_FILEBUF_FORCE
,
GIT_CHERRY_PICK_FILE_MODE
))
<
0
||
(
error
=
git_filebuf_printf
(
&
file
,
"%s"
,
commit_msg
))
<
0
)
goto
cleanup
;
error
=
git_filebuf_commit
(
&
file
);
cleanup:
if
(
error
<
0
)
git_filebuf_cleanup
(
&
file
);
git_buf_free
(
&
file_path
);
return
error
;
}
static
int
cherry_pick_normalize_opts
(
git_repository
*
repo
,
git_cherry_pick_options
*
opts
,
const
git_cherry_pick_options
*
given
,
const
char
*
their_label
)
{
int
error
=
0
;
unsigned
int
default_checkout_strategy
=
GIT_CHECKOUT_SAFE_CREATE
|
GIT_CHECKOUT_ALLOW_CONFLICTS
;
GIT_UNUSED
(
repo
);
if
(
given
!=
NULL
)
memcpy
(
opts
,
given
,
sizeof
(
git_cherry_pick_options
));
else
{
git_cherry_pick_options
default_opts
=
GIT_CHERRY_PICK_OPTIONS_INIT
;
memcpy
(
opts
,
&
default_opts
,
sizeof
(
git_cherry_pick_options
));
}
if
(
!
opts
->
checkout_opts
.
checkout_strategy
)
opts
->
checkout_opts
.
checkout_strategy
=
default_checkout_strategy
;
if
(
!
opts
->
checkout_opts
.
our_label
)
opts
->
checkout_opts
.
our_label
=
"HEAD"
;
if
(
!
opts
->
checkout_opts
.
their_label
)
opts
->
checkout_opts
.
their_label
=
their_label
;
return
error
;
}
static
int
cherry_pick_state_cleanup
(
git_repository
*
repo
)
{
const
char
*
state_files
[]
=
{
GIT_CHERRY_PICK_HEAD_FILE
,
GIT_MERGE_MSG_FILE
};
return
git_repository__cleanup_files
(
repo
,
state_files
,
ARRAY_SIZE
(
state_files
));
}
static
int
cherry_pick_seterr
(
git_commit
*
commit
,
const
char
*
fmt
)
{
char
commit_oidstr
[
GIT_OID_HEXSZ
+
1
];
giterr_set
(
GITERR_CHERRYPICK
,
fmt
,
git_oid_tostr
(
commit_oidstr
,
GIT_OID_HEXSZ
+
1
,
git_commit_id
(
commit
)));
return
-
1
;
}
int
git_cherry_pick_commit
(
git_index
**
out
,
git_repository
*
repo
,
git_commit
*
cherry_pick_commit
,
git_commit
*
our_commit
,
unsigned
int
mainline
,
const
git_merge_options
*
merge_opts
)
{
git_commit
*
parent_commit
=
NULL
;
git_tree
*
parent_tree
=
NULL
,
*
our_tree
=
NULL
,
*
cherry_pick_tree
=
NULL
;
int
parent
=
0
,
error
=
0
;
assert
(
out
&&
repo
&&
cherry_pick_commit
&&
our_commit
);
if
(
git_commit_parentcount
(
cherry_pick_commit
)
>
1
)
{
if
(
!
mainline
)
return
cherry_pick_seterr
(
cherry_pick_commit
,
"Mainline branch is not specified but %s is a merge commit"
);
parent
=
mainline
;
}
else
{
if
(
mainline
)
return
cherry_pick_seterr
(
cherry_pick_commit
,
"Mainline branch specified but %s is not a merge commit"
);
parent
=
git_commit_parentcount
(
cherry_pick_commit
);
}
if
(
parent
&&
((
error
=
git_commit_parent
(
&
parent_commit
,
cherry_pick_commit
,
(
parent
-
1
)))
<
0
||
(
error
=
git_commit_tree
(
&
parent_tree
,
parent_commit
))
<
0
))
goto
done
;
if
((
error
=
git_commit_tree
(
&
cherry_pick_tree
,
cherry_pick_commit
))
<
0
||
(
error
=
git_commit_tree
(
&
our_tree
,
our_commit
))
<
0
)
goto
done
;
error
=
git_merge_trees
(
out
,
repo
,
parent_tree
,
our_tree
,
cherry_pick_tree
,
merge_opts
);
done:
git_tree_free
(
parent_tree
);
git_tree_free
(
our_tree
);
git_tree_free
(
cherry_pick_tree
);
git_commit_free
(
parent_commit
);
return
error
;
}
int
git_cherry_pick
(
git_repository
*
repo
,
git_commit
*
commit
,
const
git_cherry_pick_options
*
given_opts
)
{
git_cherry_pick_options
opts
;
git_reference
*
our_ref
=
NULL
;
git_commit
*
our_commit
=
NULL
;
char
commit_oidstr
[
GIT_OID_HEXSZ
+
1
];
const
char
*
commit_msg
,
*
commit_summary
;
git_buf
their_label
=
GIT_BUF_INIT
;
git_index
*
index_new
=
NULL
,
*
index_repo
=
NULL
;
int
error
=
0
;
assert
(
repo
&&
commit
);
GITERR_CHECK_VERSION
(
given_opts
,
GIT_CHERRY_PICK_OPTIONS_VERSION
,
"git_cherry_pick_options"
);
if
((
error
=
git_repository__ensure_not_bare
(
repo
,
"cherry-pick"
))
<
0
)
return
error
;
if
((
commit_msg
=
git_commit_message
(
commit
))
==
NULL
||
(
commit_summary
=
git_commit_summary
(
commit
))
==
NULL
)
{
error
=
-
1
;
goto
on_error
;
}
git_oid_fmt
(
commit_oidstr
,
git_commit_id
(
commit
));
if
((
error
=
write_merge_msg
(
repo
,
commit_msg
))
<
0
||
(
error
=
git_buf_printf
(
&
their_label
,
"%.7s... %s"
,
commit_oidstr
,
commit_summary
))
<
0
||
(
error
=
cherry_pick_normalize_opts
(
repo
,
&
opts
,
given_opts
,
git_buf_cstr
(
&
their_label
)))
<
0
||
(
error
=
write_cherry_pick_head
(
repo
,
commit_oidstr
))
<
0
||
(
error
=
git_repository_head
(
&
our_ref
,
repo
))
<
0
||
(
error
=
git_reference_peel
((
git_object
**
)
&
our_commit
,
our_ref
,
GIT_OBJ_COMMIT
))
<
0
||
(
error
=
git_cherry_pick_commit
(
&
index_new
,
repo
,
commit
,
our_commit
,
opts
.
mainline
,
&
opts
.
merge_opts
))
<
0
||
(
error
=
git_merge__indexes
(
repo
,
index_new
))
<
0
||
(
error
=
git_repository_index
(
&
index_repo
,
repo
))
<
0
||
(
error
=
git_merge__append_conflicts_to_merge_msg
(
repo
,
index_repo
))
<
0
||
(
error
=
git_checkout_index
(
repo
,
index_repo
,
&
opts
.
checkout_opts
))
<
0
)
goto
on_error
;
goto
done
;
on_error:
cherry_pick_state_cleanup
(
repo
);
done:
git_index_free
(
index_new
);
git_index_free
(
index_repo
);
git_commit_free
(
our_commit
);
git_reference_free
(
our_ref
);
git_buf_free
(
&
their_label
);
return
error
;
}
int
git_cherry_pick_init_opts
(
git_cherry_pick_options
*
opts
,
int
version
)
{
if
(
version
!=
GIT_CHERRY_PICK_OPTIONS_VERSION
)
{
giterr_set
(
GITERR_INVALID
,
"Invalid version %d for git_cherry_pick_options"
,
version
);
return
-
1
;
}
else
{
git_cherry_pick_options
o
=
GIT_CHERRY_PICK_OPTIONS_INIT
;
memcpy
(
opts
,
&
o
,
sizeof
(
o
));
return
0
;
}
}
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