Message ID | 20190417040733.22200-1-alexhenrie24@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Give git-pull a --reset option | expand |
On Wed, Apr 17, 2019 at 12:07 AM Alex Henrie <alexhenrie24@gmail.com> wrote: > A common workflow is to make a commit on a local branch, push the branch > to the remote, check out the remote branch on a second computer, amend > the commit on the second computer, force-push back to the remote branch, > and finally submit a pull request. However, if the user switches back to > the first computer, they must then run the cumbersome command > `git fetch && git reset --hard origin`. (Actually, at this point Git > novices often try running `git pull --force`, but it doesn't do what > they expect.) This patch adds the shortcut `git pull --reset` to serve > as a complement to `git push --force`. I didn't know this was a particularly common workflow, although I admit to working this way myself often enough. > Signed-off-by: Alex Henrie <alexhenrie24@gmail.com> > --- > Documentation/git-pull.txt | 8 ++++++++ > builtin/pull.c | 28 ++++++++++++++++++++++++++++ Perhaps add a test or two to t/t5520-pull.sh covering this new feature. > diff --git a/builtin/pull.c b/builtin/pull.c > @@ -860,6 +864,21 @@ static int run_rebase(const struct object_id *curr_head, > +/** > + * Runs git-reset, returning its exit status. > + */ > +static int run_reset(void) > +{ > + int ret; > + struct argv_array args = ARGV_ARRAY_INIT; In this codebase, it's typical to have a blank line following the declarations. > + argv_array_pushl(&args, "reset", NULL); > + argv_array_push(&args, "--hard"); > + argv_array_push(&args, "FETCH_HEAD"); Not sure why you're using "pushl" for the first and then plain "push" for the rest. With "pushl", the entire setup can be collapsed to: argv_array_pushl(&args, "reset", "--hard", "FETCH_HEAD", NULL); But, given that this argument list isn't dynamic, you could simplify further by just declaring: const char *argv[] = { "reset", "--hard", "FETCH_HEAD", NULL }; > + ret = run_command_v_opt(args.argv, RUN_GIT_CMD); > + argv_array_clear(&args); ...and do away with the argv_array_clear() altogether. > + return ret; > +} In fact, taking these suggestions into account, the code collapses to just two lines, which you could easily inline into the sole caller, thus you don't need a separate function at all. > @@ -892,6 +911,9 @@ int cmd_pull(int argc, const char **argv, const char *prefix) > + if (opt_rebase && opt_reset) > + die(_("--rebase and --reset are mutually exclusive.")); Modern practice on this project is to not end these messages with a period, however, as most messages in this file currently end with a period, this may be okay. > if (!opt_rebase && opt_autostash != -1) > die(_("--[no-]autostash option is only valid with --rebase."));
diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt index 118d9d86f7..bae8f07161 100644 --- a/Documentation/git-pull.txt +++ b/Documentation/git-pull.txt @@ -23,6 +23,7 @@ More precisely, 'git pull' runs 'git fetch' with the given parameters and calls 'git merge' to merge the retrieved branch heads into the current branch. With `--rebase`, it runs 'git rebase' instead of 'git merge'. +With `--reset`, it runs `git reset --hard` instead of 'git merge'. <repository> should be the name of a remote repository as passed to linkgit:git-fetch[1]. <refspec> can name an @@ -141,6 +142,13 @@ unless you have read linkgit:git-rebase[1] carefully. + This option is only valid when "--rebase" is used. +--reset:: + Reset the local branch to match the remote commit, discarding any local + commits or other changes. + +--no-reset:: + Override earlier --reset. + Options related to fetching ~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/builtin/pull.c b/builtin/pull.c index 33db889955..97379447eb 100644 --- a/builtin/pull.c +++ b/builtin/pull.c @@ -95,6 +95,7 @@ static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT; /* Options passed to git-merge or git-rebase */ static enum rebase_type opt_rebase = -1; +static char *opt_reset; static char *opt_diffstat; static char *opt_log; static char *opt_signoff; @@ -144,6 +145,9 @@ static struct option pull_options[] = { "(false|true|merges|preserve|interactive)", N_("incorporate changes by rebasing rather than merging"), PARSE_OPT_OPTARG, parse_opt_rebase }, + OPT_PASSTHRU(0, "reset", &opt_reset, NULL, + N_("discard all local changes rather than merging"), + PARSE_OPT_NOARG | PARSE_OPT_NONEG), OPT_PASSTHRU('n', NULL, &opt_diffstat, NULL, N_("do not show a diffstat at the end of the merge"), PARSE_OPT_NOARG | PARSE_OPT_NONEG), @@ -860,6 +864,21 @@ static int run_rebase(const struct object_id *curr_head, return ret; } +/** + * Runs git-reset, returning its exit status. + */ +static int run_reset(void) +{ + int ret; + struct argv_array args = ARGV_ARRAY_INIT; + argv_array_pushl(&args, "reset", NULL); + argv_array_push(&args, "--hard"); + argv_array_push(&args, "FETCH_HEAD"); + ret = run_command_v_opt(args.argv, RUN_GIT_CMD); + argv_array_clear(&args); + return ret; +} + int cmd_pull(int argc, const char **argv, const char *prefix) { const char *repo, **refspecs; @@ -892,6 +911,9 @@ int cmd_pull(int argc, const char **argv, const char *prefix) if (get_oid("HEAD", &orig_head)) oidclr(&orig_head); + if (opt_rebase && opt_reset) + die(_("--rebase and --reset are mutually exclusive.")); + if (!opt_rebase && opt_autostash != -1) die(_("--[no-]autostash option is only valid with --rebase.")); @@ -986,6 +1008,12 @@ int cmd_pull(int argc, const char **argv, const char *prefix) ret = rebase_submodules(); return ret; + } else if (opt_reset) { + int ret = run_reset(); + if (!ret && (recurse_submodules == RECURSE_SUBMODULES_ON || + recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND)) + ret = update_submodules(); + return ret; } else { int ret = run_merge(); if (!ret && (recurse_submodules == RECURSE_SUBMODULES_ON ||
A common workflow is to make a commit on a local branch, push the branch to the remote, check out the remote branch on a second computer, amend the commit on the second computer, force-push back to the remote branch, and finally submit a pull request. However, if the user switches back to the first computer, they must then run the cumbersome command `git fetch && git reset --hard origin`. (Actually, at this point Git novices often try running `git pull --force`, but it doesn't do what they expect.) This patch adds the shortcut `git pull --reset` to serve as a complement to `git push --force`. Signed-off-by: Alex Henrie <alexhenrie24@gmail.com> --- Documentation/git-pull.txt | 8 ++++++++ builtin/pull.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+)