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
ccb30827
Commit
ccb30827
authored
Mar 11, 2014
by
Edward Thomson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add `git_merge_status` to provide info about an upcoming merge
parent
05d47768
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
204 additions
and
157 deletions
+204
-157
include/git2/merge.h
+40
-0
src/merge.c
+74
-9
tests/merge/workdir/fastforward.c
+0
-148
tests/merge/workdir/status.c
+89
-0
tests/resources/merge-resolve/.gitted/refs/heads/previous
+1
-0
No files found.
include/git2/merge.h
View file @
ccb30827
...
...
@@ -235,6 +235,46 @@ GIT_EXTERN(int) git_merge_tree_init_opts(
int
version
);
/**
* The results of `git_merge_status` indicate the state of a merge scenario.
*/
typedef
enum
{
/**
* A "normal" merge; both HEAD and the given merge input have diverged
* from their common ancestor. The divergent commits must be merged.
*/
GIT_MERGE_STATUS_NORMAL
=
0
,
/**
* The repository is already up-to-date and no merge needs to be
* performed. The given merge input already exists as a parent of HEAD.
*/
GIT_MERGE_STATUS_UP_TO_DATE
=
(
1
<<
0
),
/**
* The given merge input is a fast-forward from HEAD and no merge
* needs to be performed. Instead, the client can check out the
* given merge input.
*/
GIT_MERGE_STATUS_FASTFORWARD
=
(
1
<<
1
),
}
git_merge_status_t
;
/**
* Determine the status of the merge between the given branch(es) and the
* HEAD of the repository.
*
* @param status_out status enumeration that the result is written into
* @param repo the repository to merge
* @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_status
(
git_merge_status_t
*
status_out
,
git_repository
*
repo
,
const
git_merge_head
**
their_heads
,
size_t
their_heads_len
);
/**
* Option flags for `git_merge`.
*/
typedef
enum
{
...
...
src/merge.c
View file @
ccb30827
...
...
@@ -2497,6 +2497,79 @@ static int merge_state_cleanup(git_repository *repo)
return
git_repository__cleanup_files
(
repo
,
state_files
,
ARRAY_SIZE
(
state_files
));
}
static
int
merge_heads
(
git_merge_head
**
ancestor_head_out
,
git_merge_head
**
our_head_out
,
git_repository
*
repo
,
const
git_merge_head
**
their_heads
,
size_t
their_heads_len
)
{
git_merge_head
*
ancestor_head
=
NULL
,
*
our_head
=
NULL
;
git_reference
*
our_ref
=
NULL
;
int
error
=
0
;
*
ancestor_head_out
=
NULL
;
*
our_head_out
=
NULL
;
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_merge_head_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
)
{
if
(
error
!=
GIT_ENOTFOUND
)
goto
done
;
giterr_clear
();
error
=
0
;
}
*
ancestor_head_out
=
ancestor_head
;
*
our_head_out
=
our_head
;
done
:
if
(
error
<
0
)
{
git_merge_head_free
(
ancestor_head
);
git_merge_head_free
(
our_head
);
}
git_reference_free
(
our_ref
);
return
error
;
}
int
git_merge_status
(
git_merge_status_t
*
out
,
git_repository
*
repo
,
const
git_merge_head
**
their_heads
,
size_t
their_heads_len
)
{
git_merge_head
*
ancestor_head
=
NULL
,
*
our_head
=
NULL
;
int
error
;
assert
(
out
&&
repo
&&
their_heads
);
*
out
=
GIT_MERGE_STATUS_NORMAL
;
if
((
error
=
merge_heads
(
&
ancestor_head
,
&
our_head
,
repo
,
their_heads
,
their_heads_len
))
<
0
)
goto
done
;
if
(
their_heads_len
==
1
&&
ancestor_head
!=
NULL
)
{
/* We're up-to-date if we're trying to merge our own common ancestor. */
if
(
git_oid_equal
(
&
ancestor_head
->
oid
,
&
their_heads
[
0
]
->
oid
))
*
out
=
GIT_MERGE_STATUS_UP_TO_DATE
;
/* We're fastforwardable if we're our own common ancestor. */
else
if
(
git_oid_equal
(
&
ancestor_head
->
oid
,
&
our_head
->
oid
))
*
out
=
GIT_MERGE_STATUS_FASTFORWARD
;
}
done
:
return
error
;
}
int
git_merge
(
git_merge_result
**
out
,
git_repository
*
repo
,
...
...
@@ -2530,15 +2603,7 @@ int git_merge(
their_trees
=
git__calloc
(
their_heads_len
,
sizeof
(
git_tree
*
));
GITERR_CHECK_ALLOC
(
their_trees
);
if
((
error
=
git_repository__ensure_not_bare
(
repo
,
"merge"
))
<
0
)
goto
on_error
;
if
((
error
=
git_reference_lookup
(
&
our_ref
,
repo
,
GIT_HEAD_FILE
))
<
0
||
(
error
=
git_merge_head_from_ref
(
&
our_head
,
repo
,
our_ref
))
<
0
)
goto
on_error
;
if
((
error
=
merge_ancestor_head
(
&
ancestor_head
,
repo
,
our_head
,
their_heads
,
their_heads_len
))
<
0
&&
error
!=
GIT_ENOTFOUND
)
if
((
error
=
merge_heads
(
&
ancestor_head
,
&
our_head
,
repo
,
their_heads
,
their_heads_len
))
<
0
)
goto
on_error
;
if
((
error
=
merge_normalize_opts
(
repo
,
&
opts
,
given_opts
,
ancestor_head
,
our_head
,
their_heads_len
,
their_heads
))
<
0
)
...
...
tests/merge/workdir/fastforward.c
deleted
100644 → 0
View file @
05d47768
#include "clar_libgit2.h"
#include "git2/repository.h"
#include "git2/merge.h"
#include "git2/sys/index.h"
#include "merge.h"
#include "../merge_helpers.h"
#include "refs.h"
static
git_repository
*
repo
;
static
git_index
*
repo_index
;
#define TEST_REPO_PATH "merge-resolve"
#define TEST_INDEX_PATH TEST_REPO_PATH "/.git/index"
#define THEIRS_FASTFORWARD_BRANCH "ff_branch"
#define THEIRS_FASTFORWARD_ID "fd89f8cffb663ac89095a0f9764902e93ceaca6a"
#define THEIRS_NOFASTFORWARD_BRANCH "branch"
#define THEIRS_NOFASTFORWARD_ID "7cb63eed597130ba4abb87b3e544b85021905520"
// Fixture setup and teardown
void
test_merge_workdir_fastforward__initialize
(
void
)
{
repo
=
cl_git_sandbox_init
(
TEST_REPO_PATH
);
git_repository_index
(
&
repo_index
,
repo
);
}
void
test_merge_workdir_fastforward__cleanup
(
void
)
{
git_index_free
(
repo_index
);
cl_git_sandbox_cleanup
();
}
static
git_merge_result
*
merge_fastforward_branch
(
int
flags
)
{
git_reference
*
their_ref
;
git_merge_head
*
their_heads
[
1
];
git_merge_result
*
result
;
git_merge_opts
opts
=
GIT_MERGE_OPTS_INIT
;
opts
.
merge_flags
=
flags
;
cl_git_pass
(
git_reference_lookup
(
&
their_ref
,
repo
,
GIT_REFS_HEADS_DIR
THEIRS_FASTFORWARD_BRANCH
));
cl_git_pass
(
git_merge_head_from_ref
(
&
their_heads
[
0
],
repo
,
their_ref
));
cl_git_pass
(
git_merge
(
&
result
,
repo
,
(
const
git_merge_head
**
)
their_heads
,
1
,
&
opts
));
git_merge_head_free
(
their_heads
[
0
]);
git_reference_free
(
their_ref
);
return
result
;
}
void
test_merge_workdir_fastforward__fastforward
(
void
)
{
git_merge_result
*
result
;
git_oid
expected
,
ff_oid
;
cl_git_pass
(
git_oid_fromstr
(
&
expected
,
THEIRS_FASTFORWARD_ID
));
cl_assert
(
result
=
merge_fastforward_branch
(
0
));
cl_assert
(
git_merge_result_is_fastforward
(
result
));
cl_git_pass
(
git_merge_result_fastforward_id
(
&
ff_oid
,
result
));
cl_assert
(
git_oid_cmp
(
&
ff_oid
,
&
expected
)
==
0
);
git_merge_result_free
(
result
);
}
void
test_merge_workdir_fastforward__fastforward_only
(
void
)
{
git_merge_result
*
result
;
git_merge_opts
opts
=
GIT_MERGE_OPTS_INIT
;
git_reference
*
their_ref
;
git_merge_head
*
their_head
;
int
error
;
opts
.
merge_flags
=
GIT_MERGE_FASTFORWARD_ONLY
;
cl_git_pass
(
git_reference_lookup
(
&
their_ref
,
repo
,
GIT_REFS_HEADS_DIR
THEIRS_NOFASTFORWARD_BRANCH
));
cl_git_pass
(
git_merge_head_from_ref
(
&
their_head
,
repo
,
their_ref
));
cl_git_fail
((
error
=
git_merge
(
&
result
,
repo
,
(
const
git_merge_head
**
)
&
their_head
,
1
,
&
opts
)));
cl_assert
(
error
==
GIT_ENONFASTFORWARD
);
git_merge_head_free
(
their_head
);
git_reference_free
(
their_ref
);
}
void
test_merge_workdir_fastforward__no_fastforward
(
void
)
{
git_merge_result
*
result
;
struct
merge_index_entry
merge_index_entries
[]
=
{
{
0100644
,
"233c0919c998ed110a4b6ff36f353aec8b713487"
,
0
,
"added-in-master.txt"
},
{
0100644
,
"ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf"
,
0
,
"automergeable.txt"
},
{
0100644
,
"ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b"
,
0
,
"changed-in-branch.txt"
},
{
0100644
,
"bd9cb4cd0a770cb9adcb5fce212142ef40ea1c35"
,
0
,
"changed-in-master.txt"
},
{
0100644
,
"4e886e602529caa9ab11d71f86634bd1b6e0de10"
,
0
,
"conflicting.txt"
},
{
0100644
,
"364bbe4ce80c7bd31e6307dce77d46e3e1759fb3"
,
0
,
"new-in-ff.txt"
},
{
0100644
,
"dfe3f22baa1f6fce5447901c3086bae368de6bdd"
,
0
,
"removed-in-branch.txt"
},
{
0100644
,
"c8f06f2e3bb2964174677e91f0abead0e43c9e5d"
,
0
,
"unchanged.txt"
},
};
cl_assert
(
result
=
merge_fastforward_branch
(
GIT_MERGE_NO_FASTFORWARD
));
cl_assert
(
!
git_merge_result_is_fastforward
(
result
));
cl_assert
(
merge_test_index
(
repo_index
,
merge_index_entries
,
8
));
cl_assert
(
git_index_reuc_entrycount
(
repo_index
)
==
0
);
git_merge_result_free
(
result
);
}
void
test_merge_workdir_fastforward__uptodate
(
void
)
{
git_reference
*
their_ref
;
git_merge_head
*
their_heads
[
1
];
git_merge_result
*
result
;
cl_git_pass
(
git_reference_lookup
(
&
their_ref
,
repo
,
GIT_HEAD_FILE
));
cl_git_pass
(
git_merge_head_from_ref
(
&
their_heads
[
0
],
repo
,
their_ref
));
cl_git_pass
(
git_merge
(
&
result
,
repo
,
(
const
git_merge_head
**
)
their_heads
,
1
,
NULL
));
cl_assert
(
git_merge_result_is_uptodate
(
result
));
git_merge_head_free
(
their_heads
[
0
]);
git_reference_free
(
their_ref
);
git_merge_result_free
(
result
);
}
void
test_merge_workdir_fastforward__uptodate_merging_prev_commit
(
void
)
{
git_oid
their_oid
;
git_merge_head
*
their_heads
[
1
];
git_merge_result
*
result
;
cl_git_pass
(
git_oid_fromstr
(
&
their_oid
,
"c607fc30883e335def28cd686b51f6cfa02b06ec"
));
cl_git_pass
(
git_merge_head_from_id
(
&
their_heads
[
0
],
repo
,
&
their_oid
));
cl_git_pass
(
git_merge
(
&
result
,
repo
,
(
const
git_merge_head
**
)
their_heads
,
1
,
NULL
));
cl_assert
(
git_merge_result_is_uptodate
(
result
));
git_merge_head_free
(
their_heads
[
0
]);
git_merge_result_free
(
result
);
}
tests/merge/workdir/status.c
0 → 100644
View file @
ccb30827
#include "clar_libgit2.h"
#include "git2/repository.h"
#include "git2/merge.h"
#include "git2/sys/index.h"
#include "merge.h"
#include "../merge_helpers.h"
#include "refs.h"
static
git_repository
*
repo
;
static
git_index
*
repo_index
;
#define TEST_REPO_PATH "merge-resolve"
#define TEST_INDEX_PATH TEST_REPO_PATH "/.git/index"
#define UPTODATE_BRANCH "master"
#define PREVIOUS_BRANCH "previous"
#define FASTFORWARD_BRANCH "ff_branch"
#define FASTFORWARD_ID "fd89f8cffb663ac89095a0f9764902e93ceaca6a"
#define NOFASTFORWARD_BRANCH "branch"
#define NOFASTFORWARD_ID "7cb63eed597130ba4abb87b3e544b85021905520"
// Fixture setup and teardown
void
test_merge_workdir_status__initialize
(
void
)
{
repo
=
cl_git_sandbox_init
(
TEST_REPO_PATH
);
git_repository_index
(
&
repo_index
,
repo
);
}
void
test_merge_workdir_status__cleanup
(
void
)
{
git_index_free
(
repo_index
);
cl_git_sandbox_cleanup
();
}
static
git_status_t
status_from_branch
(
const
char
*
branchname
)
{
git_buf
refname
=
GIT_BUF_INIT
;
git_reference
*
their_ref
;
git_merge_head
*
their_heads
[
1
];
git_status_t
status
;
git_buf_printf
(
&
refname
,
"%s%s"
,
GIT_REFS_HEADS_DIR
,
branchname
);
cl_git_pass
(
git_reference_lookup
(
&
their_ref
,
repo
,
git_buf_cstr
(
&
refname
)));
cl_git_pass
(
git_merge_head_from_ref
(
&
their_heads
[
0
],
repo
,
their_ref
));
cl_git_pass
(
git_merge_status
(
&
status
,
repo
,
their_heads
,
1
));
git_buf_free
(
&
refname
);
git_merge_head_free
(
their_heads
[
0
]);
git_reference_free
(
their_ref
);
return
status
;
}
void
test_merge_workdir_status__fastforward
(
void
)
{
git_merge_status_t
status
;
status
=
status_from_branch
(
FASTFORWARD_BRANCH
);
cl_assert_equal_i
(
GIT_MERGE_STATUS_FASTFORWARD
,
status
);
}
void
test_merge_workdir_status__no_fastforward
(
void
)
{
git_merge_status_t
status
;
status
=
status_from_branch
(
NOFASTFORWARD_BRANCH
);
cl_assert_equal_i
(
GIT_MERGE_STATUS_NORMAL
,
status
);
}
void
test_merge_workdir_status__uptodate
(
void
)
{
git_merge_status_t
status
;
status
=
status_from_branch
(
UPTODATE_BRANCH
);
cl_assert_equal_i
(
GIT_MERGE_STATUS_UP_TO_DATE
,
status
);
}
void
test_merge_workdir_status__uptodate_merging_prev_commit
(
void
)
{
git_merge_status_t
status
;
status
=
status_from_branch
(
PREVIOUS_BRANCH
);
cl_assert_equal_i
(
GIT_MERGE_STATUS_UP_TO_DATE
,
status
);
}
tests/resources/merge-resolve/.gitted/refs/heads/previous
0 → 100644
View file @
ccb30827
c607fc30883e335def28cd686b51f6cfa02b06ec
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