Merge branch 'jc/merge-blobs' into maint
* jc/merge-blobs: Makefile: Replace merge-file.h with merge-blobs.h in LIB_H merge-tree: fix d/f conflicts merge-tree: add comments to clarify what these functions are doing merge-tree: lose unused "resolve_directories" merge-tree: lose unused "flags" from merge_list Which merge_file() function do you mean?
This commit is contained in:
commit
686b895928
4
Makefile
4
Makefile
@ -653,7 +653,7 @@ LIB_H += list-objects.h
|
||||
LIB_H += ll-merge.h
|
||||
LIB_H += log-tree.h
|
||||
LIB_H += mailmap.h
|
||||
LIB_H += merge-file.h
|
||||
LIB_H += merge-blobs.h
|
||||
LIB_H += merge-recursive.h
|
||||
LIB_H += mergesort.h
|
||||
LIB_H += notes-cache.h
|
||||
@ -769,7 +769,7 @@ LIB_OBJS += log-tree.o
|
||||
LIB_OBJS += mailmap.o
|
||||
LIB_OBJS += match-trees.o
|
||||
LIB_OBJS += merge.o
|
||||
LIB_OBJS += merge-file.o
|
||||
LIB_OBJS += merge-blobs.o
|
||||
LIB_OBJS += merge-recursive.o
|
||||
LIB_OBJS += mergesort.o
|
||||
LIB_OBJS += name-hash.o
|
||||
|
@ -42,7 +42,7 @@ static int merge_entry(int pos, const char *path)
|
||||
return found;
|
||||
}
|
||||
|
||||
static void merge_file(const char *path)
|
||||
static void merge_one_path(const char *path)
|
||||
{
|
||||
int pos = cache_name_pos(path, strlen(path));
|
||||
|
||||
@ -102,7 +102,7 @@ int cmd_merge_index(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
die("git merge-index: unknown option %s", arg);
|
||||
}
|
||||
merge_file(arg);
|
||||
merge_one_path(arg);
|
||||
}
|
||||
if (err && !quiet)
|
||||
die("merge program failed");
|
||||
|
@ -3,17 +3,15 @@
|
||||
#include "xdiff-interface.h"
|
||||
#include "blob.h"
|
||||
#include "exec_cmd.h"
|
||||
#include "merge-file.h"
|
||||
#include "merge-blobs.h"
|
||||
|
||||
static const char merge_tree_usage[] = "git merge-tree <base-tree> <branch1> <branch2>";
|
||||
static int resolve_directories = 1;
|
||||
|
||||
struct merge_list {
|
||||
struct merge_list *next;
|
||||
struct merge_list *link; /* other stages for this object */
|
||||
|
||||
unsigned int stage : 2,
|
||||
flags : 30;
|
||||
unsigned int stage : 2;
|
||||
unsigned int mode;
|
||||
const char *path;
|
||||
struct blob *blob;
|
||||
@ -27,7 +25,7 @@ static void add_merge_entry(struct merge_list *entry)
|
||||
merge_result_end = &entry->next;
|
||||
}
|
||||
|
||||
static void merge_trees(struct tree_desc t[3], const char *base);
|
||||
static void merge_trees_recursive(struct tree_desc t[3], const char *base, int df_conflict);
|
||||
|
||||
static const char *explanation(struct merge_list *entry)
|
||||
{
|
||||
@ -76,7 +74,7 @@ static void *result(struct merge_list *entry, unsigned long *size)
|
||||
their = NULL;
|
||||
if (entry)
|
||||
their = entry->blob;
|
||||
return merge_file(path, base, our, their, size);
|
||||
return merge_blobs(path, base, our, their, size);
|
||||
}
|
||||
|
||||
static void *origin(struct merge_list *entry, unsigned long *size)
|
||||
@ -174,17 +172,17 @@ static char *traverse_path(const struct traverse_info *info, const struct name_e
|
||||
return make_traverse_path(path, info, n);
|
||||
}
|
||||
|
||||
static void resolve(const struct traverse_info *info, struct name_entry *branch1, struct name_entry *result)
|
||||
static void resolve(const struct traverse_info *info, struct name_entry *ours, struct name_entry *result)
|
||||
{
|
||||
struct merge_list *orig, *final;
|
||||
const char *path;
|
||||
|
||||
/* If it's already branch1, don't bother showing it */
|
||||
if (!branch1)
|
||||
/* If it's already ours, don't bother showing it */
|
||||
if (!ours)
|
||||
return;
|
||||
|
||||
path = traverse_path(info, result);
|
||||
orig = create_entry(2, branch1->mode, branch1->sha1, path);
|
||||
orig = create_entry(2, ours->mode, ours->sha1, path);
|
||||
final = create_entry(0, result->mode, result->sha1, path);
|
||||
|
||||
final->link = orig;
|
||||
@ -192,34 +190,35 @@ static void resolve(const struct traverse_info *info, struct name_entry *branch1
|
||||
add_merge_entry(final);
|
||||
}
|
||||
|
||||
static int unresolved_directory(const struct traverse_info *info, struct name_entry n[3])
|
||||
static void unresolved_directory(const struct traverse_info *info, struct name_entry n[3],
|
||||
int df_conflict)
|
||||
{
|
||||
char *newbase;
|
||||
struct name_entry *p;
|
||||
struct tree_desc t[3];
|
||||
void *buf0, *buf1, *buf2;
|
||||
|
||||
if (!resolve_directories)
|
||||
return 0;
|
||||
p = n;
|
||||
if (!p->mode) {
|
||||
p++;
|
||||
if (!p->mode)
|
||||
p++;
|
||||
for (p = n; p < n + 3; p++) {
|
||||
if (p->mode && S_ISDIR(p->mode))
|
||||
break;
|
||||
}
|
||||
if (!S_ISDIR(p->mode))
|
||||
return 0;
|
||||
if (n + 3 <= p)
|
||||
return; /* there is no tree here */
|
||||
|
||||
newbase = traverse_path(info, p);
|
||||
buf0 = fill_tree_descriptor(t+0, n[0].sha1);
|
||||
buf1 = fill_tree_descriptor(t+1, n[1].sha1);
|
||||
buf2 = fill_tree_descriptor(t+2, n[2].sha1);
|
||||
merge_trees(t, newbase);
|
||||
|
||||
#define ENTRY_SHA1(e) (((e)->mode && S_ISDIR((e)->mode)) ? (e)->sha1 : NULL)
|
||||
buf0 = fill_tree_descriptor(t+0, ENTRY_SHA1(n + 0));
|
||||
buf1 = fill_tree_descriptor(t+1, ENTRY_SHA1(n + 1));
|
||||
buf2 = fill_tree_descriptor(t+2, ENTRY_SHA1(n + 2));
|
||||
#undef ENTRY_SHA1
|
||||
|
||||
merge_trees_recursive(t, newbase, df_conflict);
|
||||
|
||||
free(buf0);
|
||||
free(buf1);
|
||||
free(buf2);
|
||||
free(newbase);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@ -242,18 +241,26 @@ static struct merge_list *link_entry(unsigned stage, const struct traverse_info
|
||||
static void unresolved(const struct traverse_info *info, struct name_entry n[3])
|
||||
{
|
||||
struct merge_list *entry = NULL;
|
||||
int i;
|
||||
unsigned dirmask = 0, mask = 0;
|
||||
|
||||
if (unresolved_directory(info, n))
|
||||
for (i = 0; i < 3; i++) {
|
||||
mask |= (1 << 1);
|
||||
if (n[i].mode && S_ISDIR(n[i].mode))
|
||||
dirmask |= (1 << i);
|
||||
}
|
||||
|
||||
unresolved_directory(info, n, dirmask && (dirmask != mask));
|
||||
|
||||
if (dirmask == mask)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Do them in reverse order so that the resulting link
|
||||
* list has the stages in order - link_entry adds new
|
||||
* links at the front.
|
||||
*/
|
||||
entry = link_entry(3, info, n + 2, entry);
|
||||
entry = link_entry(2, info, n + 1, entry);
|
||||
entry = link_entry(1, info, n + 0, entry);
|
||||
if (n[2].mode && !S_ISDIR(n[2].mode))
|
||||
entry = link_entry(3, info, n + 2, entry);
|
||||
if (n[1].mode && !S_ISDIR(n[1].mode))
|
||||
entry = link_entry(2, info, n + 1, entry);
|
||||
if (n[0].mode && !S_ISDIR(n[0].mode))
|
||||
entry = link_entry(1, info, n + 0, entry);
|
||||
|
||||
add_merge_entry(entry);
|
||||
}
|
||||
@ -292,20 +299,29 @@ static int threeway_callback(int n, unsigned long mask, unsigned long dirmask, s
|
||||
/* Same in both? */
|
||||
if (same_entry(entry+1, entry+2)) {
|
||||
if (entry[0].sha1) {
|
||||
/* Modified identically */
|
||||
resolve(info, NULL, entry+1);
|
||||
return mask;
|
||||
}
|
||||
/* "Both added the same" is left unresolved */
|
||||
}
|
||||
|
||||
if (same_entry(entry+0, entry+1)) {
|
||||
if (entry[2].sha1 && !S_ISDIR(entry[2].mode)) {
|
||||
/* We did not touch, they modified -- take theirs */
|
||||
resolve(info, entry+1, entry+2);
|
||||
return mask;
|
||||
}
|
||||
/*
|
||||
* If we did not touch a directory but they made it
|
||||
* into a file, we fall through and unresolved()
|
||||
* recurses down. Likewise for the opposite case.
|
||||
*/
|
||||
}
|
||||
|
||||
if (same_entry(entry+0, entry+2)) {
|
||||
if (entry[1].sha1 && !S_ISDIR(entry[1].mode)) {
|
||||
/* We modified, they did not touch -- take ours */
|
||||
resolve(info, NULL, entry+1);
|
||||
return mask;
|
||||
}
|
||||
@ -315,15 +331,21 @@ static int threeway_callback(int n, unsigned long mask, unsigned long dirmask, s
|
||||
return mask;
|
||||
}
|
||||
|
||||
static void merge_trees(struct tree_desc t[3], const char *base)
|
||||
static void merge_trees_recursive(struct tree_desc t[3], const char *base, int df_conflict)
|
||||
{
|
||||
struct traverse_info info;
|
||||
|
||||
setup_traverse_info(&info, base);
|
||||
info.data = &df_conflict;
|
||||
info.fn = threeway_callback;
|
||||
traverse_trees(3, t, &info);
|
||||
}
|
||||
|
||||
static void merge_trees(struct tree_desc t[3], const char *base)
|
||||
{
|
||||
merge_trees_recursive(t, base, 0);
|
||||
}
|
||||
|
||||
static void *get_tree_descriptor(struct tree_desc *desc, const char *rev)
|
||||
{
|
||||
unsigned char sha1[20];
|
||||
|
@ -3,7 +3,7 @@
|
||||
#include "xdiff-interface.h"
|
||||
#include "ll-merge.h"
|
||||
#include "blob.h"
|
||||
#include "merge-file.h"
|
||||
#include "merge-blobs.h"
|
||||
|
||||
static int fill_mmfile_blob(mmfile_t *f, struct blob *obj)
|
||||
{
|
||||
@ -80,7 +80,7 @@ static int generate_common_file(mmfile_t *res, mmfile_t *f1, mmfile_t *f2)
|
||||
return xdi_diff(f1, f2, &xpp, &xecfg, &ecb);
|
||||
}
|
||||
|
||||
void *merge_file(const char *path, struct blob *base, struct blob *our, struct blob *their, unsigned long *size)
|
||||
void *merge_blobs(const char *path, struct blob *base, struct blob *our, struct blob *their, unsigned long *size)
|
||||
{
|
||||
void *res = NULL;
|
||||
mmfile_t f1, f2, common;
|
8
merge-blobs.h
Normal file
8
merge-blobs.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef MERGE_BLOBS_H
|
||||
#define MERGE_BLOBS_H
|
||||
|
||||
#include "blob.h"
|
||||
|
||||
extern void *merge_blobs(const char *, struct blob *, struct blob *, struct blob *, unsigned long *);
|
||||
|
||||
#endif /* MERGE_BLOBS_H */
|
@ -1,7 +0,0 @@
|
||||
#ifndef MERGE_FILE_H
|
||||
#define MERGE_FILE_H
|
||||
|
||||
extern void *merge_file(const char *path, struct blob *base, struct blob *our,
|
||||
struct blob *their, unsigned long *size);
|
||||
|
||||
#endif
|
@ -976,7 +976,7 @@ merge_file_special_markers(struct merge_options *o,
|
||||
return mfi;
|
||||
}
|
||||
|
||||
static struct merge_file_info merge_file(struct merge_options *o,
|
||||
static struct merge_file_info merge_file_one(struct merge_options *o,
|
||||
const char *path,
|
||||
const unsigned char *o_sha, int o_mode,
|
||||
const unsigned char *a_sha, int a_mode,
|
||||
@ -1166,7 +1166,7 @@ static void conflict_rename_rename_1to2(struct merge_options *o,
|
||||
struct merge_file_info mfi;
|
||||
struct diff_filespec other;
|
||||
struct diff_filespec *add;
|
||||
mfi = merge_file(o, one->path,
|
||||
mfi = merge_file_one(o, one->path,
|
||||
one->sha1, one->mode,
|
||||
a->sha1, a->mode,
|
||||
b->sha1, b->mode,
|
||||
@ -1450,7 +1450,7 @@ static int process_renames(struct merge_options *o,
|
||||
ren1_dst, branch2);
|
||||
if (o->call_depth) {
|
||||
struct merge_file_info mfi;
|
||||
mfi = merge_file(o, ren1_dst, null_sha1, 0,
|
||||
mfi = merge_file_one(o, ren1_dst, null_sha1, 0,
|
||||
ren1->pair->two->sha1, ren1->pair->two->mode,
|
||||
dst_other.sha1, dst_other.mode,
|
||||
branch1, branch2);
|
||||
|
@ -254,4 +254,48 @@ EXPECTED
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
test_expect_success 'turn file to tree' '
|
||||
git reset --hard initial &&
|
||||
rm initial-file &&
|
||||
mkdir initial-file &&
|
||||
test_commit "turn-file-to-tree" "initial-file/ONE" "CCC" &&
|
||||
git merge-tree initial initial turn-file-to-tree >actual &&
|
||||
cat >expect <<-\EOF &&
|
||||
added in remote
|
||||
their 100644 43aa4fdec31eb92e1fdc2f0ce6ea9ddb7c32bcf7 initial-file/ONE
|
||||
@@ -0,0 +1 @@
|
||||
+CCC
|
||||
removed in remote
|
||||
base 100644 e79c5e8f964493290a409888d5413a737e8e5dd5 initial-file
|
||||
our 100644 e79c5e8f964493290a409888d5413a737e8e5dd5 initial-file
|
||||
@@ -1 +0,0 @@
|
||||
-initial
|
||||
EOF
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'turn tree to file' '
|
||||
git reset --hard initial &&
|
||||
mkdir dir &&
|
||||
test_commit "add-tree" "dir/path" "AAA" &&
|
||||
test_commit "add-another-tree" "dir/another" "BBB" &&
|
||||
rm -fr dir &&
|
||||
test_commit "make-file" "dir" "CCC" &&
|
||||
git merge-tree add-tree add-another-tree make-file >actual &&
|
||||
cat >expect <<-\EOF &&
|
||||
added in local
|
||||
our 100644 ba629238ca89489f2b350e196ca445e09d8bb834 dir/another
|
||||
removed in remote
|
||||
base 100644 43d5a8ed6ef6c00ff775008633f95787d088285d dir/path
|
||||
our 100644 43d5a8ed6ef6c00ff775008633f95787d088285d dir/path
|
||||
@@ -1 +0,0 @@
|
||||
-AAA
|
||||
added in remote
|
||||
their 100644 43aa4fdec31eb92e1fdc2f0ce6ea9ddb7c32bcf7 dir
|
||||
@@ -0,0 +1 @@
|
||||
+CCC
|
||||
EOF
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_done
|
||||
|
Loading…
Reference in New Issue
Block a user