2 * merge.c: merging changes into a working file
4 * ====================================================================
5 * Copyright (c) 2000-2006 CollabNet. All rights reserved.
7 * This software is licensed as described in the file COPYING, which
8 * you should have received as part of this distribution. The terms
9 * are also available at http://subversion.tigris.org/license-1.html.
10 * If newer versions of this license are posted there, you may use a
11 * newer version instead, at your option.
13 * This software consists of voluntary contributions made by many
14 * individuals. For exact contribution history, see the revision
15 * history and logs, available at http://subversion.tigris.org/.
16 * ====================================================================
27 #include "translate.h"
28 #include "questions.h"
31 #include "svn_private_config.h"
34 /* Return a pointer to the svn_prop_t structure from PROP_DIFF
35 belonging to PROP_NAME, if any. NULL otherwise.*/
36 static const svn_prop_t
*
37 get_prop(const apr_array_header_t
*prop_diff
,
38 const char *prop_name
)
43 for (i
= 0; i
< prop_diff
->nelts
; i
++)
45 const svn_prop_t
*elt
= &APR_ARRAY_IDX(prop_diff
, i
, svn_prop_t
);
46 if (strcmp(elt
->name
,prop_name
) == 0)
55 /* Detranslate a working copy file MERGE_TARGET to achieve the effect of:
62 in 1 pass to get a file which can be compared with the left and right
63 files which were created with the 'new props' above.
65 Property changes make this a little complex though. Changes in
72 may change the way a file is translated.
74 Effect for svn:mime-type:
76 The value for svn:mime-type affects the translation wrt keywords
77 and eol-style settings.
79 I) both old and new mime-types are texty
80 -> just do the translation dance (as lined out below)
82 II) the old one is texty, the new one is binary
83 -> detranslate with the old eol-style and keywords
84 (the new re+detranslation is a no-op)
86 III) the old one is binary, the new one texty
87 -> detranslate with the new eol-style
88 (the old detranslation is a no-op)
90 IV) the old and new ones are binary
91 -> don't detranslate, just make a straight copy
94 Effect for svn:eol-style
96 I) On add or change use the new value
98 II) otherwise: use the old value (absent means 'no translation')
101 Effect for svn:keywords
103 Always use old settings (re+detranslation are no-op)
106 Effect for svn:special
108 Always use the old settings (same reasons as for svn:keywords)
112 detranslate_wc_file(const char **detranslated_file
,
113 const char *merge_target
,
114 svn_wc_adm_access_t
*adm_access
,
115 svn_boolean_t force_copy
,
116 const apr_array_header_t
*prop_diff
,
119 svn_boolean_t is_binary
;
120 const svn_prop_t
*prop
;
121 svn_subst_eol_style_t style
;
123 apr_hash_t
*keywords
;
124 svn_boolean_t special
;
126 /* Decide if the merge target currently is a text or binary file. */
127 SVN_ERR(svn_wc_has_binary_prop(&is_binary
,
128 merge_target
, adm_access
, pool
));
131 /* See if we need to do a straight copy:
132 - old and new mime-types are binary, or
133 - old mime-type is binary and no new mime-type specified */
135 && (((prop
= get_prop(prop_diff
, SVN_PROP_MIME_TYPE
))
136 && prop
->value
&& svn_mime_type_is_binary(prop
->value
->data
))
139 /* this is case IV above */
143 style
= svn_subst_eol_style_none
;
145 else if ((!is_binary
)
146 && (prop
= get_prop(prop_diff
, SVN_PROP_MIME_TYPE
))
147 && prop
->value
&& svn_mime_type_is_binary(prop
->value
->data
))
149 /* Old props indicate texty, new props indicate binary:
150 detranslate keywords and old eol-style */
151 SVN_ERR(svn_wc__get_keywords(&keywords
, merge_target
,
152 adm_access
, NULL
, pool
));
153 SVN_ERR(svn_wc__get_special(&special
, merge_target
, adm_access
, pool
));
157 /* New props indicate texty, regardless of old props */
159 /* In case the file used to be special, detranslate specially */
160 SVN_ERR(svn_wc__get_special(&special
, merge_target
, adm_access
, pool
));
166 style
= svn_subst_eol_style_none
;
170 /* In case a new eol style was set, use that for detranslation */
171 if ((prop
= get_prop(prop_diff
, SVN_PROP_EOL_STYLE
)) && prop
->value
)
173 /* Value added or changed */
174 svn_subst_eol_style_from_value(&style
, &eol
, prop
->value
->data
);
177 SVN_ERR(svn_wc__get_eol_style(&style
, &eol
, merge_target
,
182 style
= svn_subst_eol_style_none
;
185 /* In case there were keywords, detranslate with keywords
186 (iff we were texty) */
188 SVN_ERR(svn_wc__get_keywords(&keywords
, merge_target
,
189 adm_access
, NULL
, pool
));
195 /* Now, detranslate with the settings we created above */
197 if (force_copy
|| keywords
|| eol
|| special
)
199 const char *detranslated
;
200 /* Force a copy into the temporary wc area to avoid having
201 temporary files created below to appear in the actual wc. */
203 SVN_ERR(svn_wc_create_tmp_file2
204 (NULL
, &detranslated
,
205 svn_wc_adm_access_path(adm_access
),
206 svn_io_file_del_none
, pool
));
208 SVN_ERR(svn_subst_translate_to_normal_form(merge_target
,
211 eol
, eol
? FALSE
: TRUE
,
215 *detranslated_file
= detranslated
;
218 *detranslated_file
= merge_target
;
223 /* Updates (by copying and translating) the eol style in
224 OLD_TARGET returning the filename containing the
225 correct eol style in NEW_TARGET, if an eol style
226 change is contained in PROP_DIFF */
228 maybe_update_target_eols(const char **new_target
,
229 const char *old_target
,
230 svn_wc_adm_access_t
*adm_access
,
231 const apr_array_header_t
*prop_diff
,
234 const svn_prop_t
*prop
= get_prop(prop_diff
, SVN_PROP_EOL_STYLE
);
236 if (prop
&& prop
->value
)
241 svn_subst_eol_style_from_value(NULL
, &eol
, prop
->value
->data
);
242 SVN_ERR(svn_wc_create_tmp_file2(NULL
, &tmp_new
,
243 svn_wc_adm_access_path(adm_access
),
244 svn_io_file_del_none
,
246 SVN_ERR(svn_subst_copy_and_translate3(old_target
,
251 *new_target
= tmp_new
;
254 *new_target
= old_target
;
261 svn_wc__merge_internal(svn_stringbuf_t
**log_accum
,
262 enum svn_wc_merge_outcome_t
*merge_outcome
,
265 const char *merge_target
,
266 const char *copyfrom_text
,
267 svn_wc_adm_access_t
*adm_access
,
268 const char *left_label
,
269 const char *right_label
,
270 const char *target_label
,
271 svn_boolean_t dry_run
,
272 const char *diff3_cmd
,
273 const apr_array_header_t
*merge_options
,
274 const apr_array_header_t
*prop_diff
,
275 svn_wc_conflict_resolver_func_t conflict_func
,
276 void *conflict_baton
,
279 const char *tmp_target
, *result_target
, *working_text
;
280 const char *adm_path
= svn_wc_adm_access_path(adm_access
);
281 apr_file_t
*result_f
;
282 svn_boolean_t is_binary
= FALSE
;
283 const svn_wc_entry_t
*entry
;
284 svn_boolean_t contains_conflicts
;
285 const svn_prop_t
*mimeprop
;
287 /* Sanity check: the merge target must be under revision control (unless
288 this is an add-with-history). */
289 SVN_ERR(svn_wc_entry(&entry
, merge_target
, adm_access
, FALSE
, pool
));
290 if (! entry
&& ! copyfrom_text
)
292 *merge_outcome
= svn_wc_merge_no_merge
;
296 /* Decide if the merge target is a text or binary file. */
297 if ((mimeprop
= get_prop(prop_diff
, SVN_PROP_MIME_TYPE
))
299 is_binary
= svn_mime_type_is_binary(mimeprop
->value
->data
);
300 else if (! copyfrom_text
)
301 SVN_ERR(svn_wc_has_binary_prop(&is_binary
, merge_target
, adm_access
, pool
));
303 working_text
= copyfrom_text
? copyfrom_text
: merge_target
;
304 SVN_ERR(detranslate_wc_file(&tmp_target
, working_text
, adm_access
,
305 (! is_binary
) && diff3_cmd
!= NULL
,
308 /* We cannot depend on the left file to contain the same eols as the
309 right file. If the merge target has mods, this will mark the entire
310 file as conflicted, so we need to compensate. */
311 SVN_ERR(maybe_update_target_eols(&left
, left
, adm_access
, prop_diff
, pool
));
313 if (! is_binary
) /* this is a text file */
315 /* Open a second temporary file for writing; this is where diff3
316 will write the merged results. */
317 SVN_ERR(svn_wc_create_tmp_file2(&result_f
, &result_target
,
318 adm_path
, svn_io_file_del_none
,
321 /* Run an external merge if requested. */
326 SVN_ERR(svn_io_run_diff3_2(&exit_code
, ".",
327 tmp_target
, left
, right
,
328 target_label
, left_label
, right_label
,
330 merge_options
, pool
));
332 contains_conflicts
= exit_code
== 1;
337 const char *target_marker
;
338 const char *left_marker
;
339 const char *right_marker
;
340 svn_stream_t
*ostream
;
341 svn_diff_file_options_t
*options
;
343 ostream
= svn_stream_from_aprfile(result_f
, pool
);
344 options
= svn_diff_file_options_create(pool
);
347 SVN_ERR(svn_diff_file_options_parse(options
, merge_options
, pool
));
349 SVN_ERR(svn_diff_file_diff3_2(&diff
,
350 left
, tmp_target
, right
,
353 /* Labels fall back to sensible defaults if not specified. */
355 target_marker
= apr_psprintf(pool
, "<<<<<<< %s", target_label
);
357 target_marker
= "<<<<<<< .working";
360 left_marker
= apr_psprintf(pool
, "||||||| %s", left_label
);
362 left_marker
= "||||||| .old";
365 right_marker
= apr_psprintf(pool
, ">>>>>>> %s", right_label
);
367 right_marker
= ">>>>>>> .new";
369 SVN_ERR(svn_diff_file_output_merge(ostream
, diff
,
370 left
, tmp_target
, right
,
374 "=======", /* seperator */
375 FALSE
, /* display original */
376 FALSE
, /* resolve conflicts */
378 SVN_ERR(svn_stream_close(ostream
));
380 contains_conflicts
= svn_diff_contains_conflicts(diff
);
383 /* Close the output file */
384 SVN_ERR(svn_io_file_close(result_f
, pool
));
386 if (contains_conflicts
&& ! dry_run
) /* got a conflict */
388 const char *left_copy
, *right_copy
, *target_copy
;
389 const char *tmp_left
, *tmp_right
, *tmp_target_copy
;
390 const char *parentt
, *target_base
;
391 svn_wc_adm_access_t
*parent_access
;
392 svn_wc_entry_t tmp_entry
;
394 /* Give the conflict resolution callback a chance to clean
395 up the conflict before we mark the file 'conflicted' */
398 svn_wc_conflict_result_t
*result
= NULL
;
399 svn_wc_conflict_description_t cdesc
;
401 cdesc
.path
= merge_target
;
402 cdesc
.node_kind
= svn_node_file
;
403 cdesc
.kind
= svn_wc_conflict_kind_text
;
404 cdesc
.is_binary
= FALSE
;
405 cdesc
.mime_type
= (mimeprop
&& mimeprop
->value
)
406 ? mimeprop
->value
->data
: NULL
;
407 cdesc
.access
= adm_access
;
408 cdesc
.action
= svn_wc_conflict_action_edit
;
409 cdesc
.reason
= svn_wc_conflict_reason_edited
;
410 cdesc
.base_file
= left
;
411 cdesc
.their_file
= right
;
412 cdesc
.my_file
= tmp_target
;
413 cdesc
.merged_file
= result_target
;
414 cdesc
.property_name
= NULL
;
416 SVN_ERR(conflict_func(&result
, &cdesc
, conflict_baton
, pool
));
418 return svn_error_create(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE
,
419 NULL
, _("Conflict callback violated API:"
420 " returned no results"));
422 switch (result
->choice
)
424 /* If the callback wants to use one of the fulltexts
425 to resolve the conflict, so be it.*/
426 case svn_wc_conflict_choose_base
:
428 SVN_ERR(svn_wc__loggy_copy
429 (log_accum
, NULL
, adm_access
,
430 svn_wc__copy_translate
,
433 *merge_outcome
= svn_wc_merge_merged
;
434 contains_conflicts
= FALSE
;
437 case svn_wc_conflict_choose_theirs_full
:
439 SVN_ERR(svn_wc__loggy_copy
440 (log_accum
, NULL
, adm_access
,
441 svn_wc__copy_translate
,
444 *merge_outcome
= svn_wc_merge_merged
;
445 contains_conflicts
= FALSE
;
448 case svn_wc_conflict_choose_mine_full
:
450 /* Do nothing to merge_target, let it live untouched! */
451 *merge_outcome
= svn_wc_merge_merged
;
452 contains_conflicts
= FALSE
;
456 /* For the case of 3-way file merging, we don't
457 really distinguish between these return values;
458 if the callback claims to have "generally
459 resolved" the situation, we still interpret
460 that as "OK, we'll assume the merged version is
462 case svn_wc_conflict_choose_merged
:
464 SVN_ERR(svn_wc__loggy_copy
465 (log_accum
, NULL
, adm_access
,
466 svn_wc__copy_translate
,
467 /* Look for callback's own merged-file first: */
468 result
->merged_file
?
469 result
->merged_file
: result_target
,
472 *merge_outcome
= svn_wc_merge_merged
;
473 contains_conflicts
= FALSE
;
476 case svn_wc_conflict_choose_postpone
:
479 /* Assume conflict remains, fall through to code below. */
484 /* Preserve the three pre-merge files, and modify the
485 entry (mark as conflicted, track the preserved files). */
489 SVN_ERR(svn_io_open_unique_file2(NULL
,
493 svn_io_file_del_none
,
496 /* Have I mentioned how much I miss Lisp? */
498 SVN_ERR(svn_io_open_unique_file2(NULL
,
502 svn_io_file_del_none
,
505 /* Why, how much more pleasant to be forced to unroll my loops.
506 If I'd been writing in Lisp, I might have mapped an inline
507 lambda form over a list, or something equally disgusting.
508 Thank goodness C was here to protect me! */
510 SVN_ERR(svn_io_open_unique_file2(NULL
,
514 svn_io_file_del_none
,
517 /* We preserve all the files with keywords expanded and line
518 endings in local (working) form. */
520 svn_path_split(target_copy
, &parentt
, &target_base
, pool
);
521 SVN_ERR(svn_wc_adm_retrieve(&parent_access
, adm_access
, parentt
,
524 /* Log files require their paths to be in the subtree
525 relative to the adm_access path they are executed in.
527 Make our LEFT and RIGHT files 'local' if they aren't... */
528 if (! svn_path_is_child(adm_path
, left
, pool
))
530 SVN_ERR(svn_wc_create_tmp_file2
532 adm_path
, svn_io_file_del_none
, pool
));
533 SVN_ERR(svn_io_copy_file(left
, tmp_left
, TRUE
, pool
));
538 if (! svn_path_is_child(adm_path
, right
, pool
))
540 SVN_ERR(svn_wc_create_tmp_file2
542 adm_path
, svn_io_file_del_none
, pool
));
543 SVN_ERR(svn_io_copy_file(right
, tmp_right
, TRUE
, pool
));
548 /* NOTE: Callers must ensure that the svn:eol-style and
549 svn:keywords property values are correct in the currently
550 installed props. With 'svn merge', it's no big deal. But
551 when 'svn up' calls this routine, it needs to make sure that
552 this routine is using the newest property values that may
553 have been received *during* the update. Since this routine
554 will be run from within a log-command, merge_file()
555 needs to make sure that a previous log-command to 'install
556 latest props' has already executed first. Ben and I just
557 checked, and that is indeed the order in which the log items
558 are written, so everything should be fine. Really. */
560 /* Create LEFT and RIGHT backup files, in expanded form.
561 We use merge_target's current properties to do the translation. */
562 /* Derive the basenames of the 3 backup files. */
563 SVN_ERR(svn_wc__loggy_translated_file(log_accum
,
566 merge_target
, pool
));
567 SVN_ERR(svn_wc__loggy_translated_file(log_accum
,
569 right_copy
, tmp_right
,
570 merge_target
, pool
));
572 /* Back up MERGE_TARGET through detranslation/retranslation:
573 the new translation properties may not match the current ones */
574 SVN_ERR(svn_wc_translated_file2(&tmp_target_copy
,
578 SVN_WC_TRANSLATE_TO_NF
579 | SVN_WC_TRANSLATE_NO_OUTPUT_CLEANUP
,
581 SVN_ERR(svn_wc__loggy_translated_file
582 (log_accum
, adm_access
,
583 target_copy
, tmp_target_copy
, merge_target
, pool
));
585 tmp_entry
.conflict_old
586 = svn_path_is_child(adm_path
, left_copy
, pool
);
587 tmp_entry
.conflict_new
588 = svn_path_is_child(adm_path
, right_copy
, pool
);
589 tmp_entry
.conflict_wrk
= target_base
;
591 /* Mark merge_target's entry as "Conflicted", and start tracking
592 the backup files in the entry as well. */
593 SVN_ERR(svn_wc__loggy_entry_modify
594 (log_accum
, adm_access
,
595 merge_target
, &tmp_entry
,
596 SVN_WC__ENTRY_MODIFY_CONFLICT_OLD
597 | SVN_WC__ENTRY_MODIFY_CONFLICT_NEW
598 | SVN_WC__ENTRY_MODIFY_CONFLICT_WRK
,
601 *merge_outcome
= svn_wc_merge_conflict
;
603 else if (contains_conflicts
&& dry_run
)
605 *merge_outcome
= svn_wc_merge_conflict
;
606 } /* end of conflict handling */
607 else if (copyfrom_text
)
609 *merge_outcome
= svn_wc_merge_merged
;
614 SVN_ERR(svn_io_files_contents_same_p(&same
, result_target
,
615 merge_target
, pool
));
617 *merge_outcome
= same
? svn_wc_merge_unchanged
: svn_wc_merge_merged
;
620 if (*merge_outcome
!= svn_wc_merge_unchanged
&& ! dry_run
)
621 /* replace MERGE_TARGET with the new merged file, expanding. */
622 SVN_ERR(svn_wc__loggy_copy(log_accum
, NULL
,
624 svn_wc__copy_translate
,
625 result_target
, merge_target
,
628 } /* end of merging for text files */
630 else if (! dry_run
) /* merging procedure for binary files */
632 /* ### when making the binary-file backups, should we be honoring
633 keywords and eol stuff? */
635 const char *left_copy
, *right_copy
;
636 const char *parentt
, *left_base
, *right_base
;
637 svn_wc_entry_t tmp_entry
;
639 /* Give the conflict resolution callback a chance to clean
640 up the conflict before we mark the file 'conflicted' */
643 svn_wc_conflict_result_t
*result
= NULL
;
644 svn_wc_conflict_description_t cdesc
;
646 cdesc
.path
= merge_target
;
647 cdesc
.node_kind
= svn_node_file
;
648 cdesc
.kind
= svn_wc_conflict_kind_text
;
649 cdesc
.is_binary
= TRUE
;
650 cdesc
.mime_type
= (mimeprop
&& mimeprop
->value
)
651 ? mimeprop
->value
->data
: NULL
;
652 cdesc
.access
= adm_access
;
653 cdesc
.action
= svn_wc_conflict_action_edit
;
654 cdesc
.reason
= svn_wc_conflict_reason_edited
;
655 cdesc
.base_file
= left
;
656 cdesc
.their_file
= right
;
657 cdesc
.my_file
= tmp_target
;
658 cdesc
.merged_file
= NULL
; /* notice there is NO merged file! */
659 cdesc
.property_name
= NULL
;
661 SVN_ERR(conflict_func(&result
, &cdesc
, conflict_baton
, pool
));
663 return svn_error_create(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE
,
664 NULL
, _("Conflict callback violated API:"
665 " returned no results"));
667 switch (result
->choice
)
669 /* For a binary file, there's no merged file to look at,
670 unless the conflict-callback did the merging itself. */
671 case svn_wc_conflict_choose_base
:
673 SVN_ERR(svn_wc__loggy_copy
674 (log_accum
, NULL
, adm_access
,
675 svn_wc__copy_translate
,
678 *merge_outcome
= svn_wc_merge_merged
;
679 contains_conflicts
= FALSE
;
682 case svn_wc_conflict_choose_theirs_full
:
684 SVN_ERR(svn_wc__loggy_copy
685 (log_accum
, NULL
, adm_access
,
686 svn_wc__copy_translate
,
689 *merge_outcome
= svn_wc_merge_merged
;
690 contains_conflicts
= FALSE
;
693 /* For a binary file, if the response is to use the
694 user's file, we do nothing. We also do nothing if
695 the response claims to have already resolved the
697 case svn_wc_conflict_choose_mine_full
:
699 *merge_outcome
= svn_wc_merge_merged
;
700 contains_conflicts
= FALSE
;
703 case svn_wc_conflict_choose_merged
:
705 if (! result
->merged_file
)
707 /* Callback asked us to choose its own
708 merged file, but didn't provide one! */
709 return svn_error_create
710 (SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE
,
711 NULL
, _("Conflict callback violated API:"
712 " returned no merged file"));
716 SVN_ERR(svn_wc__loggy_copy
717 (log_accum
, NULL
, adm_access
,
718 svn_wc__copy_translate
,
719 result
->merged_file
, merge_target
,
721 *merge_outcome
= svn_wc_merge_merged
;
722 contains_conflicts
= FALSE
;
726 case svn_wc_conflict_choose_postpone
:
729 /* Assume conflict remains, fall through to code below. */
734 /* reserve names for backups of left and right fulltexts */
735 SVN_ERR(svn_io_open_unique_file2(NULL
,
739 svn_io_file_del_none
,
742 SVN_ERR(svn_io_open_unique_file2(NULL
,
746 svn_io_file_del_none
,
749 /* create the backup files */
750 SVN_ERR(svn_io_copy_file(left
,
751 left_copy
, TRUE
, pool
));
752 SVN_ERR(svn_io_copy_file(right
,
753 right_copy
, TRUE
, pool
));
755 /* Was the merge target detranslated? */
756 if (merge_target
!= tmp_target
)
758 /* Create a .mine file too */
759 const char *mine_copy
;
761 SVN_ERR(svn_io_open_unique_file2(NULL
,
765 svn_io_file_del_none
,
767 SVN_ERR(svn_wc__loggy_move(log_accum
, NULL
,
772 mine_copy
= svn_path_is_child(adm_path
, mine_copy
, pool
);
773 tmp_entry
.conflict_wrk
= mine_copy
;
776 tmp_entry
.conflict_wrk
= NULL
;
778 /* Derive the basenames of the backup files. */
779 svn_path_split(left_copy
, &parentt
, &left_base
, pool
);
780 svn_path_split(right_copy
, &parentt
, &right_base
, pool
);
782 /* Mark merge_target's entry as "Conflicted", and start tracking
783 the backup files in the entry as well. */
784 tmp_entry
.conflict_old
= left_base
;
785 tmp_entry
.conflict_new
= right_base
;
786 SVN_ERR(svn_wc__loggy_entry_modify
788 adm_access
, merge_target
,
790 SVN_WC__ENTRY_MODIFY_CONFLICT_OLD
791 | SVN_WC__ENTRY_MODIFY_CONFLICT_NEW
792 | SVN_WC__ENTRY_MODIFY_CONFLICT_WRK
,
795 *merge_outcome
= svn_wc_merge_conflict
; /* a conflict happened */
797 } /* end of binary conflict handling */
799 *merge_outcome
= svn_wc_merge_conflict
; /* dry_run for binary files. */
802 /* Merging is complete. Regardless of text or binariness, we might
803 need to tweak the executable bit on the new working file. */
806 SVN_ERR(svn_wc__loggy_maybe_set_executable(log_accum
,
807 adm_access
, merge_target
,
810 SVN_ERR(svn_wc__loggy_maybe_set_readonly(log_accum
,
811 adm_access
, merge_target
,
822 svn_wc_merge3(enum svn_wc_merge_outcome_t
*merge_outcome
,
825 const char *merge_target
,
826 svn_wc_adm_access_t
*adm_access
,
827 const char *left_label
,
828 const char *right_label
,
829 const char *target_label
,
830 svn_boolean_t dry_run
,
831 const char *diff3_cmd
,
832 const apr_array_header_t
*merge_options
,
833 const apr_array_header_t
*prop_diff
,
834 svn_wc_conflict_resolver_func_t conflict_func
,
835 void *conflict_baton
,
838 svn_stringbuf_t
*log_accum
= svn_stringbuf_create("", pool
);
840 SVN_ERR(svn_wc__merge_internal(&log_accum
, merge_outcome
,
841 left
, right
, merge_target
,
844 left_label
, right_label
, target_label
,
849 conflict_func
, conflict_baton
,
852 /* Write our accumulation of log entries into a log file */
853 SVN_ERR(svn_wc__write_log(adm_access
, 0, log_accum
, pool
));
855 SVN_ERR(svn_wc__run_log(adm_access
, NULL
, pool
));
862 svn_wc_merge2(enum svn_wc_merge_outcome_t
*merge_outcome
,
865 const char *merge_target
,
866 svn_wc_adm_access_t
*adm_access
,
867 const char *left_label
,
868 const char *right_label
,
869 const char *target_label
,
870 svn_boolean_t dry_run
,
871 const char *diff3_cmd
,
872 const apr_array_header_t
*merge_options
,
875 return svn_wc_merge3(merge_outcome
,
876 left
, right
, merge_target
, adm_access
,
877 left_label
, right_label
, target_label
,
878 dry_run
, diff3_cmd
, merge_options
, NULL
,
883 svn_wc_merge(const char *left
,
885 const char *merge_target
,
886 svn_wc_adm_access_t
*adm_access
,
887 const char *left_label
,
888 const char *right_label
,
889 const char *target_label
,
890 svn_boolean_t dry_run
,
891 enum svn_wc_merge_outcome_t
*merge_outcome
,
892 const char *diff3_cmd
,
895 return svn_wc_merge3(merge_outcome
,
896 left
, right
, merge_target
, adm_access
,
897 left_label
, right_label
, target_label
,
898 dry_run
, diff3_cmd
, NULL
, NULL
, NULL
,
904 /* Constructor for the result-structure returned by conflict callbacks. */
905 svn_wc_conflict_result_t
*
906 svn_wc_create_conflict_result(svn_wc_conflict_choice_t choice
,
907 const char *merged_file
,
910 svn_wc_conflict_result_t
*result
= apr_pcalloc(pool
, sizeof(*result
));
911 result
->choice
= choice
;
912 result
->merged_file
= merged_file
;
914 /* If we add more fields to svn_wc_conflict_result_t, add them here. */