Logo Search packages:      
Sourcecode: bazaar version File versions

merge.c

/* merge.c
 *
 ****************************************************************
 * Copyright (C) 2003 Tom Lord
 *
 * See the file "COPYING" for further information about
 * the copyright and warranty status of this work.
 */


#include "config-options.h"
#include "po/gettext.h"
#include "hackerlab/cmd/main.h"
#include "hackerlab/fs/file-names.h"
#include "libarch/namespace.h"
#include "libarch/project-tree.h"
#include "libarch/merge.h"
#include "commands/cmd.h"
#include "commands/cmdutils.h"
#include "commands/merge.h"
#include "commands/version.h"



static t_uchar * usage = N_("[options] [FROM]");

#define OPTS(OP) \
  OP (opt_help_msg, "h", "help", 0, \
      N_("Display a help message and exit.")) \
  OP (opt_long_help, "H", 0, 0, \
      N_("Display a verbose help message and exit.")) \
  OP (opt_version, "V", "version", 0, \
      N_("Display a release identifier string\n" \
      "and exit.")) \
  OP (opt_archive, "A", "archive", 1, \
      N_("Override tree archive")) \
  OP (opt_changes, "c", "changes OUTPUT", 1, \
      N_("Generate but don't apply the changeset.")) \
  OP (opt_reference, "r", "reference VERSION", 1 , \
      N_("Set reference version (default: project tree version)")) \
  OP (opt_show_points, 0, "show-merge-points", 0, \
      N_("Calculate the trees to use for merging, show their ids and exit.")) \
  OP (opt_star, 0, "star-merge", 0, \
      N_("Use the more restrictive star merge algorithm for choosing the common ancestor")) \
  OP (opt_trace, 0, "trace", 0, \
      N_("Trace the selection of the merge points.")) \
  OP (opt_two_way, 0, "two-way", 0, \
      N_("Perform a 2-way merge.")) \
  OP (opt_three_way, "t", "three-way", 0, \
      N_("(Deprecated - now default) Perform a 3-way merge.")) \
  OP (opt_dir, "d", "dir DIR", 1, \
      N_("Operate on project tree in DIR (default `.')")) \
  OP (opt_unescaped, 0, "unescaped", 0, \
      N_("show filenames in unescaped form"))


