Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Recursive Merge #3513

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Nov 30, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ v0.23 + 1

### Breaking API changes

* The `git_merge_tree_flag_t` is now `git_merge_flag_t`. Subsequently,
its members are no longer prefixed with `GIT_MERGE_TREE_FLAG` but are
now prefixed with `GIT_MERGE_FLAG`, and the `tree_flags` field of the
`git_merge_options` structure is now named `flags`.

* The `git_merge_file_flags_t` enum is now `git_merge_file_flag_t` for
consistency with other enum type names.

* `git_cert` descendent types now have a proper `parent` member

* It is the responsibility of the refdb backend to decide what to do
Expand Down
44 changes: 31 additions & 13 deletions include/git2/merge.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,29 +62,37 @@ GIT_EXTERN(int) git_merge_file_init_input(
unsigned int version);

/**
* Flags for `git_merge_tree` options. A combination of these flags can be
* passed in via the `tree_flags` value in the `git_merge_options`.
* Flags for `git_merge` options. A combination of these flags can be
* passed in via the `flags` value in the `git_merge_options`.
*/
typedef enum {
/**
* Detect renames that occur between the common ancestor and the "ours"
* side or the common ancestor and the "theirs" side. This will enable
* the ability to merge between a modified and renamed file.
*/
GIT_MERGE_TREE_FIND_RENAMES = (1 << 0),
GIT_MERGE_FIND_RENAMES = (1 << 0),

/**
* If a conflict occurs, exit immediately instead of attempting to
* continue resolving conflicts. The merge operation will fail with
* GIT_EMERGECONFLICT and no index will be returned.
*/
GIT_MERGE_TREE_FAIL_ON_CONFLICT = (1 << 1),
GIT_MERGE_FAIL_ON_CONFLICT = (1 << 1),

/**
* Do not write the REUC extension on the generated index
*/
GIT_MERGE_TREE_SKIP_REUC = (1 << 2),
} git_merge_tree_flag_t;
GIT_MERGE_SKIP_REUC = (1 << 2),

/**
* If the commits being merged have multiple merge bases, do not build
* a recursive merge base (by merging the multiple merge bases),
* instead simply use the first base. This flag provides a similar
* merge base to `git-merge-resolve`.
*/
GIT_MERGE_NO_RECURSIVE = (1 << 3),
} git_merge_flag_t;

/**
* Merge file favor options for `git_merge_options` instruct the file-level
Expand Down Expand Up @@ -152,7 +160,7 @@ typedef enum {

/** Take extra time to find minimal diff */
GIT_MERGE_FILE_DIFF_MINIMAL = (1 << 7),
} git_merge_file_flags_t;
} git_merge_file_flag_t;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This name change should also be reflected in the CHANGELOG.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.


/**
* Options for merging a file
Expand Down Expand Up @@ -181,8 +189,8 @@ typedef struct {
/** The file to favor in region conflicts. */
git_merge_file_favor_t favor;

/** see `git_merge_file_flags_t` above */
unsigned int flags;
/** see `git_merge_file_flag_t` above */
git_merge_file_flag_t flags;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Multiple options from git_merge_file_flag_t may be specified, that is the diff style, whitespace options etc.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, and this doesn't preclude that. This is to match the style in the rest of the library where enum types are named in the singular, even when they will be combined. For example: git_repository_open_flag_t.

} git_merge_file_options;

