summaryrefslogtreecommitdiff
path: root/src/merge.h
blob: d7d1c67b7aa6c4c368156c8a239f8dc726c516bb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/*
 * 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_merge_h__
#define INCLUDE_merge_h__

#include "vector.h"
#include "commit_list.h"
#include "pool.h"

#include "git2/merge.h"
#include "git2/types.h"

#define GIT_MERGE_MSG_FILE		"MERGE_MSG"
#define GIT_MERGE_MODE_FILE		"MERGE_MODE"
#define GIT_MERGE_FILE_MODE		0666

#define GIT_MERGE_TREE_RENAME_THRESHOLD	50
#define GIT_MERGE_TREE_TARGET_LIMIT		1000

/** Types of changes when files are merged from branch to branch. */
typedef enum {
	/* No conflict - a change only occurs in one branch. */
	GIT_MERGE_DIFF_NONE = 0,

	/* Occurs when a file is modified in both branches. */
	GIT_MERGE_DIFF_BOTH_MODIFIED = (1 << 0),

	/* Occurs when a file is added in both branches. */
	GIT_MERGE_DIFF_BOTH_ADDED = (1 << 1),

	/* Occurs when a file is deleted in both branches. */
	GIT_MERGE_DIFF_BOTH_DELETED = (1 << 2),

	/* Occurs when a file is modified in one branch and deleted in the other. */
	GIT_MERGE_DIFF_MODIFIED_DELETED = (1 << 3),

	/* Occurs when a file is renamed in one branch and modified in the other. */
	GIT_MERGE_DIFF_RENAMED_MODIFIED = (1 << 4),

	/* Occurs when a file is renamed in one branch and deleted in the other. */
	GIT_MERGE_DIFF_RENAMED_DELETED = (1 << 5),

	/* Occurs when a file is renamed in one branch and a file with the same
	 * name is added in the other.  Eg, A->B and new file B.  Core git calls
	 * this a "rename/delete". */
	GIT_MERGE_DIFF_RENAMED_ADDED = (1 << 6),

	/* Occurs when both a file is renamed to the same name in the ours and
	 * theirs branches.  Eg, A->B and A->B in both.  Automergeable. */
	GIT_MERGE_DIFF_BOTH_RENAMED = (1 << 7),

	/* Occurs when a file is renamed to different names in the ours and theirs
	 * branches.  Eg, A->B and A->C. */
	GIT_MERGE_DIFF_BOTH_RENAMED_1_TO_2 = (1 << 8),

	/* Occurs when two files are renamed to the same name in the ours and
	 * theirs branches.  Eg, A->C and B->C. */
	GIT_MERGE_DIFF_BOTH_RENAMED_2_TO_1 = (1 << 9),

	/* Occurs when an item at a path in one branch is a directory, and an
	 * item at the same path in a different branch is a file. */
	GIT_MERGE_DIFF_DIRECTORY_FILE = (1 << 10),

	/* The child of a folder that is in a directory/file conflict. */
	GIT_MERGE_DIFF_DF_CHILD = (1 << 11),
} git_merge_diff_type_t;


typedef struct {
	git_repository *repo;
	git_pool pool;

	/* Vector of git_index_entry that represent the merged items that
	 * have been staged, either because only one side changed, or because
	 * the two changes were non-conflicting and mergeable.  These items
	 * will be written as staged entries in the main index.
	 */
	git_vector staged;

	/* Vector of git_merge_diff entries that represent the conflicts that
	 * have not been automerged.  These items will be written to high-stage
	 * entries in the main index.
	 */
	git_vector conflicts;

	/* Vector of git_merge_diff that have been automerged.  These items
	 * will be written to the REUC when the index is produced.
	 */
	git_vector resolved;
} git_merge_diff_list;

/**
 * Description of changes to one file across three trees.
 */
typedef struct {
	git_merge_diff_type_t type;

	git_index_entry ancestor_entry;

	git_index_entry our_entry;
	git_delta_t our_status;

	git_index_entry their_entry;
	git_delta_t their_status;
} git_merge_diff;

/** Internal structure for merge inputs */
struct git_merge_head {
	char *ref_name;
	char *remote_url;

	git_oid oid;
	char oid_str[GIT_OID_HEXSZ+1];
	git_commit *commit;
};

/** Internal structure for merge results */
struct git_merge_result {
	bool is_uptodate;

	bool is_fastforward;
	git_oid fastforward_oid;

	git_index *index;
};

int git_merge__bases_many(
	git_commit_list **out,
	git_revwalk *walk,
	git_commit_list_node *one,
	git_vector *twos);

/*
 * Three-way tree differencing
 */

git_merge_diff_list *git_merge_diff_list__alloc(git_repository *repo);

int git_merge_diff_list__find_differences(git_merge_diff_list *merge_diff_list,
	const git_tree *ancestor_tree,
	const git_tree *ours_tree,
	const git_tree *theirs_tree);

int git_merge_diff_list__find_renames(git_repository *repo, git_merge_diff_list *merge_diff_list, const git_merge_tree_opts *opts);

void git_merge_diff_list__free(git_merge_diff_list *diff_list);

/* Merge metadata setup */

int git_merge__setup(
	git_repository *repo,
	const git_merge_head *our_head,
	const git_merge_head *their_heads[],
	size_t their_heads_len,
	unsigned int flags);

#endif