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
0ddc6094
Unverified
Commit
0ddc6094
authored
Nov 30, 2018
by
Patrick Steinhardt
Committed by
GitHub
Nov 30, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #4770 from tiennou/feature/merge-analysis-any-branch
Allow merge analysis against any reference
parents
e7873eb2
cb71a9ce
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
131 additions
and
30 deletions
+131
-30
include/git2/merge.h
+19
-0
src/merge.c
+35
-10
src/refs.c
+24
-0
src/refs.h
+2
-0
src/repository.c
+2
-0
tests/merge/workdir/analysis.c
+49
-20
No files found.
include/git2/merge.h
View file @
0ddc6094
...
...
@@ -389,6 +389,25 @@ GIT_EXTERN(int) git_merge_analysis(
size_t
their_heads_len
);
/**
* Analyzes the given branch(es) and determines the opportunities for
* merging them into a reference.
*
* @param analysis_out analysis enumeration that the result is written into
* @param repo the repository to merge
* @param our_ref the reference to perform the analysis from
* @param their_heads the heads to merge into
* @param their_heads_len the number of heads to merge
* @return 0 on success or error code
*/
GIT_EXTERN
(
int
)
git_merge_analysis_for_ref
(
git_merge_analysis_t
*
analysis_out
,
git_merge_preference_t
*
preference_out
,
git_repository
*
repo
,
git_reference
*
our_ref
,
const
git_annotated_commit
**
their_heads
,
size_t
their_heads_len
);
/**
* Find a merge base between two commits
*
* @param out the OID of a merge base between 'one' and 'two'
...
...
src/merge.c
View file @
0ddc6094
...
...
@@ -3110,11 +3110,11 @@ static int merge_heads(
git_annotated_commit
**
ancestor_head_out
,
git_annotated_commit
**
our_head_out
,
git_repository
*
repo
,
git_reference
*
our_ref
,
const
git_annotated_commit
**
their_heads
,
size_t
their_heads_len
)
{
git_annotated_commit
*
ancestor_head
=
NULL
,
*
our_head
=
NULL
;
git_reference
*
our_ref
=
NULL
;
int
error
=
0
;
*
ancestor_head_out
=
NULL
;
...
...
@@ -3123,8 +3123,7 @@ static int merge_heads(
if
((
error
=
git_repository__ensure_not_bare
(
repo
,
"merge"
))
<
0
)
goto
done
;
if
((
error
=
git_reference_lookup
(
&
our_ref
,
repo
,
GIT_HEAD_FILE
))
<
0
||
(
error
=
git_annotated_commit_from_ref
(
&
our_head
,
repo
,
our_ref
))
<
0
)
if
((
error
=
git_annotated_commit_from_ref
(
&
our_head
,
repo
,
our_ref
))
<
0
)
goto
done
;
if
((
error
=
merge_ancestor_head
(
&
ancestor_head
,
repo
,
our_head
,
their_heads
,
their_heads_len
))
<
0
)
{
...
...
@@ -3144,8 +3143,6 @@ done:
git_annotated_commit_free
(
our_head
);
}
git_reference_free
(
our_ref
);
return
error
;
}
...
...
@@ -3182,17 +3179,19 @@ done:
return
error
;
}
int
git_merge_analysis
(
int
git_merge_analysis
_for_ref
(
git_merge_analysis_t
*
analysis_out
,
git_merge_preference_t
*
preference_out
,
git_repository
*
repo
,
git_reference
*
our_ref
,
const
git_annotated_commit
**
their_heads
,
size_t
their_heads_len
)
{
git_annotated_commit
*
ancestor_head
=
NULL
,
*
our_head
=
NULL
;
int
error
=
0
;
bool
unborn
;
assert
(
analysis_out
&&
preference_out
&&
repo
&&
their_heads
);
assert
(
analysis_out
&&
preference_out
&&
repo
&&
their_heads
&&
their_heads_len
>
0
);
if
(
their_heads_len
!=
1
)
{
giterr_set
(
GITERR_MERGE
,
"can only merge a single branch"
);
...
...
@@ -3205,12 +3204,16 @@ int git_merge_analysis(
if
((
error
=
merge_preference
(
preference_out
,
repo
))
<
0
)
goto
done
;
if
(
git_repository_head_unborn
(
repo
))
{
if
((
error
=
git_reference__is_unborn_head
(
&
unborn
,
our_ref
,
repo
))
<
0
)
goto
done
;
if
(
unborn
)
{
*
analysis_out
|=
GIT_MERGE_ANALYSIS_FASTFORWARD
|
GIT_MERGE_ANALYSIS_UNBORN
;
error
=
0
;
goto
done
;
}
if
((
error
=
merge_heads
(
&
ancestor_head
,
&
our_head
,
repo
,
their_heads
,
their_heads_len
))
<
0
)
if
((
error
=
merge_heads
(
&
ancestor_head
,
&
our_head
,
repo
,
our_ref
,
their_heads
,
their_heads_len
))
<
0
)
goto
done
;
/* We're up-to-date if we're trying to merge our own common ancestor. */
...
...
@@ -3233,6 +3236,28 @@ done:
return
error
;
}
int
git_merge_analysis
(
git_merge_analysis_t
*
analysis_out
,
git_merge_preference_t
*
preference_out
,
git_repository
*
repo
,
const
git_annotated_commit
**
their_heads
,
size_t
their_heads_len
)
{
git_reference
*
head_ref
=
NULL
;
int
error
=
0
;
if
((
error
=
git_reference_lookup
(
&
head_ref
,
repo
,
GIT_HEAD_FILE
))
<
0
)
{
giterr_set
(
GITERR_MERGE
,
"failed to lookup HEAD reference"
);
return
error
;
}
error
=
git_merge_analysis_for_ref
(
analysis_out
,
preference_out
,
repo
,
head_ref
,
their_heads
,
their_heads_len
);
git_reference_free
(
head_ref
);
return
error
;
}
int
git_merge
(
git_repository
*
repo
,
const
git_annotated_commit
**
their_heads
,
...
...
@@ -3248,7 +3273,7 @@ int git_merge(
unsigned
int
checkout_strategy
;
int
error
=
0
;
assert
(
repo
&&
their_heads
);
assert
(
repo
&&
their_heads
&&
their_heads_len
>
0
);
if
(
their_heads_len
!=
1
)
{
giterr_set
(
GITERR_MERGE
,
"can only merge a single branch"
);
...
...
src/refs.c
View file @
0ddc6094
...
...
@@ -1430,3 +1430,27 @@ const char *git_reference_shorthand(const git_reference *ref)
{
return
git_reference__shorthand
(
ref
->
name
);
}
int
git_reference__is_unborn_head
(
bool
*
unborn
,
const
git_reference
*
ref
,
git_repository
*
repo
)
{
int
error
;
git_reference
*
tmp_ref
;
assert
(
unborn
&&
ref
&&
repo
);
if
(
ref
->
type
==
GIT_REF_OID
)
{
*
unborn
=
0
;
return
0
;
}
error
=
git_reference_lookup_resolved
(
&
tmp_ref
,
repo
,
ref
->
name
,
-
1
);
git_reference_free
(
tmp_ref
);
if
(
error
!=
0
&&
error
!=
GIT_ENOTFOUND
)
return
error
;
else
if
(
error
==
GIT_ENOTFOUND
&&
git__strcmp
(
ref
->
name
,
GIT_HEAD_FILE
)
==
0
)
*
unborn
=
true
;
else
*
unborn
=
false
;
return
0
;
}
src/refs.h
View file @
0ddc6094
...
...
@@ -136,4 +136,6 @@ int git_reference__update_for_commit(
const
git_oid
*
id
,
const
char
*
operation
);
int
git_reference__is_unborn_head
(
bool
*
unborn
,
const
git_reference
*
ref
,
git_repository
*
repo
);
#endif
src/repository.c
View file @
0ddc6094
...
...
@@ -2157,6 +2157,8 @@ int git_repository_head(git_reference **head_out, git_repository *repo)
git_reference
*
head
;
int
error
;
assert
(
head_out
);
if
((
error
=
git_reference_lookup
(
&
head
,
repo
,
GIT_HEAD_FILE
))
<
0
)
return
error
;
...
...
tests/merge/workdir/analysis.c
View file @
0ddc6094
...
...
@@ -40,21 +40,33 @@ void test_merge_workdir_analysis__cleanup(void)
static
void
analysis_from_branch
(
git_merge_analysis_t
*
merge_analysis
,
git_merge_preference_t
*
merge_pref
,
const
char
*
branchname
)
const
char
*
our_branchname
,
const
char
*
their_branchname
)
{
git_buf
refname
=
GIT_BUF_INIT
;
git_buf
our_refname
=
GIT_BUF_INIT
;
git_buf
their_refname
=
GIT_BUF_INIT
;
git_reference
*
our_ref
;
git_reference
*
their_ref
;
git_annotated_commit
*
their_head
;
git_buf_printf
(
&
refname
,
"%s%s"
,
GIT_REFS_HEADS_DIR
,
branchname
);
if
(
our_branchname
!=
NULL
)
{
cl_git_pass
(
git_buf_printf
(
&
our_refname
,
"%s%s"
,
GIT_REFS_HEADS_DIR
,
our_branchname
));
cl_git_pass
(
git_reference_lookup
(
&
our_ref
,
repo
,
git_buf_cstr
(
&
our_refname
)));
}
else
{
cl_git_pass
(
git_reference_lookup
(
&
our_ref
,
repo
,
GIT_HEAD_FILE
));
}
cl_git_pass
(
git_reference_lookup
(
&
their_ref
,
repo
,
git_buf_cstr
(
&
refname
)));
cl_git_pass
(
git_buf_printf
(
&
their_refname
,
"%s%s"
,
GIT_REFS_HEADS_DIR
,
their_branchname
));
cl_git_pass
(
git_reference_lookup
(
&
their_ref
,
repo
,
git_buf_cstr
(
&
their_refname
)));
cl_git_pass
(
git_annotated_commit_from_ref
(
&
their_head
,
repo
,
their_ref
));
cl_git_pass
(
git_merge_analysis
(
merge_analysis
,
merge_pref
,
repo
,
(
const
git_annotated_commit
**
)
&
their_head
,
1
));
cl_git_pass
(
git_merge_analysis
_for_ref
(
merge_analysis
,
merge_pref
,
repo
,
our_ref
,
(
const
git_annotated_commit
**
)
&
their_head
,
1
));
git_buf_dispose
(
&
refname
);
git_buf_dispose
(
&
our_refname
);
git_buf_dispose
(
&
their_refname
);
git_annotated_commit_free
(
their_head
);
git_reference_free
(
our_ref
);
git_reference_free
(
their_ref
);
}
...
...
@@ -63,9 +75,8 @@ void test_merge_workdir_analysis__fastforward(void)
git_merge_analysis_t
merge_analysis
;
git_merge_preference_t
merge_pref
;
analysis_from_branch
(
&
merge_analysis
,
&
merge_pref
,
FASTFORWARD_BRANCH
);
cl_assert_equal_i
(
GIT_MERGE_ANALYSIS_FASTFORWARD
,
(
merge_analysis
&
GIT_MERGE_ANALYSIS_FASTFORWARD
));
cl_assert_equal_i
(
GIT_MERGE_ANALYSIS_NORMAL
,
(
merge_analysis
&
GIT_MERGE_ANALYSIS_NORMAL
));
analysis_from_branch
(
&
merge_analysis
,
&
merge_pref
,
NULL
,
FASTFORWARD_BRANCH
);
cl_assert_equal_i
(
GIT_MERGE_ANALYSIS_NORMAL
|
GIT_MERGE_ANALYSIS_FASTFORWARD
,
merge_analysis
);
}
void
test_merge_workdir_analysis__no_fastforward
(
void
)
...
...
@@ -73,7 +84,7 @@ void test_merge_workdir_analysis__no_fastforward(void)
git_merge_analysis_t
merge_analysis
;
git_merge_preference_t
merge_pref
;
analysis_from_branch
(
&
merge_analysis
,
&
merge_pref
,
NOFASTFORWARD_BRANCH
);
analysis_from_branch
(
&
merge_analysis
,
&
merge_pref
,
N
ULL
,
N
OFASTFORWARD_BRANCH
);
cl_assert_equal_i
(
GIT_MERGE_ANALYSIS_NORMAL
,
merge_analysis
);
}
...
...
@@ -82,7 +93,7 @@ void test_merge_workdir_analysis__uptodate(void)
git_merge_analysis_t
merge_analysis
;
git_merge_preference_t
merge_pref
;
analysis_from_branch
(
&
merge_analysis
,
&
merge_pref
,
UPTODATE_BRANCH
);
analysis_from_branch
(
&
merge_analysis
,
&
merge_pref
,
NULL
,
UPTODATE_BRANCH
);
cl_assert_equal_i
(
GIT_MERGE_ANALYSIS_UP_TO_DATE
,
merge_analysis
);
}
...
...
@@ -91,7 +102,7 @@ void test_merge_workdir_analysis__uptodate_merging_prev_commit(void)
git_merge_analysis_t
merge_analysis
;
git_merge_preference_t
merge_pref
;
analysis_from_branch
(
&
merge_analysis
,
&
merge_pref
,
PREVIOUS_BRANCH
);
analysis_from_branch
(
&
merge_analysis
,
&
merge_pref
,
NULL
,
PREVIOUS_BRANCH
);
cl_assert_equal_i
(
GIT_MERGE_ANALYSIS_UP_TO_DATE
,
merge_analysis
);
}
...
...
@@ -104,9 +115,8 @@ void test_merge_workdir_analysis__unborn(void)
git_buf_joinpath
(
&
master
,
git_repository_path
(
repo
),
"refs/heads/master"
);
p_unlink
(
git_buf_cstr
(
&
master
));
analysis_from_branch
(
&
merge_analysis
,
&
merge_pref
,
NOFASTFORWARD_BRANCH
);
cl_assert_equal_i
(
GIT_MERGE_ANALYSIS_FASTFORWARD
,
(
merge_analysis
&
GIT_MERGE_ANALYSIS_FASTFORWARD
));
cl_assert_equal_i
(
GIT_MERGE_ANALYSIS_UNBORN
,
(
merge_analysis
&
GIT_MERGE_ANALYSIS_UNBORN
));
analysis_from_branch
(
&
merge_analysis
,
&
merge_pref
,
NULL
,
NOFASTFORWARD_BRANCH
);
cl_assert_equal_i
(
GIT_MERGE_ANALYSIS_FASTFORWARD
|
GIT_MERGE_ANALYSIS_UNBORN
,
merge_analysis
);
git_buf_dispose
(
&
master
);
}
...
...
@@ -120,9 +130,9 @@ void test_merge_workdir_analysis__fastforward_with_config_noff(void)
git_repository_config
(
&
config
,
repo
);
git_config_set_string
(
config
,
"merge.ff"
,
"false"
);
analysis_from_branch
(
&
merge_analysis
,
&
merge_pref
,
FASTFORWARD_BRANCH
);
cl_assert_equal_i
(
GIT_MERGE_ANALYSIS_
FASTFORWARD
,
(
merge_analysis
&
GIT_MERGE_ANALYSIS_FASTFORWARD
)
);
cl_assert_equal_i
(
GIT_MERGE_ANALYSIS_NORMAL
,
(
merge_analysis
&
GIT_MERGE_ANALYSIS_NORMAL
));
analysis_from_branch
(
&
merge_analysis
,
&
merge_pref
,
NULL
,
FASTFORWARD_BRANCH
);
cl_assert_equal_i
(
GIT_MERGE_ANALYSIS_
NORMAL
|
GIT_MERGE_ANALYSIS_FASTFORWARD
,
merge_analysis
);
cl_assert_equal_i
(
GIT_MERGE_PREFERENCE_NO_FASTFORWARD
,
(
merge_pref
&
GIT_MERGE_PREFERENCE_NO_FASTFORWARD
));
}
...
...
@@ -135,7 +145,26 @@ void test_merge_workdir_analysis__no_fastforward_with_config_ffonly(void)
git_repository_config
(
&
config
,
repo
);
git_config_set_string
(
config
,
"merge.ff"
,
"only"
);
analysis_from_branch
(
&
merge_analysis
,
&
merge_pref
,
NOFASTFORWARD_BRANCH
);
cl_assert_equal_i
(
GIT_MERGE_ANALYSIS_NORMAL
,
(
merge_analysis
&
GIT_MERGE_ANALYSIS_NORMAL
));
analysis_from_branch
(
&
merge_analysis
,
&
merge_pref
,
NULL
,
NOFASTFORWARD_BRANCH
);
cl_assert_equal_i
(
GIT_MERGE_ANALYSIS_NORMAL
,
merge_analysis
);
cl_assert_equal_i
(
GIT_MERGE_PREFERENCE_FASTFORWARD_ONLY
,
(
merge_pref
&
GIT_MERGE_PREFERENCE_FASTFORWARD_ONLY
));
}
void
test_merge_workdir_analysis__between_uptodate_refs
(
void
)
{
git_merge_analysis_t
merge_analysis
;
git_merge_preference_t
merge_pref
;
analysis_from_branch
(
&
merge_analysis
,
&
merge_pref
,
NOFASTFORWARD_BRANCH
,
PREVIOUS_BRANCH
);
cl_assert_equal_i
(
GIT_MERGE_ANALYSIS_UP_TO_DATE
,
merge_analysis
);
}
void
test_merge_workdir_analysis__between_noff_refs
(
void
)
{
git_merge_analysis_t
merge_analysis
;
git_merge_preference_t
merge_pref
;
analysis_from_branch
(
&
merge_analysis
,
&
merge_pref
,
"branch"
,
FASTFORWARD_BRANCH
);
cl_assert_equal_i
(
GIT_MERGE_ANALYSIS_NORMAL
,
merge_analysis
);
}
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