t_uchar arch_cmd_merge_help[] = N_("merge from another branch\n"

                                      "Merge changes from FROM into the project tree, considering common\n"
                                      "ancestry from the project tree reference version, REFERENCE (which\n"
                                      "defaults to the tree version of the project tree).\n"
                                      "If FROM is not given, it defaults to the tree revision.\n"
                                      "\n"
                              "The --star-merge option is for use in situations where the pattern\n"
                              "of merges between branches is strictly a star. If you desire standard\n"
                              "external rejection hunks, you should use --star-merge --two-way.\n"
                              "\n"
                              "By default, merge will perform a three way merge, using any of the\n"
                              "'best' common ancestors available. When used in a star development\n"
                              "model, the results will be the same as with --star-merge. However\n"
                              "when used in a mesh model, where teams of developers are collaborating\n"
                              "with each other, the chosen common ancestor will be the closest commont\n"
                              "text, reducing spurious conflicts.\n"
                                      "\n"
                                      "FROM indicates a revision (it may be specified as a version name,\n"
                                      "indicating the latest revision in that version).\n"
                                      "\n"
                                      "TREE is the project tree into which the merge will occur.\n"
                                      "\n"
                              "The mesh or graph algorithm details:\n"
                              "merge works by computing the closest common ancestor. This is defined\n"
                              "as the common ancestor that is reachable in a minimal number of hops from\n"
                              "Both FROM and TREE. When multiple ancestors are reachable in the same\n"
                              "number of hops, only ancestors with no children reachable in the same\n"
                              "number of hops are chosen. If there are multiple ancestors left to choose\n"
                              "from, an arbitrary one is chosen.\n"
                              "This is optimised for diff3 merges, use of --two-way is NOT RECOMMENDED\n"
                              "without also specifying --star-merge.\n"
                              "\n"
                              "The --star-merge option details:\n"
                                      "Star-merge works by computing the most recent ANCESTOR revision of\n"
                                      "REFERENCE and FROM and then applying the changeset:\n"
                                      "\n"
                                      "         delta (ANCESTOR, FROM)\n"
                                      "\n"
                                      "to TREE.\n"
                                      "\n"
                                      "The \"most recent ancestor\" is defined as follows:\n"
                                      "\n"
                                      "MAYBE_ANCESTOR_1 is defined as the highest patch level of FROM in REFERENCE\n"
                                      "for which both TREE and FROM have a patch log. In other words, it is the latest\n"
                                      "REFERENCE revision of FROM's version already merged into TREE.\n"
                                      "\n"
                                      "MAYBE_ANCESTOR_2 is defined as the highest patch level in REFERENCE for\n"
                                      "which both FROM and REFERENCE have a patch log.  In other words, it is\n"
                                      "the latest revision of REFERENCE already merged into FROM.\n"
                                      "\n"
                                      "MAYBE_ANCESTOR_2, if it is not \"nil\", was merged into FROM at some revision\n"
                                      "of FROM's version, which we can call LAST_MERGE_INTO_FROM.\n"
                                      "\n"
                                      "If both MAYBE_ANCESTOR_1 or MAYBE_ANCESTOR_2 are nil, star-merge can do\n"
                                      "nothing.\n"
                                      "\n"
                                      "If just one of MAYBE_ANCESTOR_1 is MAYBE_ANCESTOR_2 is not nil, then that\n"
                                      "non-nil value is ANCESTOR.\n"
                                      "\n"
                                      "If both MAYBE_ANCESTOR_1 and MAYBE_ANCESTOR_2 are not nil, then\n"
                                      "LAST_MERGE_INTO_FROM and MAYBE_ANCESTOR_1 are compared (both are revisions in\n"
                                      "FROM's version). If MAYBE_ANCESTOR_1 is the later revision, then\n"
                                      "MAYBE_ANCESTOR_1 is ANCESTOR, otherwise, MAYBE_ANCESTOR_2 is ANCESTOR.\n");

enum options
{
  OPTS (OPT_ENUM)
};

static struct opt_desc opts[] =
{
  OPTS (OPT_DESC)
    {-1, 0, 0, 0, 0}
};



