summaryrefslogtreecommitdiff
path: root/merge-recursive.c
diff options
context:
space:
mode:
Diffstat (limited to 'merge-recursive.c')
-rw-r--r--merge-recursive.c29
1 files changed, 29 insertions, 0 deletions
diff --git a/merge-recursive.c b/merge-recursive.c
index 2b614b64ba..3096594b3e 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -16,6 +16,22 @@
#include "path-list.h"
#include "xdiff-interface.h"
+static int subtree_merge;
+
+static struct tree *shift_tree_object(struct tree *one, struct tree *two)
+{
+ unsigned char shifted[20];
+
+ /*
+ * NEEDSWORK: this limits the recursion depth to hardcoded
+ * value '2' to avoid excessive overhead.
+ */
+ shift_tree(one->object.sha1, two->object.sha1, shifted, 2);
+ if (!hashcmp(two->object.sha1, shifted))
+ return two;
+ return lookup_tree(shifted);
+}
+
/*
* A virtual commit has
* - (const char *)commit->util set to the name, and
@@ -1137,6 +1153,12 @@ static int merge_trees(struct tree *head,
struct tree **result)
{
int code, clean;
+
+ if (subtree_merge) {
+ merge = shift_tree_object(head, merge);
+ common = shift_tree_object(head, common);
+ }
+
if (sha_eq(common->object.sha1, merge->object.sha1)) {
output(0, "Already uptodate!");
*result = head;
@@ -1342,6 +1364,13 @@ int main(int argc, char *argv[])
struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
int index_fd;
+ if (argv[0]) {
+ int namelen = strlen(argv[0]);
+ if (8 < namelen &&
+ !strcmp(argv[0] + namelen - 8, "-subtree"))
+ subtree_merge = 1;
+ }
+
git_config(merge_config);
if (getenv("GIT_MERGE_VERBOSITY"))
verbosity = strtol(getenv("GIT_MERGE_VERBOSITY"), NULL, 10);