2 * merge.c: merging changes into a working file
4 * ====================================================================
5 * Licensed to the Apache Software Foundation (ASF) under one
6 * or more contributor license agreements. See the NOTICE file
7 * distributed with this work for additional information
8 * regarding copyright ownership. The ASF licenses this file
9 * to you under the Apache License, Version 2.0 (the
10 * "License"); you may not use this file except in compliance
11 * with the License. You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing,
16 * software distributed under the License is distributed on an
17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 * KIND, either express or implied. See the License for the
19 * specific language governing permissions and limitations
21 * ====================================================================
26 #include "svn_dirent_uri.h"
28 #include "svn_pools.h"
29 #include "svn_props.h"
32 #include "conflicts.h"
34 #include "translate.h"
35 #include "workqueue.h"
37 #include "private/svn_skel.h"
39 #include "svn_private_config.h"
41 /* Contains some information on the merge target before merge, and some
42 information needed for the diff processing. */
43 typedef struct merge_target_t
45 svn_wc__db_t
*db
; /* The DB used to access target */
46 const char *local_abspath
; /* The absolute path to target */
47 const char *wri_abspath
; /* The working copy of target */
49 apr_hash_t
*old_actual_props
; /* The set of actual properties
51 const apr_array_header_t
*prop_diff
; /* The property changes */
53 const char *diff3_cmd
; /* The diff3 command and options */
54 const apr_array_header_t
*merge_options
;
59 /* Return a pointer to the svn_prop_t structure from PROP_DIFF
60 belonging to PROP_NAME, if any. NULL otherwise.*/
61 static const svn_prop_t
*
62 get_prop(const apr_array_header_t
*prop_diff
,
63 const char *prop_name
)
68 for (i
= 0; i
< prop_diff
->nelts
; i
++)
70 const svn_prop_t
*elt
= &APR_ARRAY_IDX(prop_diff
, i
,
73 if (strcmp(elt
->name
, prop_name
) == 0)
82 /* Detranslate a working copy file MERGE_TARGET to achieve the effect of:
89 in one pass, to get a file which can be compared with the left and right
90 files which are in repository normal form.
92 Property changes make this a little complex though. Changes in
99 may change the way a file is translated.
101 Effect for svn:mime-type:
103 If svn:mime-type is considered 'binary', we ignore svn:eol-style (but
104 still translate keywords).
106 I) both old and new mime-types are texty
107 -> just do the translation dance (as lined out below)
108 ### actually we do a shortcut with just one translation:
109 detranslate with the old keywords and ... eol-style
110 (the new re+detranslation is a no-op w.r.t. keywords [1])
112 II) the old one is texty, the new one is binary
113 -> detranslate with the old eol-style and keywords
114 (the new re+detranslation is a no-op [1])
116 III) the old one is binary, the new one texty
117 -> detranslate with the old keywords and new eol-style
118 (the old detranslation is a no-op w.r.t. eol, and
119 the new re+detranslation is a no-op w.r.t. keywords [1])
121 IV) the old and new ones are binary
122 -> detranslate with the old keywords
123 (the new re+detranslation is a no-op [1])
125 Effect for svn:eol-style
127 I) On add or change of svn:eol-style, use the new value
129 II) otherwise: use the old value (absent means 'no translation')
131 Effect for svn:keywords
133 Always use the old settings (re+detranslation are no-op [1]).
135 [1] Translation of keywords from repository normal form to WC form and
136 back is normally a no-op, but is not a no-op if text contains a kw
137 that is only enabled by the new props and is present in non-
138 contracted form (such as "$Rev: 1234 $"). If we want to catch this
139 case we should detranslate with both the old & the new keywords
142 Effect for svn:special
144 Always use the old settings (re+detranslation are no-op).
146 Sets *DETRANSLATED_ABSPATH to the path to the detranslated file,
147 this may be the same as SOURCE_ABSPATH if FORCE_COPY is FALSE and no
148 translation is required.
150 If FORCE_COPY is FALSE and *DETRANSLATED_ABSPATH is a file distinct
151 from SOURCE_ABSPATH then the file will be deleted on RESULT_POOL
154 If FORCE_COPY is TRUE then *DETRANSLATED_ABSPATH will always be a
155 new file distinct from SOURCE_ABSPATH and it will be the callers
156 responsibility to delete the file.
160 detranslate_wc_file(const char **detranslated_abspath
,
161 const merge_target_t
*mt
,
162 svn_boolean_t force_copy
,
163 const char *source_abspath
,
164 svn_cancel_func_t cancel_func
,
166 apr_pool_t
*result_pool
,
167 apr_pool_t
*scratch_pool
)
169 svn_boolean_t old_is_binary
, new_is_binary
;
170 svn_subst_eol_style_t style
;
172 apr_hash_t
*keywords
;
173 svn_boolean_t special
;
176 const char *old_mime_value
177 = svn_prop_get_value(mt
->old_actual_props
, SVN_PROP_MIME_TYPE
);
178 const svn_prop_t
*prop
= get_prop(mt
->prop_diff
, SVN_PROP_MIME_TYPE
);
179 const char *new_mime_value
180 = prop
? (prop
->value
? prop
->value
->data
: NULL
) : old_mime_value
;
182 old_is_binary
= old_mime_value
&& svn_mime_type_is_binary(old_mime_value
);
183 new_is_binary
= new_mime_value
&& svn_mime_type_is_binary(new_mime_value
);
186 /* See what translations we want to do */
187 if (old_is_binary
&& new_is_binary
)
189 /* Case IV. Old and new props 'binary': detranslate keywords only */
190 SVN_ERR(svn_wc__get_translate_info(NULL
, NULL
, &keywords
, NULL
,
191 mt
->db
, mt
->local_abspath
,
192 mt
->old_actual_props
, TRUE
,
193 scratch_pool
, scratch_pool
));
194 /* ### Why override 'special'? Elsewhere it has precedence. */
197 style
= svn_subst_eol_style_none
;
199 else if (!old_is_binary
&& new_is_binary
)
201 /* Case II. Old props indicate texty, new props indicate binary:
202 detranslate keywords and old eol-style */
203 SVN_ERR(svn_wc__get_translate_info(&style
, &eol
,
206 mt
->db
, mt
->local_abspath
,
207 mt
->old_actual_props
, TRUE
,
208 scratch_pool
, scratch_pool
));
212 /* Case I & III. New props indicate texty, regardless of old props */
214 /* In case the file used to be special, detranslate specially */
215 SVN_ERR(svn_wc__get_translate_info(&style
, &eol
,
218 mt
->db
, mt
->local_abspath
,
219 mt
->old_actual_props
, TRUE
,
220 scratch_pool
, scratch_pool
));
226 style
= svn_subst_eol_style_none
;
230 const svn_prop_t
*prop
;
232 /* In case a new eol style was set, use that for detranslation */
233 if ((prop
= get_prop(mt
->prop_diff
, SVN_PROP_EOL_STYLE
)) && prop
->value
)
235 /* Value added or changed */
236 svn_subst_eol_style_from_value(&style
, &eol
, prop
->value
->data
);
238 else if (!old_is_binary
)
240 /* Already fetched */
245 style
= svn_subst_eol_style_none
;
250 /* Now, detranslate with the settings we created above */
252 if (force_copy
|| keywords
|| eol
|| special
)
254 const char *temp_dir_abspath
;
255 const char *detranslated
;
257 /* Force a copy into the temporary wc area to avoid having
258 temporary files created below to appear in the actual wc. */
259 SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&temp_dir_abspath
, mt
->db
,
261 scratch_pool
, scratch_pool
));
263 /* ### svn_subst_copy_and_translate4() also creates a tempfile
264 ### internally. Anyway to piggyback on that? */
265 SVN_ERR(svn_io_open_unique_file3(NULL
, &detranslated
, temp_dir_abspath
,
267 ? svn_io_file_del_none
268 : svn_io_file_del_on_pool_cleanup
),
269 result_pool
, scratch_pool
));
271 /* Always 'repair' EOLs here, so that we can apply a diff that
272 changes from inconsistent newlines and no 'svn:eol-style' to
273 consistent newlines and 'svn:eol-style' set. */
275 if (style
== svn_subst_eol_style_native
)
276 eol
= SVN_SUBST_NATIVE_EOL_STR
;
277 else if (style
!= svn_subst_eol_style_fixed
278 && style
!= svn_subst_eol_style_none
)
279 return svn_error_create(SVN_ERR_IO_UNKNOWN_EOL
, NULL
, NULL
);
281 SVN_ERR(svn_subst_copy_and_translate4(source_abspath
,
286 FALSE
/* contract keywords */,
288 cancel_func
, cancel_baton
,
291 SVN_ERR(svn_dirent_get_absolute(detranslated_abspath
, detranslated
,
295 *detranslated_abspath
= apr_pstrdup(result_pool
, source_abspath
);
300 /* Updates (by copying and translating) the eol style in
301 OLD_TARGET_ABSPATH returning the filename containing the
302 correct eol style in NEW_TARGET_ABSPATH, if an eol style
303 change is contained in PROP_DIFF. */
305 maybe_update_target_eols(const char **new_target_abspath
,
306 const apr_array_header_t
*prop_diff
,
307 const char *old_target_abspath
,
308 svn_cancel_func_t cancel_func
,
310 apr_pool_t
*result_pool
,
311 apr_pool_t
*scratch_pool
)
313 const svn_prop_t
*prop
= get_prop(prop_diff
, SVN_PROP_EOL_STYLE
);
315 if (prop
&& prop
->value
)
320 svn_subst_eol_style_from_value(NULL
, &eol
, prop
->value
->data
);
321 SVN_ERR(svn_io_open_unique_file3(NULL
, &tmp_new
, NULL
,
322 svn_io_file_del_on_pool_cleanup
,
323 result_pool
, scratch_pool
));
325 /* Always 'repair' EOLs here, so that we can apply a diff that
326 changes from inconsistent newlines and no 'svn:eol-style' to
327 consistent newlines and 'svn:eol-style' set. */
328 SVN_ERR(svn_subst_copy_and_translate4(old_target_abspath
,
335 cancel_func
, cancel_baton
,
337 *new_target_abspath
= apr_pstrdup(result_pool
, tmp_new
);
340 *new_target_abspath
= apr_pstrdup(result_pool
, old_target_abspath
);
346 /* Set *TARGET_MARKER, *LEFT_MARKER and *RIGHT_MARKER to strings suitable
347 for delimiting the alternative texts in a text conflict. Include in each
348 marker a string that may be given by TARGET_LABEL, LEFT_LABEL and
349 RIGHT_LABEL respectively or a default value where any of those are NULL.
351 Allocate the results in POOL or statically. */
353 init_conflict_markers(const char **target_marker
,
354 const char **left_marker
,
355 const char **right_marker
,
356 const char *target_label
,
357 const char *left_label
,
358 const char *right_label
,
361 /* Labels fall back to sensible defaults if not specified. */
363 *target_marker
= apr_psprintf(pool
, "<<<<<<< %s", target_label
);
365 *target_marker
= "<<<<<<< .working";
368 *left_marker
= apr_psprintf(pool
, "||||||| %s", left_label
);
370 *left_marker
= "||||||| .old";
373 *right_marker
= apr_psprintf(pool
, ">>>>>>> %s", right_label
);
375 *right_marker
= ">>>>>>> .new";
378 /* Do a 3-way merge of the files at paths LEFT, DETRANSLATED_TARGET,
379 * and RIGHT, using diff options provided in MERGE_OPTIONS. Store the merge
380 * result in the file RESULT_F.
381 * If there are conflicts, set *CONTAINS_CONFLICTS to true, and use
382 * TARGET_LABEL, LEFT_LABEL, and RIGHT_LABEL as labels for conflict
383 * markers. Else, set *CONTAINS_CONFLICTS to false.
384 * Do all allocations in POOL. */
386 do_text_merge(svn_boolean_t
*contains_conflicts
,
387 apr_file_t
*result_f
,
388 const apr_array_header_t
*merge_options
,
389 const char *detranslated_target
,
392 const char *target_label
,
393 const char *left_label
,
394 const char *right_label
,
395 svn_cancel_func_t cancel_func
,
400 svn_stream_t
*ostream
;
401 const char *target_marker
;
402 const char *left_marker
;
403 const char *right_marker
;
404 svn_diff_file_options_t
*diff3_options
;
406 diff3_options
= svn_diff_file_options_create(pool
);
409 SVN_ERR(svn_diff_file_options_parse(diff3_options
,
410 merge_options
, pool
));
413 init_conflict_markers(&target_marker
, &left_marker
, &right_marker
,
414 target_label
, left_label
, right_label
, pool
);
416 SVN_ERR(svn_diff_file_diff3_2(&diff
, left
, detranslated_target
, right
,
417 diff3_options
, pool
));
419 ostream
= svn_stream_from_aprfile2(result_f
, TRUE
, pool
);
421 SVN_ERR(svn_diff_file_output_merge3(ostream
, diff
,
422 left
, detranslated_target
, right
,
426 "=======", /* separator */
427 svn_diff_conflict_display_modified_original_latest
,
428 cancel_func
, cancel_baton
,
430 SVN_ERR(svn_stream_close(ostream
));
432 *contains_conflicts
= svn_diff_contains_conflicts(diff
);
437 /* Same as do_text_merge() above, but use the external diff3
438 * command DIFF3_CMD to perform the merge. Pass MERGE_OPTIONS
439 * to the diff3 command. Do all allocations in POOL. */
441 do_text_merge_external(svn_boolean_t
*contains_conflicts
,
442 apr_file_t
*result_f
,
443 const char *diff3_cmd
,
444 const apr_array_header_t
*merge_options
,
445 const char *detranslated_target
,
446 const char *left_abspath
,
447 const char *right_abspath
,
448 const char *target_label
,
449 const char *left_label
,
450 const char *right_label
,
451 apr_pool_t
*scratch_pool
)
455 SVN_ERR(svn_io_run_diff3_3(&exit_code
, ".",
456 detranslated_target
, left_abspath
, right_abspath
,
457 target_label
, left_label
, right_label
,
459 merge_options
, scratch_pool
));
461 *contains_conflicts
= exit_code
== 1;
466 /* Preserve the three pre-merge files.
468 Create three empty files, with unique names that each include the
469 basename of TARGET_ABSPATH and one of LEFT_LABEL, RIGHT_LABEL and
470 TARGET_LABEL, in the directory that contains TARGET_ABSPATH. Typical
471 names are "foo.c.r37" or "foo.c.2.mine". Set *LEFT_COPY, *RIGHT_COPY and
472 *TARGET_COPY to their absolute paths.
474 Set *WORK_ITEMS to a list of new work items that will write copies of
475 LEFT_ABSPATH, RIGHT_ABSPATH and TARGET_ABSPATH into the three files,
476 translated to working-copy form.
478 The translation to working-copy form will be done according to the
479 versioned properties of TARGET_ABSPATH that are current when the work
480 queue items are executed.
482 If target_abspath is not versioned use detranslated_target_abspath
484 ### NOT IMPLEMENTED -- 'detranslated_target_abspath' is not used.
487 preserve_pre_merge_files(svn_skel_t
**work_items
,
488 const char **left_copy
,
489 const char **right_copy
,
490 const char **target_copy
,
491 const merge_target_t
*mt
,
492 const char *left_abspath
,
493 const char *right_abspath
,
494 const char *left_label
,
495 const char *right_label
,
496 const char *target_label
,
497 const char *detranslated_target_abspath
,
498 svn_cancel_func_t cancel_func
,
500 apr_pool_t
*result_pool
,
501 apr_pool_t
*scratch_pool
)
503 const char *tmp_left
, *tmp_right
, *detranslated_target_copy
;
504 const char *dir_abspath
, *target_name
;
505 const char *wcroot_abspath
, *temp_dir_abspath
;
506 svn_skel_t
*work_item
, *last_items
= NULL
;
510 svn_dirent_split(&dir_abspath
, &target_name
, mt
->local_abspath
,
513 SVN_ERR(svn_wc__db_get_wcroot(&wcroot_abspath
, mt
->db
, mt
->wri_abspath
,
514 scratch_pool
, scratch_pool
));
515 SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&temp_dir_abspath
, mt
->db
,
517 scratch_pool
, scratch_pool
));
519 /* Create three empty files in DIR_ABSPATH, naming them with unique names
520 that each include TARGET_NAME and one of {LEFT,RIGHT,TARGET}_LABEL,
521 and set *{LEFT,RIGHT,TARGET}_COPY to those names. */
522 SVN_ERR(svn_io_open_uniquely_named(
523 NULL
, left_copy
, dir_abspath
, target_name
, left_label
,
524 svn_io_file_del_none
, result_pool
, scratch_pool
));
525 SVN_ERR(svn_io_open_uniquely_named(
526 NULL
, right_copy
, dir_abspath
, target_name
, right_label
,
527 svn_io_file_del_none
, result_pool
, scratch_pool
));
528 SVN_ERR(svn_io_open_uniquely_named(
529 NULL
, target_copy
, dir_abspath
, target_name
, target_label
,
530 svn_io_file_del_none
, result_pool
, scratch_pool
));
532 /* We preserve all the files with keywords expanded and line
533 endings in local (working) form. */
535 /* The workingqueue requires its paths to be in the subtree
536 relative to the wcroot path they are executed in.
538 Make our LEFT and RIGHT files 'local' if they aren't... */
539 if (! svn_dirent_is_ancestor(wcroot_abspath
, left_abspath
))
541 SVN_ERR(svn_io_open_unique_file3(NULL
, &tmp_left
, temp_dir_abspath
,
542 svn_io_file_del_none
,
543 scratch_pool
, scratch_pool
));
544 SVN_ERR(svn_io_copy_file(left_abspath
, tmp_left
, TRUE
, scratch_pool
));
546 /* And create a wq item to remove the file later */
547 SVN_ERR(svn_wc__wq_build_file_remove(&work_item
, mt
->db
, wcroot_abspath
,
549 result_pool
, scratch_pool
));
551 last_items
= svn_wc__wq_merge(last_items
, work_item
, result_pool
);
554 tmp_left
= left_abspath
;
556 if (! svn_dirent_is_ancestor(wcroot_abspath
, right_abspath
))
558 SVN_ERR(svn_io_open_unique_file3(NULL
, &tmp_right
, temp_dir_abspath
,
559 svn_io_file_del_none
,
560 scratch_pool
, scratch_pool
));
561 SVN_ERR(svn_io_copy_file(right_abspath
, tmp_right
, TRUE
, scratch_pool
));
563 /* And create a wq item to remove the file later */
564 SVN_ERR(svn_wc__wq_build_file_remove(&work_item
, mt
->db
, wcroot_abspath
,
566 result_pool
, scratch_pool
));
568 last_items
= svn_wc__wq_merge(last_items
, work_item
, result_pool
);
571 tmp_right
= right_abspath
;
573 /* NOTE: Callers must ensure that the svn:eol-style and
574 svn:keywords property values are correct in the currently
575 installed props. With 'svn merge', it's no big deal. But
576 when 'svn up' calls this routine, it needs to make sure that
577 this routine is using the newest property values that may
578 have been received *during* the update. Since this routine
579 will be run from within a log-command, merge_file()
580 needs to make sure that a previous log-command to 'install
581 latest props' has already executed first. Ben and I just
582 checked, and that is indeed the order in which the log items
583 are written, so everything should be fine. Really. */
585 /* Create LEFT and RIGHT backup files, in expanded form.
586 We use TARGET_ABSPATH's current properties to do the translation. */
587 /* Derive the basenames of the 3 backup files. */
588 SVN_ERR(svn_wc__wq_build_file_copy_translated(&work_item
,
589 mt
->db
, mt
->local_abspath
,
590 tmp_left
, *left_copy
,
591 result_pool
, scratch_pool
));
592 *work_items
= svn_wc__wq_merge(*work_items
, work_item
, result_pool
);
594 SVN_ERR(svn_wc__wq_build_file_copy_translated(&work_item
,
595 mt
->db
, mt
->local_abspath
,
596 tmp_right
, *right_copy
,
597 result_pool
, scratch_pool
));
598 *work_items
= svn_wc__wq_merge(*work_items
, work_item
, result_pool
);
600 /* Back up TARGET_ABSPATH through detranslation/retranslation:
601 the new translation properties may not match the current ones */
602 SVN_ERR(detranslate_wc_file(&detranslated_target_copy
, mt
, TRUE
,
604 cancel_func
, cancel_baton
,
605 scratch_pool
, scratch_pool
));
607 SVN_ERR(svn_wc__wq_build_file_copy_translated(&work_item
,
608 mt
->db
, mt
->local_abspath
,
609 detranslated_target_copy
,
611 result_pool
, scratch_pool
));
612 *work_items
= svn_wc__wq_merge(*work_items
, work_item
, result_pool
);
614 /* And maybe delete some tempfiles */
615 SVN_ERR(svn_wc__wq_build_file_remove(&work_item
, mt
->db
, wcroot_abspath
,
616 detranslated_target_copy
,
617 result_pool
, scratch_pool
));
618 *work_items
= svn_wc__wq_merge(*work_items
, work_item
, result_pool
);
620 *work_items
= svn_wc__wq_merge(*work_items
, last_items
, result_pool
);
625 /* Attempt a trivial merge of LEFT_ABSPATH and RIGHT_ABSPATH to
626 * the target file at TARGET_ABSPATH.
628 * These are the inherently trivial cases:
630 * left == right == target => no-op
631 * left != right, left == target => target := right
633 * This case is also treated as trivial:
635 * left != right, right == target => no-op
637 * ### Strictly, this case is a conflict, and the no-op outcome is only
638 * one of the possible resolutions.
640 * TODO: Raise a conflict at this level and implement the 'no-op'
641 * resolution of that conflict at a higher level, in preparation for
642 * being able to support stricter conflict detection.
644 * This case is inherently trivial but not currently handled here:
646 * left == right != target => no-op
648 * The files at LEFT_ABSPATH and RIGHT_ABSPATH are in repository normal
649 * form. The file at DETRANSLATED_TARGET_ABSPATH is a copy of the target,
650 * 'detranslated' to repository normal form, or may be the target file
651 * itself if no translation is necessary.
653 * When this function updates the target file, it translates to working copy
656 * On success, set *MERGE_OUTCOME to SVN_WC_MERGE_MERGED in case the
657 * target was changed, or to SVN_WC_MERGE_UNCHANGED if the target was not
658 * changed. Install work queue items allocated in RESULT_POOL in *WORK_ITEMS.
659 * On failure, set *MERGE_OUTCOME to SVN_WC_MERGE_NO_MERGE.
662 merge_file_trivial(svn_skel_t
**work_items
,
663 enum svn_wc_merge_outcome_t
*merge_outcome
,
664 const char *left_abspath
,
665 const char *right_abspath
,
666 const char *target_abspath
,
667 const char *detranslated_target_abspath
,
668 svn_boolean_t dry_run
,
670 svn_cancel_func_t cancel_func
,
672 apr_pool_t
*result_pool
,
673 apr_pool_t
*scratch_pool
)
675 svn_skel_t
*work_item
;
676 svn_boolean_t same_left_right
;
677 svn_boolean_t same_right_target
;
678 svn_boolean_t same_left_target
;
679 svn_node_kind_t kind
;
680 svn_boolean_t is_special
;
682 /* If the target is not a normal file, do not attempt a trivial merge. */
683 SVN_ERR(svn_io_check_special_path(target_abspath
, &kind
, &is_special
,
685 if (kind
!= svn_node_file
|| is_special
)
687 *merge_outcome
= svn_wc_merge_no_merge
;
691 /* Check the files */
692 SVN_ERR(svn_io_files_contents_three_same_p(&same_left_right
,
697 detranslated_target_abspath
,
700 /* If the LEFT side of the merge is equal to WORKING, then we can
701 * copy RIGHT directly. */
702 if (same_left_target
)
704 /* If the left side equals the right side, there is no change to merge
705 * so we leave the target unchanged. */
708 *merge_outcome
= svn_wc_merge_unchanged
;
712 *merge_outcome
= svn_wc_merge_merged
;
715 const char *wcroot_abspath
;
716 svn_boolean_t delete_src
= FALSE
;
718 /* The right_abspath might be outside our working copy. In that
719 case we should copy the file to a safe location before
720 installing to avoid breaking the workqueue.
722 This matches the behavior in preserve_pre_merge_files */
724 SVN_ERR(svn_wc__db_get_wcroot(&wcroot_abspath
,
726 scratch_pool
, scratch_pool
));
728 if (!svn_dirent_is_child(wcroot_abspath
, right_abspath
, NULL
))
730 svn_stream_t
*tmp_src
;
731 svn_stream_t
*tmp_dst
;
734 SVN_ERR(svn_stream_open_readonly(&tmp_src
, right_abspath
,
738 SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&tmp_dir
, db
,
743 SVN_ERR(svn_stream_open_unique(&tmp_dst
, &right_abspath
,
744 tmp_dir
, svn_io_file_del_none
,
745 scratch_pool
, scratch_pool
));
747 SVN_ERR(svn_stream_copy3(tmp_src
, tmp_dst
,
748 cancel_func
, cancel_baton
,
754 SVN_ERR(svn_wc__wq_build_file_install(
755 &work_item
, db
, target_abspath
, right_abspath
,
756 FALSE
/* use_commit_times */,
757 FALSE
/* record_fileinfo */,
758 result_pool
, scratch_pool
));
759 *work_items
= svn_wc__wq_merge(*work_items
, work_item
,
764 SVN_ERR(svn_wc__wq_build_file_remove(
765 &work_item
, db
, wcroot_abspath
,
767 result_pool
, scratch_pool
));
768 *work_items
= svn_wc__wq_merge(*work_items
, work_item
,
778 /* If the locally existing, changed file equals the incoming 'right'
779 * file, there is no conflict. For binary files, we historically
780 * conflicted them needlessly, while merge_text_file figured it out
781 * eventually and returned svn_wc_merge_unchanged for them, which
782 * is what we do here. */
783 if (same_right_target
)
785 *merge_outcome
= svn_wc_merge_unchanged
;
790 *merge_outcome
= svn_wc_merge_no_merge
;
795 /* Handle a non-trivial merge of 'text' files. (Assume that a trivial
796 * merge was not possible.)
798 * Set *WORK_ITEMS, *CONFLICT_SKEL and *MERGE_OUTCOME according to the
799 * result -- to install the merged file, or to indicate a conflict.
801 * On successful merge, leave the result in a temporary file and set
802 * *WORK_ITEMS to hold work items that will translate and install that
803 * file into its proper form and place (unless DRY_RUN) and delete the
804 * temporary file (in any case). Set *MERGE_OUTCOME to 'merged' or
807 * If a conflict occurs, set *MERGE_OUTCOME to 'conflicted', and (unless
808 * DRY_RUN) set *WORK_ITEMS and *CONFLICT_SKEL to record the conflict
809 * and copies of the pre-merge files. See preserve_pre_merge_files()
812 * On entry, all of the output pointers must be non-null and *CONFLICT_SKEL
813 * must either point to an existing conflict skel or be NULL.
816 merge_text_file(svn_skel_t
**work_items
,
817 svn_skel_t
**conflict_skel
,
818 enum svn_wc_merge_outcome_t
*merge_outcome
,
819 const merge_target_t
*mt
,
820 const char *left_abspath
,
821 const char *right_abspath
,
822 const char *left_label
,
823 const char *right_label
,
824 const char *target_label
,
825 svn_boolean_t dry_run
,
826 const char *detranslated_target_abspath
,
827 svn_cancel_func_t cancel_func
,
829 apr_pool_t
*result_pool
,
830 apr_pool_t
*scratch_pool
)
832 apr_pool_t
*pool
= scratch_pool
; /* ### temporary rename */
833 svn_boolean_t contains_conflicts
;
834 apr_file_t
*result_f
;
835 const char *result_target
;
836 const char *base_name
;
837 const char *temp_dir
;
838 svn_skel_t
*work_item
;
842 base_name
= svn_dirent_basename(mt
->local_abspath
, scratch_pool
);
844 /* Open a second temporary file for writing; this is where diff3
845 will write the merged results. We want to use a tempfile
846 with a name that reflects the original, in case this
847 ultimately winds up in a conflict resolution editor. */
848 SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&temp_dir
, mt
->db
, mt
->wri_abspath
,
850 SVN_ERR(svn_io_open_uniquely_named(&result_f
, &result_target
,
851 temp_dir
, base_name
, ".tmp",
852 svn_io_file_del_none
, pool
, pool
));
854 /* Run the external or internal merge, as requested. */
856 SVN_ERR(do_text_merge_external(&contains_conflicts
,
860 detranslated_target_abspath
,
867 else /* Use internal merge. */
868 SVN_ERR(do_text_merge(&contains_conflicts
,
871 detranslated_target_abspath
,
877 cancel_func
, cancel_baton
,
880 SVN_ERR(svn_io_file_close(result_f
, pool
));
882 /* Determine the MERGE_OUTCOME, and record any conflict. */
883 if (contains_conflicts
)
885 *merge_outcome
= svn_wc_merge_conflict
;
889 const char *left_copy
, *right_copy
, *target_copy
;
891 /* Preserve the three conflict files */
892 SVN_ERR(preserve_pre_merge_files(
894 &left_copy
, &right_copy
, &target_copy
,
895 mt
, left_abspath
, right_abspath
,
896 left_label
, right_label
, target_label
,
897 detranslated_target_abspath
,
898 cancel_func
, cancel_baton
,
899 result_pool
, scratch_pool
));
900 *work_items
= svn_wc__wq_merge(*work_items
, work_item
, result_pool
);
902 /* Track the conflict marker files in the metadata. */
905 *conflict_skel
= svn_wc__conflict_skel_create(result_pool
);
907 SVN_ERR(svn_wc__conflict_skel_add_text_conflict(*conflict_skel
,
908 mt
->db
, mt
->local_abspath
,
918 svn_boolean_t same
, special
;
920 /* If 'special', then use the detranslated form of the
921 target file. This is so we don't try to follow symlinks,
922 but the same treatment is probably also appropriate for
923 whatever special file types we may invent in the future. */
924 SVN_ERR(svn_wc__get_translate_info(NULL
, NULL
, NULL
,
925 &special
, mt
->db
, mt
->local_abspath
,
926 mt
->old_actual_props
, TRUE
,
928 SVN_ERR(svn_io_files_contents_same_p(&same
, result_target
,
930 detranslated_target_abspath
:
934 *merge_outcome
= same
? svn_wc_merge_unchanged
: svn_wc_merge_merged
;
937 if (*merge_outcome
!= svn_wc_merge_unchanged
&& ! dry_run
)
939 /* replace TARGET_ABSPATH with the new merged file, expanding. */
940 SVN_ERR(svn_wc__wq_build_file_install(&work_item
,
941 mt
->db
, mt
->local_abspath
,
943 FALSE
/* use_commit_times */,
944 FALSE
/* record_fileinfo */,
945 result_pool
, scratch_pool
));
946 *work_items
= svn_wc__wq_merge(*work_items
, work_item
, result_pool
);
949 /* Remove the tempfile after use */
950 SVN_ERR(svn_wc__wq_build_file_remove(&work_item
, mt
->db
, mt
->local_abspath
,
952 result_pool
, scratch_pool
));
954 *work_items
= svn_wc__wq_merge(*work_items
, work_item
, result_pool
);
959 /* Handle a non-trivial merge of 'binary' files: don't actually merge, just
960 * flag a conflict. (Assume that a trivial merge was not possible.)
962 * Copy* the files at LEFT_ABSPATH and RIGHT_ABSPATH into the same directory
963 * as the target file, giving them unique names that start with the target
964 * file's name and end with LEFT_LABEL and RIGHT_LABEL respectively.
965 * If the merge target has been 'detranslated' to repository normal form,
966 * move the detranslated file similarly to a unique name ending with
969 * ### * Why do we copy the left and right temp files when we could (maybe
970 * not always?) move them?
972 * On entry, all of the output pointers must be non-null and *CONFLICT_SKEL
973 * must either point to an existing conflict skel or be NULL.
975 * Set *WORK_ITEMS, *CONFLICT_SKEL and *MERGE_OUTCOME to indicate the
978 * ### Why do we not use preserve_pre_merge_files() in here? The
979 * behaviour would be slightly different, more consistent: the
980 * preserved 'left' and 'right' files would be translated to working
981 * copy form, which may make a difference when a binary file
982 * contains keyword expansions or when some versions of the file are
983 * not 'binary' even though we're merging in 'binary files' mode.
986 merge_binary_file(svn_skel_t
**work_items
,
987 svn_skel_t
**conflict_skel
,
988 enum svn_wc_merge_outcome_t
*merge_outcome
,
989 const merge_target_t
*mt
,
990 const char *left_abspath
,
991 const char *right_abspath
,
992 const char *left_label
,
993 const char *right_label
,
994 const char *target_label
,
995 svn_boolean_t dry_run
,
996 const char *detranslated_target_abspath
,
997 apr_pool_t
*result_pool
,
998 apr_pool_t
*scratch_pool
)
1000 apr_pool_t
*pool
= scratch_pool
; /* ### temporary rename */
1001 /* ### when making the binary-file backups, should we be honoring
1002 keywords and eol stuff? */
1003 const char *left_copy
, *right_copy
;
1004 const char *merge_dirpath
, *merge_filename
;
1005 const char *conflict_wrk
;
1009 svn_dirent_split(&merge_dirpath
, &merge_filename
, mt
->local_abspath
, pool
);
1013 *merge_outcome
= svn_wc_merge_conflict
;
1014 return SVN_NO_ERROR
;
1017 /* reserve names for backups of left and right fulltexts */
1018 SVN_ERR(svn_io_open_uniquely_named(NULL
,
1023 svn_io_file_del_none
,
1026 SVN_ERR(svn_io_open_uniquely_named(NULL
,
1031 svn_io_file_del_none
,
1034 /* create the backup files */
1035 SVN_ERR(svn_io_copy_file(left_abspath
, left_copy
, TRUE
, pool
));
1036 SVN_ERR(svn_io_copy_file(right_abspath
, right_copy
, TRUE
, pool
));
1038 /* Was the merge target detranslated? */
1039 if (strcmp(mt
->local_abspath
, detranslated_target_abspath
) != 0)
1041 /* Create a .mine file too */
1042 SVN_ERR(svn_io_open_uniquely_named(NULL
,
1047 svn_io_file_del_none
,
1049 SVN_ERR(svn_wc__wq_build_file_move(work_items
, mt
->db
,
1051 detranslated_target_abspath
,
1053 pool
, result_pool
));
1057 conflict_wrk
= NULL
;
1060 /* Mark target_abspath's entry as "Conflicted", and start tracking
1061 the backup files in the entry as well. */
1062 if (!*conflict_skel
)
1063 *conflict_skel
= svn_wc__conflict_skel_create(result_pool
);
1065 SVN_ERR(svn_wc__conflict_skel_add_text_conflict(*conflict_skel
,
1066 mt
->db
, mt
->local_abspath
,
1070 result_pool
, scratch_pool
));
1072 *merge_outcome
= svn_wc_merge_conflict
; /* a conflict happened */
1074 return SVN_NO_ERROR
;
1078 svn_wc__internal_merge(svn_skel_t
**work_items
,
1079 svn_skel_t
**conflict_skel
,
1080 enum svn_wc_merge_outcome_t
*merge_outcome
,
1082 const char *left_abspath
,
1083 const char *right_abspath
,
1084 const char *target_abspath
,
1085 const char *wri_abspath
,
1086 const char *left_label
,
1087 const char *right_label
,
1088 const char *target_label
,
1089 apr_hash_t
*old_actual_props
,
1090 svn_boolean_t dry_run
,
1091 const char *diff3_cmd
,
1092 const apr_array_header_t
*merge_options
,
1093 const apr_array_header_t
*prop_diff
,
1094 svn_cancel_func_t cancel_func
,
1096 apr_pool_t
*result_pool
,
1097 apr_pool_t
*scratch_pool
)
1099 const char *detranslated_target_abspath
;
1100 svn_boolean_t is_binary
= FALSE
;
1101 const svn_prop_t
*mimeprop
;
1102 svn_skel_t
*work_item
;
1105 SVN_ERR_ASSERT(svn_dirent_is_absolute(left_abspath
));
1106 SVN_ERR_ASSERT(svn_dirent_is_absolute(right_abspath
));
1107 SVN_ERR_ASSERT(svn_dirent_is_absolute(target_abspath
));
1111 /* Fill the merge target baton */
1113 mt
.local_abspath
= target_abspath
;
1114 mt
.wri_abspath
= wri_abspath
;
1115 mt
.old_actual_props
= old_actual_props
;
1116 mt
.prop_diff
= prop_diff
;
1117 mt
.diff3_cmd
= diff3_cmd
;
1118 mt
.merge_options
= merge_options
;
1120 /* Decide if the merge target is a text or binary file. */
1121 if ((mimeprop
= get_prop(prop_diff
, SVN_PROP_MIME_TYPE
))
1123 is_binary
= svn_mime_type_is_binary(mimeprop
->value
->data
);
1126 const char *value
= svn_prop_get_value(mt
.old_actual_props
,
1127 SVN_PROP_MIME_TYPE
);
1129 is_binary
= value
&& svn_mime_type_is_binary(value
);
1132 SVN_ERR(detranslate_wc_file(&detranslated_target_abspath
, &mt
,
1133 (! is_binary
) && diff3_cmd
!= NULL
,
1135 cancel_func
, cancel_baton
,
1136 scratch_pool
, scratch_pool
));
1138 /* We cannot depend on the left file to contain the same eols as the
1139 right file. If the merge target has mods, this will mark the entire
1140 file as conflicted, so we need to compensate. */
1141 SVN_ERR(maybe_update_target_eols(&left_abspath
, prop_diff
, left_abspath
,
1142 cancel_func
, cancel_baton
,
1143 scratch_pool
, scratch_pool
));
1145 SVN_ERR(merge_file_trivial(work_items
, merge_outcome
,
1146 left_abspath
, right_abspath
,
1147 target_abspath
, detranslated_target_abspath
,
1148 dry_run
, db
, cancel_func
, cancel_baton
,
1149 result_pool
, scratch_pool
));
1150 if (*merge_outcome
== svn_wc_merge_no_merge
)
1152 /* We have a non-trivial merge. If we classify it as a merge of
1153 * 'binary' files we'll just raise a conflict, otherwise we'll do
1154 * the actual merge of 'text' file contents. */
1157 /* Raise a text conflict */
1158 SVN_ERR(merge_binary_file(work_items
,
1168 detranslated_target_abspath
,
1169 result_pool
, scratch_pool
));
1173 SVN_ERR(merge_text_file(work_items
,
1183 detranslated_target_abspath
,
1184 cancel_func
, cancel_baton
,
1185 result_pool
, scratch_pool
));
1189 /* Merging is complete. Regardless of text or binariness, we might
1190 need to tweak the executable bit on the new working file, and
1191 possibly make it read-only. */
1194 SVN_ERR(svn_wc__wq_build_sync_file_flags(&work_item
, db
,
1196 result_pool
, scratch_pool
));
1197 *work_items
= svn_wc__wq_merge(*work_items
, work_item
, result_pool
);
1200 return SVN_NO_ERROR
;
1205 svn_wc_merge5(enum svn_wc_merge_outcome_t
*merge_content_outcome
,
1206 enum svn_wc_notify_state_t
*merge_props_outcome
,
1207 svn_wc_context_t
*wc_ctx
,
1208 const char *left_abspath
,
1209 const char *right_abspath
,
1210 const char *target_abspath
,
1211 const char *left_label
,
1212 const char *right_label
,
1213 const char *target_label
,
1214 const svn_wc_conflict_version_t
*left_version
,
1215 const svn_wc_conflict_version_t
*right_version
,
1216 svn_boolean_t dry_run
,
1217 const char *diff3_cmd
,
1218 const apr_array_header_t
*merge_options
,
1219 apr_hash_t
*original_props
,
1220 const apr_array_header_t
*prop_diff
,
1221 svn_wc_conflict_resolver_func2_t conflict_func
,
1222 void *conflict_baton
,
1223 svn_cancel_func_t cancel_func
,
1225 apr_pool_t
*scratch_pool
)
1227 const char *dir_abspath
= svn_dirent_dirname(target_abspath
, scratch_pool
);
1228 svn_skel_t
*work_items
;
1229 svn_skel_t
*conflict_skel
= NULL
;
1230 apr_hash_t
*pristine_props
= NULL
;
1231 apr_hash_t
*old_actual_props
;
1232 apr_hash_t
*new_actual_props
= NULL
;
1233 svn_node_kind_t kind
;
1235 SVN_ERR_ASSERT(svn_dirent_is_absolute(left_abspath
));
1236 SVN_ERR_ASSERT(svn_dirent_is_absolute(right_abspath
));
1237 SVN_ERR_ASSERT(svn_dirent_is_absolute(target_abspath
));
1239 /* Before we do any work, make sure we hold a write lock. */
1241 SVN_ERR(svn_wc__write_check(wc_ctx
->db
, dir_abspath
, scratch_pool
));
1243 /* Sanity check: the merge target must be a file under revision control */
1245 svn_wc__db_status_t status
;
1246 svn_boolean_t had_props
;
1247 svn_boolean_t props_mod
;
1248 svn_boolean_t conflicted
;
1250 SVN_ERR(svn_wc__db_read_info(&status
, &kind
, NULL
, NULL
, NULL
, NULL
, NULL
,
1251 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1252 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
1253 &conflicted
, NULL
, &had_props
, &props_mod
,
1255 wc_ctx
->db
, target_abspath
,
1256 scratch_pool
, scratch_pool
));
1258 if (kind
!= svn_node_file
|| (status
!= svn_wc__db_status_normal
1259 && status
!= svn_wc__db_status_added
))
1261 *merge_content_outcome
= svn_wc_merge_no_merge
;
1262 if (merge_props_outcome
)
1263 *merge_props_outcome
= svn_wc_notify_state_unchanged
;
1264 return SVN_NO_ERROR
;
1269 svn_boolean_t text_conflicted
;
1270 svn_boolean_t prop_conflicted
;
1271 svn_boolean_t tree_conflicted
;
1273 SVN_ERR(svn_wc__internal_conflicted_p(&text_conflicted
,
1276 wc_ctx
->db
, target_abspath
,
1279 /* We can't install two prop conflicts on a single node, so
1280 avoid even checking that we have to merge it */
1281 if (text_conflicted
|| prop_conflicted
|| tree_conflicted
)
1283 return svn_error_createf(
1284 SVN_ERR_WC_PATH_UNEXPECTED_STATUS
, NULL
,
1285 _("Can't merge into conflicted node '%s'"),
1286 svn_dirent_local_style(target_abspath
,
1289 /* else: Conflict was resolved by removing markers */
1292 if (merge_props_outcome
&& had_props
)
1294 SVN_ERR(svn_wc__db_read_pristine_props(&pristine_props
,
1295 wc_ctx
->db
, target_abspath
,
1296 scratch_pool
, scratch_pool
));
1298 else if (merge_props_outcome
)
1299 pristine_props
= apr_hash_make(scratch_pool
);
1303 SVN_ERR(svn_wc__db_read_props(&old_actual_props
,
1304 wc_ctx
->db
, target_abspath
,
1305 scratch_pool
, scratch_pool
));
1307 else if (pristine_props
)
1308 old_actual_props
= pristine_props
;
1310 old_actual_props
= apr_hash_make(scratch_pool
);
1313 /* Merge the properties, if requested. We merge the properties first
1314 * because the properties can affect the text (EOL style, keywords). */
1315 if (merge_props_outcome
)
1319 /* The PROPCHANGES may not have non-"normal" properties in it. If entry
1320 or wc props were allowed, then the following code would install them
1321 into the BASE and/or WORKING properties(!). */
1322 for (i
= prop_diff
->nelts
; i
--; )
1324 const svn_prop_t
*change
= &APR_ARRAY_IDX(prop_diff
, i
, svn_prop_t
);
1326 if (!svn_wc_is_normal_prop(change
->name
))
1327 return svn_error_createf(SVN_ERR_BAD_PROP_KIND
, NULL
,
1328 _("The property '%s' may not be merged "
1331 svn_dirent_local_style(target_abspath
,
1335 SVN_ERR(svn_wc__merge_props(&conflict_skel
,
1336 merge_props_outcome
,
1338 wc_ctx
->db
, target_abspath
,
1339 original_props
, pristine_props
, old_actual_props
,
1341 scratch_pool
, scratch_pool
));
1344 /* Merge the text. */
1345 SVN_ERR(svn_wc__internal_merge(&work_items
,
1347 merge_content_outcome
,
1353 left_label
, right_label
, target_label
,
1359 cancel_func
, cancel_baton
,
1360 scratch_pool
, scratch_pool
));
1362 /* If this isn't a dry run, then update the DB, run the work, and
1363 * call the conflict resolver callback. */
1368 svn_skel_t
*work_item
;
1370 SVN_ERR(svn_wc__conflict_skel_set_op_merge(conflict_skel
,
1376 SVN_ERR(svn_wc__conflict_create_markers(&work_item
,
1377 wc_ctx
->db
, target_abspath
,
1379 scratch_pool
, scratch_pool
));
1381 work_items
= svn_wc__wq_merge(work_items
, work_item
, scratch_pool
);
1384 if (new_actual_props
)
1385 SVN_ERR(svn_wc__db_op_set_props(wc_ctx
->db
, target_abspath
,
1387 svn_wc__has_magic_property(prop_diff
),
1388 conflict_skel
, work_items
,
1390 else if (conflict_skel
)
1391 SVN_ERR(svn_wc__db_op_mark_conflict(wc_ctx
->db
, target_abspath
,
1392 conflict_skel
, work_items
,
1394 else if (work_items
)
1395 SVN_ERR(svn_wc__db_wq_add(wc_ctx
->db
, target_abspath
, work_items
,
1399 SVN_ERR(svn_wc__wq_run(wc_ctx
->db
, target_abspath
,
1400 cancel_func
, cancel_baton
,
1403 if (conflict_skel
&& conflict_func
)
1405 svn_boolean_t text_conflicted
, prop_conflicted
;
1407 SVN_ERR(svn_wc__conflict_invoke_resolver(
1408 wc_ctx
->db
, target_abspath
, kind
,
1409 conflict_skel
, merge_options
,
1410 conflict_func
, conflict_baton
,
1411 cancel_func
, cancel_baton
,
1414 /* Reset *MERGE_CONTENT_OUTCOME etc. if a conflict was resolved. */
1415 SVN_ERR(svn_wc__internal_conflicted_p(
1416 &text_conflicted
, &prop_conflicted
, NULL
,
1417 wc_ctx
->db
, target_abspath
, scratch_pool
));
1418 if (*merge_props_outcome
== svn_wc_notify_state_conflicted
1419 && ! prop_conflicted
)
1420 *merge_props_outcome
= svn_wc_notify_state_merged
;
1421 if (*merge_content_outcome
== svn_wc_merge_conflict
1422 && ! text_conflicted
)
1423 *merge_content_outcome
= svn_wc_merge_merged
;
1427 return SVN_NO_ERROR
;