int
arch_cmd_merge (t_uchar * program_name, int argc, char * argv[])
{
  int o;
  struct opt_parsed * option;
  t_uchar * default_archive = 0;
  int exit_status = 2;
  t_uchar * changeset = 0;
  t_uchar * reference = 0;
  t_uchar * dir = 0;
  int two_way = 0;
  int merge_points_only = 0;
  int graph_merge = 1;
  int trace_merge = 0;
  int escape_classes = arch_escape_classes;

  default_archive = 0;

  safe_buffer_fd (1, 0, O_WRONLY, 0);

  option = 0;

  while (1)
    {
      o = opt_standard (lim_use_must_malloc, &option, opts, &argc, argv, program_name, usage, libarch_version_string, arch_cmd_merge_help, opt_help_msg, opt_long_help, opt_version);
      if (o == opt_none)
        break;
      switch (o)
        {
        default:
          safe_printfmt (2, "unhandled option `%s'\n", option->opt_string);
          panic ("internal error parsing arguments");

        usage_error:
          opt_usage (2, argv[0], program_name, usage, 1);
          exit (1);

          /* bogus_arg: */
          safe_printfmt (2, "ill-formed argument for `%s' (`%s')\n", option->opt_string, option->arg_string);
          goto usage_error;

        case opt_archive:
          {
            lim_free (0, default_archive);
            default_archive = str_save (0, option->arg_string);
            break;
          }

        case opt_changes:
          {
            lim_free (0, changeset);
            changeset = str_save (0, option->arg_string);
            break;
          }

        case opt_reference:
          {
            lim_free (0, reference);
            reference = str_save (0, option->arg_string);
            break;
          }

        case opt_two_way:
          {
            two_way = 1;
            break;
          }
      
      case opt_show_points:
        {
          merge_points_only = 1;
          break;
        }

      case opt_star:
        {
          graph_merge = 0;
          break;
        }
      
      case opt_trace:
        {
          trace_merge = 1;
          break;
        }
      
      case opt_three_way:
        {
          safe_printfmt(2, _("Please do not use -t or --three-way : they are now the default\n"));
          exit (2);
          break;
        }

        case opt_dir:
          {
            lim_free (0, dir);
            dir = str_save (0, option->arg_string);
            break;
          }
        
        case opt_unescaped:
          {
            escape_classes = 0;
            break;
          }
        }
    }

  if (argc > 2)
    goto usage_error;

  {
    t_uchar * from_spec = 0;
    t_uchar * from_archive = 0;
    struct arch_archive * from_arch = 0;
    t_uchar * from_revision = 0;
    t_uchar * to_archive = 0;
    t_uchar * to_version = 0;
    t_uchar * cache_dir = 0;
    arch_project_tree_t tree;

    arch_project_tree_init (&tree, dir);
    if (!tree.root)
      {
        safe_printfmt (2, "%s: not within a project tree (%s)\n", argv[0], dir);
        exit (2);
      }

    if (!reference)
      {
        reference = str_save (0, tree.fqversion);
        if (!reference)
          {
            safe_printfmt (2, "%s: project tree has no default version (%s)\n", argv[0], tree.root);
            exit (2);
          }
      }

    if (!arch_valid_package_name (reference, arch_maybe_archive, arch_req_version, 0))
      {
        safe_printfmt (2, "%s: invalid VERSION spec (%s)\n", argv[0], reference);
        exit (2);
      }

    to_archive = arch_parse_package_name (arch_ret_archive, default_archive, reference);
    to_version = arch_parse_package_name (arch_ret_non_archive, 0, reference);

    if (argc < 2)
      from_spec = str_save (0, to_version);
    else
      from_spec = str_save (0, argv[1]);

    if (!arch_valid_package_name (from_spec, arch_maybe_archive, arch_req_version, 1))
      {
        safe_printfmt (2, "%s: invalid FROM revision spec (%s)\n", argv[0], from_spec);
        exit (2);
      }

    from_archive = arch_parse_package_name (arch_ret_archive, tree.archive, from_spec);
    from_arch = arch_archive_connect (from_archive, 0);

    if (arch_valid_package_name (from_spec, arch_maybe_archive, arch_req_patch_level, 0))
      {
        if (argc == 2)
          arch_check_for (from_arch, arch_req_patch_level, from_spec);
        
        from_revision = arch_parse_package_name (arch_ret_non_archive, 0, from_spec);
      }
    else
      {
        t_uchar * from_version = 0;
        rel_table revisions = 0;
        
        if (argc == 2) 
        arch_check_for (from_arch, arch_req_version, from_spec);

        from_version = arch_parse_package_name (arch_ret_non_archive, 0, from_spec);

        revisions = arch_archive_revisions (from_arch, from_version, 2);

        if (!revisions)
          {
            safe_printfmt (2, "%s: FROM version has no revisions (%s/%s)\n",
                           argv[0], from_archive, from_version);
            exit (2);
          }

        from_revision = str_save (0, revisions[rel_n_records (revisions) - 1][0]);

        lim_free (0, from_version);
        rel_free_table (revisions);
      }

    cache_dir = file_name_directory_file (0, tree.root);

    exit_status = arch_star_merge (1, from_arch, from_archive, from_revision, tree.root, 0, to_archive, to_version, cache_dir, changeset, !two_way, 0, escape_classes, merge_points_only, graph_merge,trace_merge);

    lim_free (0, from_spec);
    lim_free (0, from_archive);
    arch_archive_close (from_arch);
    lim_free (0, from_revision);

    arch_project_tree_finalise (&tree);

    lim_free (0, to_archive);
    lim_free (0, to_version);

    lim_free (0, cache_dir);
  }

  lim_free (0, dir);
  lim_free (0, reference);
  lim_free (0, default_archive);

  return exit_status;
}




/* tag: Tom Lord Sat Jun 28 20:22:10 2003 (cmd-star-merge.c)
 */

Generated by  Doxygen 1.6.0   Back to index