2 * Copyright (C) the libgit2 contributors. All rights reserved.
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
9 #include "repository.h"
10 #include "merge_file.h"
12 #include "git2/repository.h"
13 #include "git2/object.h"
14 #include "git2/index.h"
16 #include "xdiff/xdiff.h"
18 #define GIT_MERGE_FILE_SIDE_EXISTS(X) ((X)->mode != 0)
20 GIT_INLINE(const char *) merge_file_best_path(
21 const git_merge_file_input
*ancestor
,
22 const git_merge_file_input
*ours
,
23 const git_merge_file_input
*theirs
)
25 if (!GIT_MERGE_FILE_SIDE_EXISTS(ancestor
)) {
26 if (strcmp(ours
->path
, theirs
->path
) == 0)
32 if (strcmp(ancestor
->path
, ours
->path
) == 0)
34 else if(strcmp(ancestor
->path
, theirs
->path
) == 0)
40 GIT_INLINE(int) merge_file_best_mode(
41 const git_merge_file_input
*ancestor
,
42 const git_merge_file_input
*ours
,
43 const git_merge_file_input
*theirs
)
46 * If ancestor didn't exist and either ours or theirs is executable,
47 * assume executable. Otherwise, if any mode changed from the ancestor,
50 if (!GIT_MERGE_FILE_SIDE_EXISTS(ancestor
)) {
51 if (ours
->mode
== GIT_FILEMODE_BLOB_EXECUTABLE
||
52 theirs
->mode
== GIT_FILEMODE_BLOB_EXECUTABLE
)
53 return GIT_FILEMODE_BLOB_EXECUTABLE
;
55 return GIT_FILEMODE_BLOB
;
58 if (ancestor
->mode
== ours
->mode
)
60 else if(ancestor
->mode
== theirs
->mode
)
66 int git_merge_file_input_from_index_entry(
67 git_merge_file_input
*input
,
69 const git_index_entry
*entry
)
74 assert(input
&& repo
&& entry
);
79 if ((error
= git_repository_odb(&odb
, repo
)) < 0 ||
80 (error
= git_odb_read(&input
->odb_object
, odb
, &entry
->oid
)) < 0)
83 input
->mode
= entry
->mode
;
84 input
->path
= git__strdup(entry
->path
);
85 input
->mmfile
.size
= git_odb_object_size(input
->odb_object
);
86 input
->mmfile
.ptr
= (char *)git_odb_object_data(input
->odb_object
);
88 if (input
->label
== NULL
)
89 input
->label
= entry
->path
;
97 int git_merge_file_input_from_diff_file(
98 git_merge_file_input
*input
,
100 const git_diff_file
*file
)
105 assert(input
&& repo
&& file
);
110 if ((error
= git_repository_odb(&odb
, repo
)) < 0 ||
111 (error
= git_odb_read(&input
->odb_object
, odb
, &file
->oid
)) < 0)
114 input
->mode
= file
->mode
;
115 input
->path
= git__strdup(file
->path
);
116 input
->mmfile
.size
= git_odb_object_size(input
->odb_object
);
117 input
->mmfile
.ptr
= (char *)git_odb_object_data(input
->odb_object
);
119 if (input
->label
== NULL
)
120 input
->label
= file
->path
;
129 git_merge_file_result
*out
,
130 git_merge_file_input
*ancestor
,
131 git_merge_file_input
*ours
,
132 git_merge_file_input
*theirs
,
133 git_merge_automerge_flags flags
)
140 assert(out
&& ancestor
&& ours
&& theirs
);
142 memset(out
, 0x0, sizeof(git_merge_file_result
));
144 if (!GIT_MERGE_FILE_SIDE_EXISTS(ours
) || !GIT_MERGE_FILE_SIDE_EXISTS(theirs
))
147 memset(&xmparam
, 0x0, sizeof(xmparam_t
));
148 xmparam
.ancestor
= ancestor
->label
;
149 xmparam
.file1
= ours
->label
;
150 xmparam
.file2
= theirs
->label
;
152 out
->path
= merge_file_best_path(ancestor
, ours
, theirs
);
153 out
->mode
= merge_file_best_mode(ancestor
, ours
, theirs
);
155 if (flags
== GIT_MERGE_AUTOMERGE_FAVOR_OURS
)
156 xmparam
.favor
= XDL_MERGE_FAVOR_OURS
;
158 if (flags
== GIT_MERGE_AUTOMERGE_FAVOR_THEIRS
)
159 xmparam
.favor
= XDL_MERGE_FAVOR_THEIRS
;
161 if ((xdl_result
= xdl_merge(&ancestor
->mmfile
, &ours
->mmfile
,
162 &theirs
->mmfile
, &xmparam
, &mmbuffer
)) < 0) {
163 giterr_set(GITERR_MERGE
, "Failed to merge files.");
168 out
->automergeable
= (xdl_result
== 0);
169 out
->data
= (unsigned char *)mmbuffer
.ptr
;
170 out
->len
= mmbuffer
.size
;