📄 diff.c
字号:
/* Easy out: if we have no adm_access for the parent directory, then this portion of the tree-delta "patch" must be inapplicable. Send a 'missing' state back; the repos-diff editor should then send a 'skip' notification. */ if (! adm_access) { if (state) *state = svn_wc_notify_state_missing; return SVN_NO_ERROR; } SVN_ERR(svn_io_check_path(mine, &kind, subpool)); switch (kind) { case svn_node_file: svn_path_split(mine, &parent_path, NULL, subpool); SVN_ERR(svn_wc_adm_retrieve(&parent_access, adm_access, parent_path, subpool)); { /* Passing NULL for the notify_func and notify_baton because * repos_diff.c:delete_item will do it for us. */ err = svn_client__wc_delete(mine, parent_access, merge_b->force, merge_b->dry_run, NULL, NULL, merge_b->ctx, subpool); } if (err && state) { *state = svn_wc_notify_state_obstructed; svn_error_clear(err); } else if (state) { *state = svn_wc_notify_state_changed; } break; case svn_node_dir: if (state) *state = svn_wc_notify_state_obstructed; break; case svn_node_none: /* file is already non-existent, this is a no-op. */ if (state) *state = svn_wc_notify_state_missing; break; default: if (state) *state = svn_wc_notify_state_unknown; break; } svn_pool_destroy(subpool); return SVN_NO_ERROR;}/* A svn_wc_diff_callbacks2_t function. */static svn_error_t *merge_dir_added(svn_wc_adm_access_t *adm_access, svn_wc_notify_state_t *state, const char *path, svn_revnum_t rev, void *baton){ struct merge_cmd_baton *merge_b = baton; apr_pool_t *subpool = svn_pool_create(merge_b->pool); svn_node_kind_t kind; const svn_wc_entry_t *entry; const char *copyfrom_url, *child; /* Easy out: if we have no adm_access for the parent directory, then this portion of the tree-delta "patch" must be inapplicable. Send a 'missing' state back; the repos-diff editor should then send a 'skip' notification. */ if (! adm_access) { if (state) { if (merge_b->dry_run && merge_b->added_path && svn_path_is_child(merge_b->added_path, path, subpool)) *state = svn_wc_notify_state_changed; else *state = svn_wc_notify_state_missing; } return SVN_NO_ERROR; } child = svn_path_is_child(merge_b->target, path, subpool); assert(child != NULL); copyfrom_url = svn_path_url_add_component(merge_b->url, child, subpool); SVN_ERR(check_scheme_match(adm_access, copyfrom_url)); SVN_ERR(svn_io_check_path(path, &kind, subpool)); switch (kind) { case svn_node_none: SVN_ERR(svn_wc_entry(&entry, path, adm_access, FALSE, subpool)); if (entry && entry->schedule != svn_wc_schedule_delete) { /* Versioned but missing */ if (state) *state = svn_wc_notify_state_obstructed; return SVN_NO_ERROR; } if (! merge_b->dry_run) { SVN_ERR(svn_io_make_dir_recursively(path, subpool)); SVN_ERR(svn_wc_add2(path, adm_access, copyfrom_url, rev, merge_b->ctx->cancel_func, merge_b->ctx->cancel_baton, NULL, NULL, /* don't pass notification func! */ subpool)); } if (merge_b->dry_run) merge_b->added_path = apr_pstrdup(merge_b->pool, path); if (state) *state = svn_wc_notify_state_changed; break; case svn_node_dir: /* Adding an unversioned directory doesn't destroy data */ SVN_ERR(svn_wc_entry(&entry, path, adm_access, TRUE, subpool)); if (! entry || (entry && entry->schedule == svn_wc_schedule_delete)) { if (!merge_b->dry_run) SVN_ERR(svn_wc_add2(path, adm_access, copyfrom_url, rev, merge_b->ctx->cancel_func, merge_b->ctx->cancel_baton, NULL, NULL, /* no notification func! */ subpool)); if (merge_b->dry_run) merge_b->added_path = apr_pstrdup(merge_b->pool, path); if (state) *state = svn_wc_notify_state_changed; } else if (state) { if (dry_run_deleted_p(merge_b, path)) *state = svn_wc_notify_state_changed; else *state = svn_wc_notify_state_obstructed; } break; case svn_node_file: if (merge_b->dry_run) merge_b->added_path = NULL; if (state) { SVN_ERR(svn_wc_entry(&entry, path, adm_access, FALSE, subpool)); if (entry && dry_run_deleted_p(merge_b, path)) /* ### TODO: Retain record of this dir being added to ### avoid problems from subsequent edits which try to ### add children. */ *state = svn_wc_notify_state_changed; else *state = svn_wc_notify_state_obstructed; } break; default: if (merge_b->dry_run) merge_b->added_path = NULL; if (state) *state = svn_wc_notify_state_unknown; break; } svn_pool_destroy(subpool); return SVN_NO_ERROR;}/* Struct used for as the baton for calling merge_delete_notify_func(). */typedef struct merge_delete_notify_baton_t{ svn_client_ctx_t *ctx; /* path to skip */ const char *path_skip;} merge_delete_notify_baton_t;/* Notify callback function that wraps the normal callback * function to remove a notification that will be sent twice * and set the proper action. */static voidmerge_delete_notify_func(void *baton, const svn_wc_notify_t *notify, apr_pool_t *pool){ merge_delete_notify_baton_t *mdb = baton; svn_wc_notify_t *new_notify; /* Skip the notification for the path we called svn_client__wc_delete() with, * because it will be outputed by repos_diff.c:delete_item */ if (strcmp(notify->path, mdb->path_skip) == 0) return; /* svn_client__wc_delete() is written primarily for scheduling operations not * update operations. Since merges are update operations we need to alter * the delete notification to show as an update not a schedule so alter * the action. */ if (notify->action == svn_wc_notify_delete) { /* We need to copy it since notify is const. */ new_notify = svn_wc_dup_notify(notify, pool); new_notify->action = svn_wc_notify_update_delete; notify = new_notify; } if (mdb->ctx->notify_func2) (*mdb->ctx->notify_func2)(mdb->ctx->notify_baton2, notify, pool);}/* A svn_wc_diff_callbacks2_t function. */static svn_error_t *merge_dir_deleted(svn_wc_adm_access_t *adm_access, svn_wc_notify_state_t *state, const char *path, void *baton){ struct merge_cmd_baton *merge_b = baton; apr_pool_t *subpool = svn_pool_create(merge_b->pool); svn_node_kind_t kind; svn_wc_adm_access_t *parent_access; const char *parent_path; svn_error_t *err; /* Easy out: if we have no adm_access for the parent directory, then this portion of the tree-delta "patch" must be inapplicable. Send a 'missing' state back; the repos-diff editor should then send a 'skip' notification. */ if (! adm_access) { if (state) *state = svn_wc_notify_state_missing; return SVN_NO_ERROR; } SVN_ERR(svn_io_check_path(path, &kind, subpool)); switch (kind) { case svn_node_dir: { merge_delete_notify_baton_t mdb; mdb.ctx = merge_b->ctx; mdb.path_skip = path; svn_path_split(path, &parent_path, NULL, subpool); SVN_ERR(svn_wc_adm_retrieve(&parent_access, adm_access, parent_path, subpool)); err = svn_client__wc_delete(path, parent_access, merge_b->force, merge_b->dry_run, merge_delete_notify_func, &mdb, merge_b->ctx, subpool); if (err && state) { *state = svn_wc_notify_state_obstructed; svn_error_clear(err); } else if (state) { *state = svn_wc_notify_state_changed; } } break; case svn_node_file: if (state) *state = svn_wc_notify_state_obstructed; break; case svn_node_none: /* dir is already non-existent, this is a no-op. */ if (state) *state = svn_wc_notify_state_missing; break; default: if (state) *state = svn_wc_notify_state_unknown; break; } svn_pool_destroy(subpool); return SVN_NO_ERROR;} /* The main callback table for 'svn merge'. */static const svn_wc_diff_callbacks2_tmerge_callbacks = { merge_file_changed, merge_file_added, merge_file_deleted, merge_dir_added, merge_dir_deleted, merge_props_changed };/*-----------------------------------------------------------------------*//** The logic behind 'svn diff' and 'svn merge'. *//* Hi! This is a comment left behind by Karl, and Ben is too afraid to erase it at this time, because he's not fully confident that all this knowledge has been grokked yet. There are five cases: 1. path is not an URL and start_revision != end_revision 2. path is not an URL and start_revision == end_revision 3. path is an URL and start_revision != end_revision 4. path is an URL and start_revision == end_revision 5. path is not an URL and no revisions given With only one distinct revision the working copy provides the other. When path is an URL there is no working copy. Thus 1: compare repository versions for URL coresponding to working copy 2: compare working copy against repository version 3: compare repository versions for URL 4: nothing to do. 5: compare working copy against text-base Case 4 is not as stupid as it looks, for example it may occur if the user specifies two dates that resolve to the same revision. *//* Helper function: given a working-copy PATH, return its associated url in *URL, allocated in POOL. If PATH is *already* a URL, that's fine, just set *URL = PATH. */static svn_error_t *convert_to_url(const char **url, const char *path, apr_pool_t *pool){ svn_wc_adm_access_t *adm_access; /* ### FIXME local */ const svn_wc_entry_t *entry; if (svn_path_is_url(path)) { *url = path; return SVN_NO_ERROR; } /* ### This may not be a good idea, see issue 880 */ SVN_ERR(svn_wc_adm_probe_open3(&adm_access, NULL, path, FALSE, 0, NULL, NULL, pool)); SVN_ERR(svn_wc_entry(&entry, path, adm_access, FALSE, pool)); SVN_ERR(svn_wc_adm_close(adm_access)); if (! entry) return svn_error_createf(SVN_ERR_UNVERSIONED_RESOURCE, NULL, _("'%s' is not under version control"), svn_path_local_style(path, pool)); if (entry->url) *url = apr_pstrdup(pool, entry->url); else *url = apr_pstrdup(pool, entry->copyfrom_url); return SVN_NO_ERROR;}/** Helper structure: for passing around the diff parameters */struct diff_parameters{ /* Additional parameters for diff tool */ const apr_array_header_t *options;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -