Index: subversion/tests/cmdline/copy_tests.py =================================================================== --- subversion/tests/cmdline/copy_tests.py (revision 936812) +++ subversion/tests/cmdline/copy_tests.py (working copy) @@ -980,9 +980,10 @@ def repos_to_wc(sbox): expected_output = svntest.actions.get_virginal_state(wc_dir, 1) expected_output.add({ - 'pi' : Item(status='A ', wc_rev='1'), + 'pi' : Item(status='A ', wc_rev='0'), }) - svntest.actions.run_and_verify_status(wc_dir, expected_output) + svntest.actions.run_and_verify_status(wc_dir, expected_output, + check_entries=False) # Revert everything and verify. svntest.actions.run_and_verify_svn(None, None, [], 'revert', '-R', wc_dir) Index: subversion/tests/cmdline/stat_tests.py =================================================================== --- subversion/tests/cmdline/stat_tests.py (revision 936812) +++ subversion/tests/cmdline/stat_tests.py (working copy) @@ -1593,7 +1593,7 @@ def status_with_tree_conflicts(sbox): [" 2 2 jrandom %s\n" % G, "D C 2 2 jrandom %s\n" % pi, " > local delete, incoming edit upon update\n", - "A + C - 1 jrandom %s\n" % rho, + "A + C - ? ? %s\n" % rho, " > local edit, incoming delete upon update\n", "! C %s\n" % tau, " > local delete, incoming delete upon update\n", Index: subversion/tests/cmdline/svntest/actions.py =================================================================== --- subversion/tests/cmdline/svntest/actions.py (revision 936812) +++ subversion/tests/cmdline/svntest/actions.py (working copy) @@ -1280,6 +1280,7 @@ def run_and_verify_commit(wc_dir_name, output_tree # This function always passes '-q' to the status command, which # suppresses the printing of any unversioned or nonexistent items. def run_and_verify_status(wc_dir_name, output_tree, + check_entries = True, singleton_handler_a = None, a_baton = None, singleton_handler_b = None, @@ -1314,7 +1315,7 @@ def run_and_verify_status(wc_dir_name, output_tree # if we have an output State, and we can/are-allowed to create an # entries-based State, then compare the two. - if output_state: + if output_state and check_entries: entries_state = wc.State.from_entries(wc_dir_name) if entries_state: tweaked = output_state.copy() Index: subversion/tests/cmdline/merge_tests.py =================================================================== --- subversion/tests/cmdline/merge_tests.py (revision 936812) +++ subversion/tests/cmdline/merge_tests.py (working copy) @@ -2161,7 +2161,7 @@ def merge_into_missing(sbox): expected_status = wc.State(F_path, { '' : Item(status=' ', wc_rev=1), 'foo' : Item(status='! ', wc_rev=2), - 'Q' : Item(status='! ', wc_rev='?'), + 'Q' : Item(status='! ', wc_rev='2'), }) expected_skip = wc.State(F_path, { 'Q' : Item(), @@ -2183,7 +2183,7 @@ def merge_into_missing(sbox): expected_status = wc.State(F_path, { '' : Item(status=' M', wc_rev=1), 'foo' : Item(status='!M', wc_rev=2), - 'Q' : Item(status='! ', wc_rev='?'), + 'Q' : Item(status='! ', wc_rev='2'), }) expected_mergeinfo_output = wc.State(F_path, { '' : Item(status=' U'), @@ -2214,9 +2214,10 @@ def merge_into_missing(sbox): expected_status.add({ 'A/B/F' : Item(status=' M', wc_rev=1), 'A/B/F/foo' : Item(status='!M', wc_rev=2), - 'A/B/F/Q' : Item(status='! ', wc_rev='?'), + 'A/B/F/Q' : Item(status='! ', wc_rev='2'), }) - svntest.actions.run_and_verify_status(wc_dir, expected_status) + svntest.actions.run_and_verify_status(wc_dir, expected_status, + check_entries=False) #---------------------------------------------------------------------- # A test for issue 1738 Index: subversion/svn/status.c =================================================================== --- subversion/svn/status.c (revision 936812) +++ subversion/svn/status.c (working copy) @@ -142,12 +142,20 @@ print_status(const char *path, if (! status->entry) working_rev = ""; - else if (! SVN_IS_VALID_REVNUM(status->entry->revision)) - working_rev = " ? "; + else if (! SVN_IS_VALID_REVNUM(status->revision)) + { + if (status->copied) + working_rev = "-"; + else if (text_status == svn_wc_status_added + || text_status == svn_wc_status_replaced) + working_rev = "0"; + else + working_rev = " ? "; + } else if (status->copied) working_rev = "-"; else - working_rev = apr_psprintf(pool, "%ld", status->entry->revision); + working_rev = apr_psprintf(pool, "%ld", status->revision); if (status->repos_text_status != svn_wc_status_none || status->repos_prop_status != svn_wc_status_none) @@ -183,15 +191,15 @@ print_status(const char *path, const char *commit_rev; const char *commit_author; - if (status->entry && SVN_IS_VALID_REVNUM(status->entry->cmt_rev)) - commit_rev = apr_psprintf(pool, "%ld", status->entry->cmt_rev); + if (SVN_IS_VALID_REVNUM(status->changed_rev)) + commit_rev = apr_psprintf(pool, "%ld", status->changed_rev); else if (status->entry) commit_rev = " ? "; else commit_rev = ""; - if (status->entry && status->entry->cmt_author) - commit_author = status->entry->cmt_author; + if (status->changed_author) + commit_author = status->changed_author; else if (status->entry) commit_author = " ? "; else @@ -277,17 +285,17 @@ svn_cl__print_status_xml(const char *path, apr_hash_set(att_hash, "file-external", APR_HASH_KEY_STRING, "true"); if (status->entry && ! status->entry->copied) apr_hash_set(att_hash, "revision", APR_HASH_KEY_STRING, - apr_psprintf(pool, "%ld", status->entry->revision)); + apr_psprintf(pool, "%ld", status->revision)); if (status->tree_conflict) apr_hash_set(att_hash, "tree-conflicted", APR_HASH_KEY_STRING, "true"); svn_xml_make_open_tag_hash(&sb, pool, svn_xml_normal, "wc-status", att_hash); - if (status->entry && SVN_IS_VALID_REVNUM(status->entry->cmt_rev)) + if (SVN_IS_VALID_REVNUM(status->changed_rev)) { - svn_cl__print_xml_commit(&sb, status->entry->cmt_rev, - status->entry->cmt_author, + svn_cl__print_xml_commit(&sb, status->changed_rev, + status->changed_author, svn_time_to_cstring(status->entry->cmt_date, pool), pool); Index: subversion/include/svn_wc.h =================================================================== --- subversion/include/svn_wc.h (revision 936812) +++ subversion/include/svn_wc.h (working copy) @@ -3617,6 +3617,21 @@ typedef struct svn_wc_status3_t */ enum svn_wc_status_kind pristine_prop_status; + /** Base revision. + * @since New in 1.7 + */ + svn_revnum_t revision; + + /** Last revision this was changed + * @since New in 1.7 + */ + svn_revnum_t changed_rev; + + /** Last commit author of this item + * @since New in 1.7 + */ + const char *changed_author; + /* NOTE! Please update svn_wc_dup_status3() when adding new fields here. */ } svn_wc_status3_t; Index: subversion/libsvn_wc/status.c =================================================================== --- subversion/libsvn_wc/status.c (revision 936812) +++ subversion/libsvn_wc/status.c (working copy) @@ -297,6 +297,11 @@ assemble_status(svn_wc_status3_t **status, svn_boolean_t switched_p = FALSE; const svn_wc_conflict_description2_t *tree_conflict; svn_boolean_t file_external_p = FALSE; + svn_wc__db_status_t db_status; + svn_revnum_t revision; + svn_revnum_t changed_rev; + const char *changed_author; + svn_boolean_t base_shadowed; #ifdef HAVE_SYMLINK svn_boolean_t wc_special; #endif /* HAVE_SYMLINK */ @@ -376,6 +381,9 @@ assemble_status(svn_wc_status3_t **status, stat->repos_lock = repos_lock; stat->url = NULL; + stat->revision = SVN_INVALID_REVNUM; + stat->changed_rev = SVN_INVALID_REVNUM; + stat->changed_author = NULL; stat->ood_last_cmt_rev = SVN_INVALID_REVNUM; stat->ood_last_cmt_date = 0; stat->ood_kind = svn_node_none; @@ -385,6 +393,51 @@ assemble_status(svn_wc_status3_t **status, return SVN_NO_ERROR; } + SVN_ERR(svn_wc__db_read_info(&db_status, NULL, &revision, NULL, NULL, NULL, + &changed_rev, NULL, &changed_author, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, &base_shadowed, NULL, + NULL, db, local_abspath, result_pool, + scratch_pool)); + + if (db_status == svn_wc__db_status_deleted) + { + const char *work_del_abspath = NULL; + const char *base_del_abspath = NULL; + const char *op_root_abspath; + svn_boolean_t base_replaced; + + SVN_ERR(svn_wc__db_scan_deletion(&base_del_abspath, &base_replaced, + NULL, &work_del_abspath, db, + local_abspath, scratch_pool, + result_pool)); + if (work_del_abspath) + op_root_abspath = work_del_abspath; + else + op_root_abspath = base_del_abspath; + + SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, &revision, NULL, + NULL, NULL, &changed_rev, + NULL, &changed_author, NULL, + NULL, NULL, NULL, NULL, NULL, + db, op_root_abspath, + result_pool, scratch_pool)); + } + else if (base_shadowed) + { + SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, &revision, NULL, NULL, NULL, + &changed_rev, NULL, &changed_author, + NULL, NULL, NULL, NULL, NULL, NULL, db, + local_abspath, result_pool, + scratch_pool)); + } + else if (db_status == svn_wc__db_status_added) + { + revision = SVN_INVALID_REVNUM; + changed_rev = SVN_INVALID_REVNUM; + changed_author = NULL; + } + /* Someone either deleted the administrative directory in the versioned subdir, or deleted the directory altogether and created a new one. In any case, what is currently there is in the way. @@ -606,6 +659,9 @@ assemble_status(svn_wc_status3_t **status, stat->copied = entry->copied; stat->repos_lock = repos_lock; stat->url = (entry->url ? entry->url : NULL); + stat->revision = revision; + stat->changed_rev = changed_rev; + stat->changed_author = changed_author; stat->ood_last_cmt_rev = SVN_INVALID_REVNUM; stat->ood_last_cmt_date = 0; stat->ood_kind = svn_node_none; @@ -2457,6 +2513,9 @@ svn_wc_dup_status3(const svn_wc_status3_t *orig_st if (orig_stat->url) new_stat->url = apr_pstrdup(pool, orig_stat->url); + if (orig_stat->changed_author) + new_stat->changed_author = apr_pstrdup(pool, orig_stat->changed_author); + if (orig_stat->ood_last_cmt_author) new_stat->ood_last_cmt_author = apr_pstrdup(pool, orig_stat->ood_last_cmt_author);