# # # patch "cmd_ws_commit.cc" # from [b10002d34577ef04e2befc0791b030710ef51813] # to [58880d5679bcbf2840bef2d8748c5018726d0ba2] # # patch "options_list.hh" # from [78fbe7c5728513ee672b75d6dcefbc2f508ba915] # to [21b9374978589e4f4182cb5124a5578b806acf4a] # # patch "work.cc" # from [0261cdf7dbc3baed0cdfc0e75a3a858f64eefa97] # to [05beca559be514b2724cfc1abbed7ffdbc5667d0] # ============================================================ --- cmd_ws_commit.cc b10002d34577ef04e2befc0791b030710ef51813 +++ cmd_ws_commit.cc 58880d5679bcbf2840bef2d8748c5018726d0ba2 @@ -42,13 +42,17 @@ static void using boost::shared_ptr; static void -revision_summary(revision_t const & rev, branch_name const & branch, utf8 & summary) +revision_summary(revision_t const & rev, + branch_name const & branch, branch_name const & newbranch, + utf8 & summary) { string out; // We intentionally do not collapse the final \n into the format // strings here, for consistency with newline conventions used by most // other format strings. out += (F("Current branch: %s") % branch).str() += '\n'; + if (!newbranch().empty() && branch != newbranch) + out += (F("New branch: %s") % newbranch).str() += '\n'; for (edge_map::const_iterator i = rev.edges.begin(); i != rev.edges.end(); ++i) { revision_id parent = edge_old_revision(*i); @@ -104,14 +108,15 @@ get_log_message_interactively(lua_hooks get_log_message_interactively(lua_hooks & lua, workspace & work, revision_t const & cs, branch_name const & branchname, + branch_name const & newbranchname, utf8 & log_message) { utf8 summary; - revision_summary(cs, branchname, summary); + revision_summary(cs, branchname, newbranchname, summary); external summary_external; utf8_to_system_best_effort(summary, summary_external); - utf8 branch_comment = utf8((F("branch \"%s\"\n\n") % branchname).str()); + utf8 branch_comment = utf8((F("branch \"%s\"\n\n") % newbranchname).str()); external branch_external; utf8_to_system_best_effort(branch_comment, branch_external); @@ -589,7 +594,7 @@ CMD(status, "status", "", CMD_REF(inform make_restricted_revision(old_rosters, new_roster, mask, rev); utf8 summary; - revision_summary(rev, app.opts.branchname, summary); + revision_summary(rev, app.opts.branchname, app.opts.newbranchname, summary); external summary_external; utf8_to_system_best_effort(summary, summary_external); cout << summary_external; @@ -1083,74 +1088,90 @@ CMD(branch, "branch", "", CMD_REF(worksp workspace work(app); project_t project(db); + // Cache the new branch, making it the same as the current if not already + // present in _MTN/options. This simplifies a number of tests below. + branch_name cache_current_newbranch(app.opts.newbranchname); + if (cache_current_newbranch().empty()) + cache_current_newbranch = app.opts.branchname; + if (args.size() == 0) { - cout << app.opts.branchname << '\n'; + if (cache_current_newbranch == app.opts.branchname) + cout << app.opts.branchname << '\n'; + else + cout << app.opts.branchname << " -> " << app.opts.newbranchname << '\n'; return; } - branch_name branch(idx(args, 0)()); + branch_name newbranch(idx(args, 0)()); - E(branch != app.opts.branchname, - F("branch of the current workspace is already set to %s") % branch); + E(newbranch != cache_current_newbranch, + F("branch of the current workspace is already set to %s") % newbranch); - std::set branches; - project.get_branch_list(branches); - - bool existing_branch = false; - for (set::const_iterator i = branches.begin(); - i != branches.end(); ++i) + if (app.opts.branchname == newbranch) { - if (branch == *i) - { + P(F("moving back to the original branch %s") % newbranch); + } + else + { + std::set branches; + project.get_branch_list(branches); + + bool existing_branch = false; + for (set::const_iterator i = branches.begin(); + i != branches.end(); ++i) + { + if (newbranch == *i) + { existing_branch = true; break; - } - } + } + } - parent_map parents; - work.get_parent_rosters(db, parents); + parent_map parents; + work.get_parent_rosters(db, parents); - set parent_revisions; - for (parent_map::iterator i = parents.begin(); - i != parents.end(); i++) - { - if (!null_id(i->first)) - parent_revisions.insert(i->first); - } + set parent_revisions; + for (parent_map::iterator i = parents.begin(); + i != parents.end(); i++) + { + if (!null_id(i->first)) + parent_revisions.insert(i->first); + } - // if this is an existing branch (and we're not inside a freshly created - // workspace), check if this branch's head revs and the current workspace - // parent share any common ancestors, if not warn the user about it - if (existing_branch && parent_revisions.size() > 0) - { - set branch_heads, revs, common_ancestors; - project.get_branch_heads(branch, branch_heads, - app.opts.ignore_suspend_certs); + // if this is an existing branch (and we're not inside a freshly created + // workspace), check if this branch's head revs and the current workspace + // parent share any common ancestors, if not warn the user about it + if (existing_branch && parent_revisions.size() > 0) + { + set branch_heads, revs, common_ancestors; + project.get_branch_heads(newbranch, branch_heads, + app.opts.ignore_suspend_certs); - set_union(parent_revisions.begin(), parent_revisions.end(), - branch_heads.begin(), branch_heads.end(), - inserter(revs, revs.begin())); + set_union(parent_revisions.begin(), parent_revisions.end(), + branch_heads.begin(), branch_heads.end(), + inserter(revs, revs.begin())); - db.get_common_ancestors(revs, common_ancestors); + db.get_common_ancestors(revs, common_ancestors); - if (common_ancestors.size() == 0) - { - W(F("the new branch has no common ancestors with the current branch;\n" - "any next commit could therefor create two unmergable heads in\n" - "%s") % branch); - } + if (common_ancestors.size() == 0) + { + W(F("the new branch has no common ancestors with the current branch;\n" + "any next commit could therefor create two unmergable heads in\n" + "%s") % newbranch); + } + } + + if (existing_branch) + P(F("next commit will use the existing branch %s") % newbranch); + else + P(F("next commit will use the new branch %s") % newbranch); } - app.opts.branchname = branch; + app.opts.newbranchname = newbranch; // the workspace should remember the branch we just committed to. work.set_ws_options(app.opts, true); - - if (existing_branch) - P(F("next commit will use the existing branch %s") % branch); - else - P(F("next commit will use the new branch %s") % branch); } CMD(commit, "commit", "ci", CMD_REF(workspace), N_("[PATH]..."), @@ -1204,8 +1225,12 @@ CMD(commit, "commit", "ci", CMD_REF(work // So in the end only if no branch is set in _MTN/options we try to detect a // valid one here by looking at the ancestor revisions of the workspace. // - if (app.opts.branchname().empty()) + if (!app.opts.newbranchname().empty()) { + app.opts.branchname = app.opts.newbranchname; + } + else if (app.opts.branchname().empty()) + { W(F("workspace has no branch name set; trying to detect one " "by looking at the parent revisions")); @@ -1214,7 +1239,8 @@ CMD(commit, "commit", "ci", CMD_REF(work i != restricted_rev.edges.end(); i++) { - // this will prefer --branch if it was set + // this will prefer --branch if it was set, but since 'commit' + // doesn't take the --branch, this isn't an issue. guess_branch(app.opts, project, edge_old_revision(i), bn_candidate); N(branchname() == "" || branchname == bn_candidate, @@ -1250,7 +1276,8 @@ CMD(commit, "commit", "ci", CMD_REF(work { // This call handles _MTN/log. get_log_message_interactively(app.lua, work, restricted_rev, - app.opts.branchname, log_message); + app.opts.branchname, app.opts.newbranchname, + log_message); // We only check for empty log messages when the user entered them // interactively. Consensus was that if someone wanted to explicitly ============================================================ --- options_list.hh 78fbe7c5728513ee672b75d6dcefbc2f508ba915 +++ options_list.hh 21b9374978589e4f4182cb5124a5578b806acf4a @@ -117,6 +117,12 @@ OPTION(branch, branch, true, "branch,b", } #endif +// This is a hidden option, only meant to be used internally by the branch +// and commit commands. The important thing is that it also ends up in the +// workspace options file. -- Richard Levitte +OPTVAR(branch, branch_name, newbranchname, ) + + OPT(brief, "brief", bool, false, gettext_noop("print a brief version of the normal output")) #ifdef option_bodies ============================================================ --- work.cc 0261cdf7dbc3baed0cdfc0e75a3a858f64eefa97 +++ work.cc 05beca559be514b2724cfc1abbed7ffdbc5667d0 @@ -364,6 +364,7 @@ read_options_file(any_path const & optsp read_options_file(any_path const & optspath, system_path & database_option, branch_name & branch_option, + branch_name & newbranch_option, rsa_keypair_id & key_option, system_path & keydir_option) { @@ -392,6 +393,8 @@ read_options_file(any_path const & optsp database_option = system_path(val); else if (opt == "branch") branch_option = branch_name(val); + else if (opt == "newbranch") + newbranch_option = branch_name(val); else if (opt == "key") internalize_rsa_keypair_id(utf8(val), key_option); else if (opt == "keydir") @@ -406,6 +409,7 @@ write_options_file(bookkeeping_path cons write_options_file(bookkeeping_path const & optspath, system_path const & database_option, branch_name const & branch_option, + branch_name const & newbranch_option, rsa_keypair_id const & key_option, system_path const & keydir_option) { @@ -414,6 +418,8 @@ write_options_file(bookkeeping_path cons st.push_str_pair(symbol("database"), database_option.as_internal()); if (!branch_option().empty()) st.push_str_pair(symbol("branch"), branch_option()); + if (!newbranch_option().empty() && newbranch_option != branch_option) + st.push_str_pair(symbol("newbranch"), newbranch_option()); if (!key_option().empty()) { utf8 key; @@ -443,13 +449,15 @@ workspace::get_ws_options(options & opts system_path database_option; branch_name branch_option; + branch_name newbranch_option; rsa_keypair_id key_option; system_path keydir_option; bookkeeping_path o_path; get_options_path(o_path); read_options_file(o_path, - database_option, branch_option, key_option, keydir_option); + database_option, branch_option, newbranch_option, + key_option, keydir_option); // Workspace options are not to override the command line. if (!opts.dbname_given) @@ -469,6 +477,11 @@ workspace::get_ws_options(options & opts branch_is_sticky = true; } + if (opts.newbranchname().empty() && !newbranch_option().empty()) + { + opts.newbranchname = newbranch_option; + } + L(FL("branch name is '%s'") % opts.branchname); if (!opts.key_given) @@ -480,6 +493,7 @@ workspace::get_database_option(system_pa system_path & database_option) { branch_name branch_option; + branch_name newbranch_option; rsa_keypair_id key_option; system_path keydir_option; @@ -487,7 +501,8 @@ workspace::get_database_option(system_pa / bookkeeping_root_component / options_file_name); read_options_file(o_path, - database_option, branch_option, key_option, keydir_option); + database_option, branch_option, newbranch_option, + key_option, keydir_option); } void @@ -502,12 +517,14 @@ workspace::set_ws_options(options const // as is in _MTN/options, not write out an empty option. system_path database_option; branch_name branch_option; + branch_name newbranch_option; rsa_keypair_id key_option; system_path keydir_option; if (file_exists(o_path)) read_options_file(o_path, - database_option, branch_option, key_option, keydir_option); + database_option, branch_option, newbranch_option, + key_option, keydir_option); // FIXME: we should do more checks here, f.e. if this is a valid sqlite // file and if it contains the correct identifier, but these checks would @@ -522,11 +539,14 @@ workspace::set_ws_options(options const if ((branch_is_sticky || workspace::branch_is_sticky) && !opts.branchname().empty()) branch_option = opts.branchname; + if (!opts.newbranchname().empty()) + newbranch_option = opts.newbranchname; if (opts.key_given) key_option = opts.signing_key; write_options_file(o_path, - database_option, branch_option, key_option, keydir_option); + database_option, branch_option, newbranch_option, + key_option, keydir_option); } void @@ -539,15 +559,19 @@ workspace::print_ws_option(utf8 const & system_path database_option; branch_name branch_option; + branch_name newbranch_option; rsa_keypair_id key_option; system_path keydir_option; read_options_file(o_path, - database_option, branch_option, key_option, keydir_option); + database_option, branch_option, newbranch_option, + key_option, keydir_option); if (opt() == "database") output << database_option << '\n'; else if (opt() == "branch") output << branch_option << '\n'; + else if (opt() == "newbranch") + output << newbranch_option << '\n'; else if (opt() == "key") output << key_option << '\n'; else if (opt() == "keydir")