91575361be66257b33bdaae86c429c047d652533
   1/*
   2 * Builtin "git pull"
   3 *
   4 * Based on git-pull.sh by Junio C Hamano
   5 *
   6 * Fetch one or more remote refs and merge it/them into the current HEAD.
   7 */
   8#include "cache.h"
   9#include "builtin.h"
  10#include "parse-options.h"
  11#include "exec_cmd.h"
  12#include "run-command.h"
  13
  14static const char * const pull_usage[] = {
  15        N_("git pull [options] [<repository> [<refspec>...]]"),
  16        NULL
  17};
  18
  19static struct option pull_options[] = {
  20        OPT_END()
  21};
  22
  23/**
  24 * Parses argv into [<repo> [<refspecs>...]], returning their values in `repo`
  25 * as a string and `refspecs` as a null-terminated array of strings. If `repo`
  26 * is not provided in argv, it is set to NULL.
  27 */
  28static void parse_repo_refspecs(int argc, const char **argv, const char **repo,
  29                const char ***refspecs)
  30{
  31        if (argc > 0) {
  32                *repo = *argv++;
  33                argc--;
  34        } else
  35                *repo = NULL;
  36        *refspecs = argv;
  37}
  38
  39/**
  40 * Runs git-fetch, returning its exit status. `repo` and `refspecs` are the
  41 * repository and refspecs to fetch, or NULL if they are not provided.
  42 */
  43static int run_fetch(const char *repo, const char **refspecs)
  44{
  45        struct argv_array args = ARGV_ARRAY_INIT;
  46        int ret;
  47
  48        argv_array_pushl(&args, "fetch", "--update-head-ok", NULL);
  49        if (repo) {
  50                argv_array_push(&args, repo);
  51                argv_array_pushv(&args, refspecs);
  52        } else if (*refspecs)
  53                die("BUG: refspecs without repo?");
  54        ret = run_command_v_opt(args.argv, RUN_GIT_CMD);
  55        argv_array_clear(&args);
  56        return ret;
  57}
  58
  59/**
  60 * Runs git-merge, returning its exit status.
  61 */
  62static int run_merge(void)
  63{
  64        int ret;
  65        struct argv_array args = ARGV_ARRAY_INIT;
  66
  67        argv_array_pushl(&args, "merge", NULL);
  68        argv_array_push(&args, "FETCH_HEAD");
  69        ret = run_command_v_opt(args.argv, RUN_GIT_CMD);
  70        argv_array_clear(&args);
  71        return ret;
  72}
  73
  74int cmd_pull(int argc, const char **argv, const char *prefix)
  75{
  76        const char *repo, **refspecs;
  77
  78        if (!getenv("_GIT_USE_BUILTIN_PULL")) {
  79                const char *path = mkpath("%s/git-pull", git_exec_path());
  80
  81                if (sane_execvp(path, (char **)argv) < 0)
  82                        die_errno("could not exec %s", path);
  83        }
  84
  85        argc = parse_options(argc, argv, prefix, pull_options, pull_usage, 0);
  86
  87        parse_repo_refspecs(argc, argv, &repo, &refspecs);
  88
  89        if (run_fetch(repo, refspecs))
  90                return 1;
  91
  92        return run_merge();
  93}