#define GIT_MERGE_FILE_OPTIONS_VERSION 1
Expand Down Expand Up @@ -232,11 +240,13 @@ typedef struct {
*/
typedef struct {
unsigned int version;
git_merge_tree_flag_t tree_flags;

/** See `git_merge_flag_t` above */
git_merge_flag_t flags;

/**
* Similarity to consider a file renamed (default 50). If
* `GIT_MERGE_TREE_FIND_RENAMES` is enabled, added files will be compared
* `GIT_MERGE_FIND_RENAMES` is enabled, added files will be compared
* with deleted files to determine their similarity. Files that are
* more similar than the rename threshold (percentage-wise) will be
* treated as a rename.
Expand All @@ -255,11 +265,19 @@ typedef struct {
/** Pluggable similarity metric; pass NULL to use internal metric */
git_diff_similarity_metric *metric;

/**
* Maximum number of times to merge common ancestors to build a
* virtual merge base when faced with criss-cross merges. When this
* limit is reached, the next ancestor will simply be used instead of
* attempting to merge it. The default is unlimited.
*/
unsigned int recursion_limit;

/** Flags for handling conflicting content. */
git_merge_file_favor_t file_favor;

/** see `git_merge_file_flags_t` above */
unsigned int file_flags;
/** see `git_merge_file_flag_t` above */
git_merge_file_flag_t file_flags;
} git_merge_options;

#define GIT_MERGE_OPTIONS_VERSION 1
Expand Down
89 changes: 71 additions & 18 deletions src/annotated_commit.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,16 @@

#include "common.h"
#include "annotated_commit.h"
#include "refs.h"
#include "cache.h"

#include "git2/commit.h"
#include "git2/refs.h"
#include "git2/repository.h"
#include "git2/annotated_commit.h"
#include "git2/revparse.h"
#include "git2/tree.h"
#include "git2/index.h"

static int annotated_commit_init(
git_annotated_commit **out,
Expand All @@ -22,14 +26,17 @@ static int annotated_commit_init(
const char *remote_url)
{
git_annotated_commit *annotated_commit;
git_commit *commit = NULL;
int error = 0;

assert(out && id);

*out = NULL;

annotated_commit = git__calloc(1, sizeof(git_annotated_commit));
GITERR_CHECK_ALLOC(annotated_commit);
if ((error = git_commit_lookup(&commit, repo, id)) < 0 ||
(error = git_annotated_commit_from_commit(&annotated_commit,
commit)) < 0)
goto done;

if (ref_name) {
annotated_commit->ref_name = git__strdup(ref_name);
Expand All @@ -41,15 +48,10 @@ static int annotated_commit_init(
GITERR_CHECK_ALLOC(annotated_commit->remote_url);
}

git_oid_fmt(annotated_commit->id_str, id);
annotated_commit->id_str[GIT_OID_HEXSZ] = '\0';

if ((error = git_commit_lookup(&annotated_commit->commit, repo, id)) < 0) {
git_annotated_commit_free(annotated_commit);
return error;
}

*out = annotated_commit;

done:
git_commit_free(commit);
return error;
}

Expand All @@ -75,6 +77,51 @@ int git_annotated_commit_from_ref(
return error;
}

int git_annotated_commit_from_head(
git_annotated_commit **out,
git_repository *repo)
{
git_reference *head;
int error;

assert(out && repo);

*out = NULL;

if ((error = git_reference_lookup(&head, repo, GIT_HEAD_FILE)) < 0)
return -1;

error = git_annotated_commit_from_ref(out, repo, head);

git_reference_free(head);
return error;
}

int git_annotated_commit_from_commit(
git_annotated_commit **out,
git_commit *commit)
{
git_annotated_commit *annotated_commit;

assert(out && commit);

*out = NULL;

annotated_commit = git__calloc(1, sizeof(git_annotated_commit));
GITERR_CHECK_ALLOC(annotated_commit);

annotated_commit->type = GIT_ANNOTATED_COMMIT_REAL;

git_cached_obj_incref(commit);
annotated_commit->commit = commit;

git_oid_fmt(annotated_commit->id_str, git_commit_id(commit));
annotated_commit->id_str[GIT_OID_HEXSZ] = '\0';

*out = annotated_commit;
return 0;
}

int git_annotated_commit_lookup(
git_annotated_commit **out,
git_repository *repo,
Expand Down Expand Up @@ -136,14 +183,20 @@ void git_annotated_commit_free(git_annotated_commit *annotated_commit)
if (annotated_commit == NULL)
return;

if (annotated_commit->commit != NULL)
git_commit_free(annotated_commit->commit);

if (annotated_commit->ref_name != NULL)
git__free(annotated_commit->ref_name);

if (annotated_commit->remote_url != NULL)
git__free(annotated_commit->remote_url);
switch (annotated_commit->type) {
case GIT_ANNOTATED_COMMIT_REAL:
git_commit_free(annotated_commit->commit);
git_tree_free(annotated_commit->tree);
git__free(annotated_commit->ref_name);
git__free(annotated_commit->remote_url);
break;
case GIT_ANNOTATED_COMMIT_VIRTUAL:
git_index_free(annotated_commit->index);
git_array_clear(annotated_commit->parents);
break;
default:
abort();
}

git__free(annotated_commit);
}
27 changes: 26 additions & 1 deletion src/annotated_commit.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,41 @@
#ifndef INCLUDE_annotated_commit_h__
#define INCLUDE_annotated_commit_h__

#include "oidarray.h"

#include "git2/oid.h"

/** Internal structure for merge inputs */
typedef enum {
GIT_ANNOTATED_COMMIT_REAL = 1,
GIT_ANNOTATED_COMMIT_VIRTUAL = 2,
} git_annotated_commit_t;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering whether we should have 0 be an invalid value and have 1 and 2 as real and virtual resp. So we can detect in cleanup functions that we failed to set a value.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense. Updated.


/**
* Internal structure for merge inputs. An annotated commit is generally
* "real" and backed by an actual commit in the repository, but merge will
* internally create "virtual" commits that are in-memory intermediate
* commits backed by an index.
*/
struct git_annotated_commit {
git_annotated_commit_t type;

/* real commit */
git_commit *commit;
git_tree *tree;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is there a new tree pointer for real annotated commits? Do we need to keep it around so the iterator can borrow the value?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's correct.


/* virtual commit structure */
git_index *index;
git_array_oid_t parents;

char *ref_name;
char *remote_url;

char id_str[GIT_OID_HEXSZ+1];
};

extern int git_annotated_commit_from_head(git_annotated_commit **out,
git_repository *repo);
extern int git_annotated_commit_from_commit(git_annotated_commit **out,
git_commit *commit);

#endif
Loading