* [PATCH v2 0/9] "git apply --3way"
@ 2012-05-10 22:32 Junio C Hamano
2012-05-10 22:32 ` [PATCH v2 1/9] apply: clear_image() clears things a bit more Junio C Hamano
` (8 more replies)
0 siblings, 9 replies; 10+ messages in thread
From: Junio C Hamano @ 2012-05-10 22:32 UTC (permalink / raw)
To: git
Here is its second round. Changes from the previous one are:
- The series has been reordered to have refactoring patches early.
- The option name is corrected to "--3way" and also takes short-and-sweet
"-3" to parallel "am".
- An invocation to ask "--3way" together with "--reject" is rejected.
- The rerere machinery is given a chance to work on the resulting
conflicts.
- The option is now documented.
There are minor things that I still find suboptimal, but as a standalone
new feature, I consider it more or less good to go otherwise.
Here are some things people might be interested in enhancing (hint, hint):
- Buffer error() messages from the first pass (i.e. attempting to apply
to your current version) if the command is running under --3way mode,
and show them if it turns out that we cannot fall back to the three-way
logic (e.g. when the preimage on which the patch was allegedly based is
not available, or the patch fails to apply to such a preimage).
Otherwise discard the error messages from the first pass and show only
the messages from the three-way merge phase.
- Probably support add/add conflicts. Note that this is prevented much
earlier in the codepath and some surgery is needed to allow us to skip
the first pass and go directly to the three-way codepath.
- Similarly, a patch that attempts to delete a path that you no longer
have is rejected early in the codepath. I have a hunch that it is not
worth worrying about, because we do not know what we removed and cannot
tell if what they removed is compatible with our earlier removal.
Junio C Hamano (9):
apply: clear_image() clears things a bit more
apply: refactor read_file_or_gitlink()
apply: split load_preimage() helper function out
apply: accept -3/--3way command line option
apply: fall back on three-way merge
apply: plug the three-way merge logic in
apply: register conflicted stages to the index
apply: allow rerere() upon --3way results
apply: document --3way option
Documentation/git-apply.txt | 10 ++-
builtin/apply.c | 202 +++++++++++++++++++++++++++++++++++++++-----
t/t4108-apply-threeway.sh | 103 ++++++++++++++++++++++
t/t4117-apply-reject.sh | 8 ++
4 files changed, 303 insertions(+), 20 deletions(-)
create mode 100755 t/t4108-apply-threeway.sh
--
1.7.10.1.574.g840b38f
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v2 1/9] apply: clear_image() clears things a bit more
2012-05-10 22:32 [PATCH v2 0/9] "git apply --3way" Junio C Hamano
@ 2012-05-10 22:32 ` Junio C Hamano
2012-05-10 22:32 ` [PATCH v2 2/9] apply: refactor read_file_or_gitlink() Junio C Hamano
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Junio C Hamano @ 2012-05-10 22:32 UTC (permalink / raw)
To: git
The clear_image() function did not clear the line table in the image
structure; this does not matter for the current callers, as the function
is only called from the codepaths that deal with binary patches where the
line table is never populated, and the codepaths that do populate the line
table free it themselves.
But it will start to matter when we introduce a codepath to retry a failed
patch, so make sure it clears and frees everything.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
builtin/apply.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/builtin/apply.c b/builtin/apply.c
index 725712d..99b1608 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -371,8 +371,8 @@ static void prepare_image(struct image *image, char *buf, size_t len,
static void clear_image(struct image *image)
{
free(image->buf);
- image->buf = NULL;
- image->len = 0;
+ free(image->line_allocated);
+ memset(image, 0, sizeof(*image));
}
/* fmt must contain _one_ %s and no other substitution */
--
1.7.10.1.574.g840b38f
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v2 2/9] apply: refactor read_file_or_gitlink()
2012-05-10 22:32 [PATCH v2 0/9] "git apply --3way" Junio C Hamano
2012-05-10 22:32 ` [PATCH v2 1/9] apply: clear_image() clears things a bit more Junio C Hamano
@ 2012-05-10 22:32 ` Junio C Hamano
2012-05-10 22:32 ` [PATCH v2 3/9] apply: split load_preimage() helper function out Junio C Hamano
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Junio C Hamano @ 2012-05-10 22:32 UTC (permalink / raw)
To: git
Reading a blob out of the object store does not have to require that the
caller has a cache entry for it.
Create a read_blob_object() helper function that takes the object name and
mode, and use it to reimplement the original function as a thin wrapper to
it.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
builtin/apply.c | 18 +++++++++++-------
1 file changed, 11 insertions(+), 7 deletions(-)
diff --git a/builtin/apply.c b/builtin/apply.c
index 99b1608..ca330e3 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -2930,20 +2930,17 @@ static int apply_fragments(struct image *img, struct patch *patch)
return 0;
}
-static int read_file_or_gitlink(struct cache_entry *ce, struct strbuf *buf)
+static int read_blob_object(struct strbuf *buf, const unsigned char *sha1, unsigned mode)
{
- if (!ce)
- return 0;
-
- if (S_ISGITLINK(ce->ce_mode)) {
+ if (S_ISGITLINK(mode)) {
strbuf_grow(buf, 100);
- strbuf_addf(buf, "Subproject commit %s\n", sha1_to_hex(ce->sha1));
+ strbuf_addf(buf, "Subproject commit %s\n", sha1_to_hex(sha1));
} else {
enum object_type type;
unsigned long sz;
char *result;
- result = read_sha1_file(ce->sha1, &type, &sz);
+ result = read_sha1_file(sha1, &type, &sz);
if (!result)
return -1;
/* XXX read_sha1_file NUL-terminates */
@@ -2952,6 +2949,13 @@ static int read_file_or_gitlink(struct cache_entry *ce, struct strbuf *buf)
return 0;
}
+static int read_file_or_gitlink(struct cache_entry *ce, struct strbuf *buf)
+{
+ if (!ce)
+ return 0;
+ return read_blob_object(buf, ce->sha1, ce->ce_mode);
+}
+
static struct patch *in_fn_table(const char *name)
{
struct string_list_item *item;
--
1.7.10.1.574.g840b38f
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v2 3/9] apply: split load_preimage() helper function out
2012-05-10 22:32 [PATCH v2 0/9] "git apply --3way" Junio C Hamano
2012-05-10 22:32 ` [PATCH v2 1/9] apply: clear_image() clears things a bit more Junio C Hamano
2012-05-10 22:32 ` [PATCH v2 2/9] apply: refactor read_file_or_gitlink() Junio C Hamano
@ 2012-05-10 22:32 ` Junio C Hamano
2012-05-10 22:32 ` [PATCH v2 4/9] apply: accept -3/--3way command line option Junio C Hamano
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Junio C Hamano @ 2012-05-10 22:32 UTC (permalink / raw)
To: git
The function apply_data() gets a patch for a single path, reads the
preimage in core, and applies the change represented in the patch.
Separate out the first part that reads the preimage into a separate
helper function load_preimage().
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
builtin/apply.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/builtin/apply.c b/builtin/apply.c
index ca330e3..2a31023 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -3028,10 +3028,10 @@ static void prepare_fn_table(struct patch *patch)
}
}
-static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)
+static int load_preimage(struct image *image,
+ struct patch *patch, struct stat *st, struct cache_entry *ce)
{
struct strbuf buf = STRBUF_INIT;
- struct image image;
size_t len;
char *img;
struct patch *tpatch;
@@ -3068,7 +3068,16 @@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *
}
img = strbuf_detach(&buf, &len);
- prepare_image(&image, img, len, !patch->is_binary);
+ prepare_image(image, img, len, !patch->is_binary);
+ return 0;
+}
+
+static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)
+{
+ struct image image;
+
+ if (load_preimage(&image, patch, st, ce) < 0)
+ return -1;
if (apply_fragments(&image, patch) < 0)
return -1; /* note with --reject this succeeds. */
--
1.7.10.1.574.g840b38f
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v2 4/9] apply: accept -3/--3way command line option
2012-05-10 22:32 [PATCH v2 0/9] "git apply --3way" Junio C Hamano
` (2 preceding siblings ...)
2012-05-10 22:32 ` [PATCH v2 3/9] apply: split load_preimage() helper function out Junio C Hamano
@ 2012-05-10 22:32 ` Junio C Hamano
2012-05-10 22:32 ` [PATCH v2 5/9] apply: fall back on three-way merge Junio C Hamano
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Junio C Hamano @ 2012-05-10 22:32 UTC (permalink / raw)
To: git
This is the beginning of teaching the three-way merge fallback logic "git
am -3" uses to the underlying "git apply". It only implements the command
line parsing part, and does not do anything interesting yet, other than
making sure that "--reject" and "--3way" are not given together.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
builtin/apply.c | 19 +++++++++++++++++--
t/t4117-apply-reject.sh | 8 ++++++++
2 files changed, 25 insertions(+), 2 deletions(-)
diff --git a/builtin/apply.c b/builtin/apply.c
index 2a31023..fcd5bdf 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -46,6 +46,7 @@ static int apply_with_reject;
static int apply_verbosely;
static int allow_overlap;
static int no_add;
+static int threeway;
static const char *fake_ancestor;
static int line_termination = '\n';
static unsigned int p_context = UINT_MAX;
@@ -3072,6 +3073,12 @@ static int load_preimage(struct image *image,
return 0;
}
+static int try_threeway_fallback(struct image *image, struct patch *patch,
+ struct stat *st, struct cache_entry *ce)
+{
+ return -1; /* for now */
+}
+
static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)
{
struct image image;
@@ -3079,8 +3086,11 @@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *
if (load_preimage(&image, patch, st, ce) < 0)
return -1;
- if (apply_fragments(&image, patch) < 0)
- return -1; /* note with --reject this succeeds. */
+ if (apply_fragments(&image, patch) < 0) {
+ /* Note: with --reject, the above call succeeds. */
+ if (!threeway || try_threeway_fallback(&image, patch, st, ce) < 0)
+ return -1;
+ }
patch->result = image.buf;
patch->resultsize = image.len;
add_to_fn_table(patch);
@@ -3992,6 +4002,8 @@ int cmd_apply(int argc, const char **argv, const char *prefix_)
"apply a patch without touching the working tree"),
OPT_BOOLEAN(0, "apply", &force_apply,
"also apply the patch (use with --stat/--summary/--check)"),
+ OPT_BOOL('3', "3way", &threeway,
+ "attempt three-way merge if a patch does not apply"),
OPT_FILENAME(0, "build-fake-ancestor", &fake_ancestor,
"build a temporary index based on embedded index information"),
{ OPTION_CALLBACK, 'z', NULL, NULL, NULL,
@@ -4040,6 +4052,9 @@ int cmd_apply(int argc, const char **argv, const char *prefix_)
argc = parse_options(argc, argv, prefix, builtin_apply_options,
apply_usage, 0);
+ if (apply_with_reject && threeway)
+ die("--reject and --3way cannot be used together.");
+
if (apply_with_reject)
apply = apply_verbosely = 1;
if (!force_apply && (diffstat || numstat || summary || check || fake_ancestor))
diff --git a/t/t4117-apply-reject.sh b/t/t4117-apply-reject.sh
index e9ccd16..8e15ecb 100755
--- a/t/t4117-apply-reject.sh
+++ b/t/t4117-apply-reject.sh
@@ -46,6 +46,14 @@ test_expect_success setup '
cat file1 >saved.file1
'
+test_expect_success 'apply --reject is incompatible with --3way' '
+ test_when_finished "cat saved.file1 >file1" &&
+ git diff >patch.0 &&
+ git checkout file1 &&
+ test_must_fail git apply --reject --3way patch.0 &&
+ git diff --exit-code
+'
+
test_expect_success 'apply without --reject should fail' '
if git apply patch.1
--
1.7.10.1.574.g840b38f
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v2 5/9] apply: fall back on three-way merge
2012-05-10 22:32 [PATCH v2 0/9] "git apply --3way" Junio C Hamano
` (3 preceding siblings ...)
2012-05-10 22:32 ` [PATCH v2 4/9] apply: accept -3/--3way command line option Junio C Hamano
@ 2012-05-10 22:32 ` Junio C Hamano
2012-05-10 22:32 ` [PATCH v2 6/9] apply: plug the three-way merge logic in Junio C Hamano
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Junio C Hamano @ 2012-05-10 22:32 UTC (permalink / raw)
To: git
Grab the preimage blob the patch claims to be based on out of the object
store, apply the patch, and then call three-way-merge function. This step
still does not plug the actual three-way merge logic yet, but we are
getting there.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
builtin/apply.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 42 insertions(+), 1 deletion(-)
diff --git a/builtin/apply.c b/builtin/apply.c
index fcd5bdf..1fe178f 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -3073,10 +3073,51 @@ static int load_preimage(struct image *image,
return 0;
}
+static int three_way_merge(struct image *image,
+ char *path,
+ unsigned char *base,
+ unsigned char *ours,
+ unsigned char *theirs)
+{
+ return -1; /* for now */
+}
+
static int try_threeway_fallback(struct image *image, struct patch *patch,
struct stat *st, struct cache_entry *ce)
{
- return -1; /* for now */
+ unsigned char pre_sha1[20], post_sha1[20], our_sha1[20];
+ struct strbuf buf = STRBUF_INIT;
+ size_t len;
+ char *img;
+ struct image tmp_image;
+
+ /* No point falling back to 3-way merge in these cases */
+ if (patch->is_new || patch->is_delete ||
+ S_ISGITLINK(patch->old_mode) || S_ISGITLINK(patch->new_mode))
+ return -1;
+
+ /* Preimage the patch was prepared for */
+ if (get_sha1(patch->old_sha1_prefix, pre_sha1) ||
+ read_blob_object(&buf, pre_sha1, patch->old_mode))
+ return error("repository lacks the necessary blob to fall back on 3-way merge.");
+ img = strbuf_detach(&buf, &len);
+ prepare_image(&tmp_image, img, len, 1);
+ /* Apply the patch to get the post image */
+ if (apply_fragments(&tmp_image, patch) < 0) {
+ clear_image(&tmp_image);
+ return -1;
+ }
+ hash_sha1_file(tmp_image.buf, tmp_image.len, blob_type, post_sha1);
+ clear_image(&tmp_image);
+
+ /* pre_sha1[] is common, post_sha1[] is theirs */
+ load_preimage(&tmp_image, patch, st, ce);
+ hash_sha1_file(tmp_image.buf, tmp_image.len, blob_type, our_sha1);
+ clear_image(&tmp_image);
+
+ /* in-core three-way merge between post and our using pre as base */
+ return three_way_merge(image,
+ patch->new_name, pre_sha1, our_sha1, post_sha1);
}
static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)
--
1.7.10.1.574.g840b38f
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v2 6/9] apply: plug the three-way merge logic in
2012-05-10 22:32 [PATCH v2 0/9] "git apply --3way" Junio C Hamano
` (4 preceding siblings ...)
2012-05-10 22:32 ` [PATCH v2 5/9] apply: fall back on three-way merge Junio C Hamano
@ 2012-05-10 22:32 ` Junio C Hamano
2012-05-10 22:32 ` [PATCH v2 7/9] apply: register conflicted stages to the index Junio C Hamano
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Junio C Hamano @ 2012-05-10 22:32 UTC (permalink / raw)
To: git
When a patch does not apply to what we have, but we know the preimage the
patch was made against, we apply the patch to the preimage to compute what
the patch author wanted the result to look like, and attempt a three-way
merge between the result and our version, using the intended preimage as
the base version.
When we are applying the patch using the index, we would additionally need
to add the object names of these three blobs involved in the merge, which
is not yet done in this step, but we add a field to "struct patch" so that
later write-out step can use it.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
builtin/apply.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 53 insertions(+), 6 deletions(-)
diff --git a/builtin/apply.c b/builtin/apply.c
index 1fe178f..ac53ecf 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -16,6 +16,8 @@
#include "dir.h"
#include "diff.h"
#include "parse-options.h"
+#include "xdiff-interface.h"
+#include "ll-merge.h"
/*
* --check turns on checking that the working tree matches the
@@ -194,12 +196,16 @@ struct patch {
unsigned int is_copy:1;
unsigned int is_rename:1;
unsigned int recount:1;
+ unsigned int conflicted_threeway:1;
struct fragment *fragments;
char *result;
size_t resultsize;
char old_sha1_prefix[41];
char new_sha1_prefix[41];
struct patch *next;
+
+ /* three-way fallback result */
+ unsigned char threeway_stage[3][20];
};
static void free_fragment_list(struct fragment *list)
@@ -3075,11 +3081,33 @@ static int load_preimage(struct image *image,
static int three_way_merge(struct image *image,
char *path,
- unsigned char *base,
- unsigned char *ours,
- unsigned char *theirs)
+ const unsigned char *base,
+ const unsigned char *ours,
+ const unsigned char *theirs)
{
- return -1; /* for now */
+ mmfile_t base_file, our_file, their_file;
+ mmbuffer_t result = { 0 };
+ int status;
+
+ read_mmblob(&base_file, base);
+ read_mmblob(&our_file, ours);
+ read_mmblob(&their_file, theirs);
+ status = ll_merge(&result, path,
+ &base_file, "base",
+ &our_file, "ours",
+ &their_file, "theirs", NULL);
+ free(base_file.ptr);
+ free(our_file.ptr);
+ free(their_file.ptr);
+ if (status < 0 || !result.ptr) {
+ free(result.ptr);
+ return -1;
+ }
+ clear_image(image);
+ image->buf = result.ptr;
+ image->len = result.size;
+
+ return status;
}
static int try_threeway_fallback(struct image *image, struct patch *patch,
@@ -3088,6 +3116,7 @@ static int try_threeway_fallback(struct image *image, struct patch *patch,
unsigned char pre_sha1[20], post_sha1[20], our_sha1[20];
struct strbuf buf = STRBUF_INIT;
size_t len;
+ int status;
char *img;
struct image tmp_image;
@@ -3100,6 +3129,9 @@ static int try_threeway_fallback(struct image *image, struct patch *patch,
if (get_sha1(patch->old_sha1_prefix, pre_sha1) ||
read_blob_object(&buf, pre_sha1, patch->old_mode))
return error("repository lacks the necessary blob to fall back on 3-way merge.");
+
+ fprintf(stderr, "Falling back to three-way merge...\n");
+
img = strbuf_detach(&buf, &len);
prepare_image(&tmp_image, img, len, 1);
/* Apply the patch to get the post image */
@@ -3116,8 +3148,23 @@ static int try_threeway_fallback(struct image *image, struct patch *patch,
clear_image(&tmp_image);
/* in-core three-way merge between post and our using pre as base */
- return three_way_merge(image,
- patch->new_name, pre_sha1, our_sha1, post_sha1);
+ status = three_way_merge(image, patch->new_name,
+ pre_sha1, our_sha1, post_sha1);
+ if (status < 0) {
+ fprintf(stderr, "Failed to fall back on three-way merge...\n");
+ return status;
+ }
+
+ if (status) {
+ patch->conflicted_threeway = 1;
+ hashcpy(patch->threeway_stage[0], pre_sha1);
+ hashcpy(patch->threeway_stage[1], our_sha1);
+ hashcpy(patch->threeway_stage[2], post_sha1);
+ fprintf(stderr, "Applied patch to '%s' with conflicts.\n", patch->new_name);
+ } else {
+ fprintf(stderr, "Applied patch to '%s' cleanly.\n", patch->new_name);
+ }
+ return 0;
}
static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)
--
1.7.10.1.574.g840b38f
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v2 7/9] apply: register conflicted stages to the index
2012-05-10 22:32 [PATCH v2 0/9] "git apply --3way" Junio C Hamano
` (5 preceding siblings ...)
2012-05-10 22:32 ` [PATCH v2 6/9] apply: plug the three-way merge logic in Junio C Hamano
@ 2012-05-10 22:32 ` Junio C Hamano
2012-05-10 22:32 ` [PATCH v2 8/9] apply: allow rerere() upon --3way results Junio C Hamano
2012-05-10 22:32 ` [PATCH v2 9/9] apply: document --3way option Junio C Hamano
8 siblings, 0 replies; 10+ messages in thread
From: Junio C Hamano @ 2012-05-10 22:32 UTC (permalink / raw)
To: git
Now we have all the necessary logic to fall back on three-way merge when
the patch does not cleanly apply, insert the conflicted entries to the
index as appropriate. This obviously triggers only when the "--index"
option is used.
When we fall back to three-way merge and some of the merges fail, just
like the case where the "--reject" option was specified and we had to
write some "*.rej" files out for unapplicable patches, exit the command
with non-zero status without showing the diffstat and summary. Otherwise
they would make the list of problematic paths scroll off the display.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
builtin/apply.c | 55 ++++++++++++++++++++++++++++++---
t/t4108-apply-threeway.sh | 78 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 128 insertions(+), 5 deletions(-)
create mode 100755 t/t4108-apply-threeway.sh
diff --git a/builtin/apply.c b/builtin/apply.c
index ac53ecf..9f376b5 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -3708,6 +3708,27 @@ static void create_one_file(char *path, unsigned mode, const char *buf, unsigned
die_errno(_("unable to write file '%s' mode %o"), path, mode);
}
+static void add_conflicted_stages_file(struct patch *patch)
+{
+ int stage, namelen;
+ unsigned ce_size, mode;
+
+ if (!update_index)
+ return;
+ namelen = strlen(patch->new_name);
+ ce_size = cache_entry_size(namelen);
+ mode = patch->new_mode ? patch->new_mode : (S_IFREG | 0644);
+ for (stage = 1; stage < 4; stage++) {
+ struct cache_entry *ce = xcalloc(1, ce_size);
+ memcpy(ce->name, patch->new_name, namelen);
+ ce->ce_mode = create_ce_mode(mode);
+ ce->ce_flags = create_ce_flags(namelen, stage);
+ hashcpy(ce->sha1, patch->threeway_stage[stage - 1]);
+ if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD) < 0)
+ die(_("unable to add cache entry for %s"), patch->new_name);
+ }
+}
+
static void create_file(struct patch *patch)
{
char *path = patch->new_name;
@@ -3718,7 +3739,11 @@ static void create_file(struct patch *patch)
if (!mode)
mode = S_IFREG | 0644;
create_one_file(path, mode, buf, size);
- add_index_file(path, mode, buf, size);
+
+ if (patch->conflicted_threeway)
+ add_conflicted_stages_file(patch);
+ else
+ add_index_file(path, mode, buf, size);
}
/* phase zero is to remove, phase one is to create */
@@ -3820,6 +3845,7 @@ static int write_out_results(struct patch *list)
int phase;
int errs = 0;
struct patch *l;
+ struct string_list cpath = STRING_LIST_INIT_DUP;
for (phase = 0; phase < 2; phase++) {
l = list;
@@ -3828,12 +3854,28 @@ static int write_out_results(struct patch *list)
errs = 1;
else {
write_out_one_result(l, phase);
- if (phase == 1 && write_out_one_reject(l))
- errs = 1;
+ if (phase == 1) {
+ if (write_out_one_reject(l))
+ errs = 1;
+ if (l->conflicted_threeway) {
+ string_list_append(&cpath, l->new_name);
+ errs = 1;
+ }
+ }
}
l = l->next;
}
}
+
+ if (cpath.nr) {
+ struct string_list_item *item;
+
+ sort_string_list(&cpath);
+ for_each_string_list_item(item, &cpath)
+ fprintf(stderr, "U %s\n", item->string);
+ string_list_clear(&cpath, 0);
+ }
+
return errs;
}
@@ -3956,8 +3998,11 @@ static int apply_patch(int fd, const char *filename, int options)
!apply_with_reject)
exit(1);
- if (apply && write_out_results(list))
- exit(1);
+ if (apply && write_out_results(list)) {
+ if (apply_with_reject)
+ exit(1);
+ return 1;
+ }
if (fake_ancestor)
build_fake_ancestor(list, fake_ancestor);
diff --git a/t/t4108-apply-threeway.sh b/t/t4108-apply-threeway.sh
new file mode 100755
index 0000000..475dfb5
--- /dev/null
+++ b/t/t4108-apply-threeway.sh
@@ -0,0 +1,78 @@
+#!/bin/sh
+
+test_description='git apply --3way'
+
+. ./test-lib.sh
+
+create_file () {
+ for i
+ do
+ echo "$i"
+ done
+}
+
+sanitize_conflicted_diff () {
+ sed -e '
+ /^index /d
+ s/^\(+[<>][<>][<>][<>]*\) .*/\1/
+ '
+}
+
+test_expect_success setup '
+ test_tick &&
+ create_file >one 1 2 3 4 5 6 7 &&
+ cat one >two &&
+ git add one two &&
+ git commit -m initial &&
+
+ git branch side &&
+
+ test_tick &&
+ create_file >one 1 two 3 4 5 six 7 &&
+ create_file >two 1 two 3 4 5 6 7 &&
+ git commit -a -m master &&
+
+ git checkout side &&
+ create_file >one 1 2 3 4 five 6 7 &&
+ create_file >two 1 2 3 4 five 6 7 &&
+ git commit -a -m side &&
+
+ git checkout master
+'
+
+test_expect_success 'apply without --3way' '
+ git diff side^ side >P.diff &&
+
+ # should fail to apply
+ git reset --hard &&
+ git checkout master^0 &&
+ test_must_fail git apply --index P.diff &&
+ # should leave things intact
+ git diff-files --exit-code &&
+ git diff-index --exit-code --cached HEAD
+'
+
+test_expect_success 'apply with --3way' '
+ # Merging side should be similar to applying this patch
+ git diff ...side >P.diff &&
+
+ # The corresponding conflicted merge
+ git reset --hard &&
+ git checkout master^0 &&
+ test_must_fail git merge --no-commit side &&
+ git ls-files -s >expect.ls &&
+ git diff HEAD | sanitize_conflicted_diff >expect.diff &&
+
+ # should fail to apply
+ git reset --hard &&
+ git checkout master^0 &&
+ test_must_fail git apply --index --3way P.diff &&
+ git ls-files -s >actual.ls &&
+ git diff HEAD | sanitize_conflicted_diff >actual.diff &&
+
+ # The result should resemble the corresponding merge
+ test_cmp expect.ls actual.ls &&
+ test_cmp expect.diff actual.diff
+'
+
+test_done
--
1.7.10.1.574.g840b38f
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v2 8/9] apply: allow rerere() upon --3way results
2012-05-10 22:32 [PATCH v2 0/9] "git apply --3way" Junio C Hamano
` (6 preceding siblings ...)
2012-05-10 22:32 ` [PATCH v2 7/9] apply: register conflicted stages to the index Junio C Hamano
@ 2012-05-10 22:32 ` Junio C Hamano
2012-05-10 22:32 ` [PATCH v2 9/9] apply: document --3way option Junio C Hamano
8 siblings, 0 replies; 10+ messages in thread
From: Junio C Hamano @ 2012-05-10 22:32 UTC (permalink / raw)
To: git
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
builtin/apply.c | 3 +++
t/t4108-apply-threeway.sh | 25 +++++++++++++++++++++++++
2 files changed, 28 insertions(+)
diff --git a/builtin/apply.c b/builtin/apply.c
index 9f376b5..502c1bf1 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -18,6 +18,7 @@
#include "parse-options.h"
#include "xdiff-interface.h"
#include "ll-merge.h"
+#include "rerere.h"
/*
* --check turns on checking that the working tree matches the
@@ -3874,6 +3875,8 @@ static int write_out_results(struct patch *list)
for_each_string_list_item(item, &cpath)
fprintf(stderr, "U %s\n", item->string);
string_list_clear(&cpath, 0);
+
+ rerere(0);
}
return errs;
diff --git a/t/t4108-apply-threeway.sh b/t/t4108-apply-threeway.sh
index 475dfb5..e6d4da6 100755
--- a/t/t4108-apply-threeway.sh
+++ b/t/t4108-apply-threeway.sh
@@ -75,4 +75,29 @@ test_expect_success 'apply with --3way' '
test_cmp expect.diff actual.diff
'
+test_expect_success 'apply with --3way with rerere enabled' '
+ git config rerere.enabled true &&
+
+ # Merging side should be similar to applying this patch
+ git diff ...side >P.diff &&
+
+ # The corresponding conflicted merge
+ git reset --hard &&
+ git checkout master^0 &&
+ test_must_fail git merge --no-commit side &&
+
+ # Manually resolve and record the resolution
+ create_file 1 two 3 4 five six 7 >one &&
+ git rerere &&
+ cat one >expect &&
+
+ # should fail to apply
+ git reset --hard &&
+ git checkout master^0 &&
+ test_must_fail git apply --index --3way P.diff &&
+
+ # but rerere should have replayed the recorded resolution
+ test_cmp expect one
+'
+
test_done
--
1.7.10.1.574.g840b38f
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v2 9/9] apply: document --3way option
2012-05-10 22:32 [PATCH v2 0/9] "git apply --3way" Junio C Hamano
` (7 preceding siblings ...)
2012-05-10 22:32 ` [PATCH v2 8/9] apply: allow rerere() upon --3way results Junio C Hamano
@ 2012-05-10 22:32 ` Junio C Hamano
8 siblings, 0 replies; 10+ messages in thread
From: Junio C Hamano @ 2012-05-10 22:32 UTC (permalink / raw)
To: git
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
Documentation/git-apply.txt | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/Documentation/git-apply.txt b/Documentation/git-apply.txt
index afd2c9a..354ff95 100644
--- a/Documentation/git-apply.txt
+++ b/Documentation/git-apply.txt
@@ -9,7 +9,7 @@ git-apply - Apply a patch to files and/or to the index
SYNOPSIS
--------
[verse]
-'git apply' [--stat] [--numstat] [--summary] [--check] [--index]
+'git apply' [--stat] [--numstat] [--summary] [--check] [--index] [--3way]
[--apply] [--no-add] [--build-fake-ancestor=<file>] [-R | --reverse]
[--allow-binary-replacement | --binary] [--reject] [-z]
[-p<n>] [-C<n>] [--inaccurate-eof] [--recount] [--cached]
@@ -72,6 +72,14 @@ OPTIONS
cached data, apply the patch, and store the result in the index
without using the working tree. This implies `--index`.
+-3::
+--3way::
+ When the patch does not apply cleanly, fall back on 3-way merge if
+ the patch records the identity of blobs it is supposed to apply to,
+ and we have those blobs available locally, possibly leaving the
+ conflict markers in the files in the working tree for the user to
+ resolve.
+
--build-fake-ancestor=<file>::
Newer 'git diff' output has embedded 'index information'
for each blob to help identify the original version that
--
1.7.10.1.574.g840b38f
^ permalink raw reply related [flat|nested] 10+ messages in thread
end of thread, other threads:[~2012-05-10 22:33 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-05-10 22:32 [PATCH v2 0/9] "git apply --3way" Junio C Hamano
2012-05-10 22:32 ` [PATCH v2 1/9] apply: clear_image() clears things a bit more Junio C Hamano
2012-05-10 22:32 ` [PATCH v2 2/9] apply: refactor read_file_or_gitlink() Junio C Hamano
2012-05-10 22:32 ` [PATCH v2 3/9] apply: split load_preimage() helper function out Junio C Hamano
2012-05-10 22:32 ` [PATCH v2 4/9] apply: accept -3/--3way command line option Junio C Hamano
2012-05-10 22:32 ` [PATCH v2 5/9] apply: fall back on three-way merge Junio C Hamano
2012-05-10 22:32 ` [PATCH v2 6/9] apply: plug the three-way merge logic in Junio C Hamano
2012-05-10 22:32 ` [PATCH v2 7/9] apply: register conflicted stages to the index Junio C Hamano
2012-05-10 22:32 ` [PATCH v2 8/9] apply: allow rerere() upon --3way results Junio C Hamano
2012-05-10 22:32 ` [PATCH v2 9/9] apply: document --3way option Junio C Hamano
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).