When merge-recursive gets to a dirlink, it starts an automatic submodule merge and then uses the resulting merge commit for the top-level tree. The submodule merge is done in another process to decouple object databases. Signed-off-by: Martin Waitz <tali@xxxxxxxxxxxxxx> --- .gitignore | 1 + Makefile | 2 +- git-dirlink-merge.sh | 28 ++++++++++++++++++++++++++++ merge-recursive.c | 36 ++++++++++++++++++++++++++++++++++++ 4 files changed, 66 insertions(+), 1 deletions(-) create mode 100644 git-dirlink-merge.sh diff --git a/.gitignore b/.gitignore index 8436a83..b076e2f 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,7 @@ git-diff-files git-diff-index git-diff-tree git-dirlink-checkout +git-dirlink-merge git-describe git-fast-import git-fetch diff --git a/Makefile b/Makefile index fcd0125..ff24477 100644 --- a/Makefile +++ b/Makefile @@ -196,7 +196,7 @@ SCRIPT_SH = \ git-merge-one-file.sh git-mergetool.sh git-parse-remote.sh \ git-pull.sh git-rebase.sh \ git-repack.sh git-request-pull.sh git-reset.sh \ - git-sh-setup.sh git-dirlink-checkout.sh \ + git-sh-setup.sh git-dirlink-checkout.sh git-dirlink-merge.sh \ git-tag.sh git-verify-tag.sh \ git-applymbox.sh git-applypatch.sh git-am.sh \ git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \ diff --git a/git-dirlink-merge.sh b/git-dirlink-merge.sh new file mode 100644 index 0000000..e719b1a --- /dev/null +++ b/git-dirlink-merge.sh @@ -0,0 +1,28 @@ +#!/bin/sh -e +# Merge a submodule +# (c) 2006 Martin Waitz + +USAGE="submodule orig-sha1 a-sha1 b-sha1" + +unset GIT_DIR +cd "$1" + +. git-sh-setup + +test $# -eq 4 || usage + +orig="$2" +ours="$3" +theirs="$4" + +base=`git-merge-base "$ours" "$theirs"` + +if test `git-merge-base "$orig" "$base"` != "$orig"; then + die "$1 cannot be merged: other side switched branches" +fi + +if test `git-rev-parse --verify HEAD` != "$ours"; then + die "$1: HEAD != ours" +fi + +exec git-merge $theirs diff --git a/merge-recursive.c b/merge-recursive.c index 8f72b2c..4b67cd0 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -11,6 +11,7 @@ #include "diff.h" #include "diffcore.h" #include "run-command.h" +#include "refs.h" #include "tag.h" #include "unpack-trees.h" #include "path-list.h" @@ -574,6 +575,21 @@ static void update_file_flags(const unsigned char *sha, void *buf; unsigned long size; + if (S_ISDIRLNK(mode)) { + /* defer dirlinks to another process, don't try to */ + /* read the object "sha" here */ + const char *dirlink_checkout[] = { + "dirlink-checkout", path, sha1_to_hex(sha), NULL + }; + struct child_process cmd = { + .argv = dirlink_checkout, + .git_cmd = 1, + }; + + run_command(&cmd); + goto update_index; + } + buf = read_sha1_file(sha, &type, &size); if (!buf) die("cannot read object %s '%s'", sha1_to_hex(sha), path); @@ -1069,6 +1085,26 @@ static struct merge_file_info merge_file(struct diff_filespec *o, free(result_buf.ptr); result.clean = (merge_status == 0); + } else if (S_ISDIRLNK(a->mode)) { + const char *dirlink_merge[] = { + "dirlink-merge", a->path, + sha1_to_hex(o->sha1), + sha1_to_hex(a->sha1), + sha1_to_hex(b->sha1), + NULL + }; + struct child_process cmd = { + .argv = dirlink_merge, + .git_cmd = 1, + }; + /* recurse into the submodule in a different process */ + result.clean = !run_command(&cmd); + if (result.clean) { + /* get the new merged version */ + if (resolve_gitlink_ref(a->path, "HEAD", + result.sha) < 0) + result.clean = 0; + } } else { if (!(S_ISLNK(a->mode) || S_ISLNK(b->mode))) die("cannot merge modes?"); -- 1.5.1.2.247.gaef5a -- Martin Waitz - To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html