{"thread":{"id":"50943","subject":"[PATCH] Give git-pull a --reset option","startedAt":"2019-04-17T04:07:43Z","lastAt":"2019-04-17T08:51:23Z","messageCount":2,"participants":["Alex Henrie","Eric Sunshine"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"373995","messageId":"20190417040733.22200-1-alexhenrie24@gmail.com","threadId":"50943","inReplyTo":null,"subject":"[PATCH] Give git-pull a --reset option","fromName":"Alex Henrie","fromEmail":"alexhenrie24@gmail.com","sentAt":"2019-04-17T04:07:33Z","receivedAt":"2019-04-17T04:07:43Z","isPatch":true,"sender":{"key":"alexhenrie24@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5951993?v=4"},"body":"A common workflow is to make a commit on a local branch, push the branch\nto the remote, check out the remote branch on a second computer, amend\nthe commit on the second computer, force-push back to the remote branch,\nand finally submit a pull request. However, if the user switches back to\nthe first computer, they must then run the cumbersome command\n`git fetch && git reset --hard origin`. (Actually, at this point Git\nnovices often try running `git pull --force`, but it doesn't do what\nthey expect.) This patch adds the shortcut `git pull --reset` to serve\nas a complement to `git push --force`.\n\nSigned-off-by: Alex Henrie <alexhenrie24@gmail.com>\n---\n Documentation/git-pull.txt |  8 ++++++++\n builtin/pull.c             | 28 ++++++++++++++++++++++++++++\n 2 files changed, 36 insertions(+)\n\ndiff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt\nindex 118d9d86f7..bae8f07161 100644\n--- a/Documentation/git-pull.txt\n+++ b/Documentation/git-pull.txt\n@@ -23,6 +23,7 @@ More precisely, 'git pull' runs 'git fetch' with the given\n parameters and calls 'git merge' to merge the retrieved branch\n heads into the current branch.\n With `--rebase`, it runs 'git rebase' instead of 'git merge'.\n+With `--reset`, it runs `git reset --hard` instead of 'git merge'.\n \n <repository> should be the name of a remote repository as\n passed to linkgit:git-fetch[1].  <refspec> can name an\n@@ -141,6 +142,13 @@ unless you have read linkgit:git-rebase[1] carefully.\n +\n This option is only valid when \"--rebase\" is used.\n \n+--reset::\n+\tReset the local branch to match the remote commit, discarding any local\n+\tcommits or other changes.\n+\n+--no-reset::\n+\tOverride earlier --reset.\n+\n Options related to fetching\n ~~~~~~~~~~~~~~~~~~~~~~~~~~~\n \ndiff --git a/builtin/pull.c b/builtin/pull.c\nindex 33db889955..97379447eb 100644\n--- a/builtin/pull.c\n+++ b/builtin/pull.c\n@@ -95,6 +95,7 @@ static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;\n \n /* Options passed to git-merge or git-rebase */\n static enum rebase_type opt_rebase = -1;\n+static char *opt_reset;\n static char *opt_diffstat;\n static char *opt_log;\n static char *opt_signoff;\n@@ -144,6 +145,9 @@ static struct option pull_options[] = {\n \t  \"(false|true|merges|preserve|interactive)\",\n \t  N_(\"incorporate changes by rebasing rather than merging\"),\n \t  PARSE_OPT_OPTARG, parse_opt_rebase },\n+\tOPT_PASSTHRU(0, \"reset\", &opt_reset, NULL,\n+\t\tN_(\"discard all local changes rather than merging\"),\n+\t\tPARSE_OPT_NOARG | PARSE_OPT_NONEG),\n \tOPT_PASSTHRU('n', NULL, &opt_diffstat, NULL,\n \t\tN_(\"do not show a diffstat at the end of the merge\"),\n \t\tPARSE_OPT_NOARG | PARSE_OPT_NONEG),\n@@ -860,6 +864,21 @@ static int run_rebase(const struct object_id *curr_head,\n \treturn ret;\n }\n \n+/**\n+ * Runs git-reset, returning its exit status.\n+ */\n+static int run_reset(void)\n+{\n+\tint ret;\n+\tstruct argv_array args = ARGV_ARRAY_INIT;\n+\targv_array_pushl(&args, \"reset\", NULL);\n+\targv_array_push(&args, \"--hard\");\n+\targv_array_push(&args, \"FETCH_HEAD\");\n+\tret = run_command_v_opt(args.argv, RUN_GIT_CMD);\n+\targv_array_clear(&args);\n+\treturn ret;\n+}\n+\n int cmd_pull(int argc, const char **argv, const char *prefix)\n {\n \tconst char *repo, **refspecs;\n@@ -892,6 +911,9 @@ int cmd_pull(int argc, const char **argv, const char *prefix)\n \tif (get_oid(\"HEAD\", &orig_head))\n \t\toidclr(&orig_head);\n \n+\tif (opt_rebase && opt_reset)\n+\t\tdie(_(\"--rebase and --reset are mutually exclusive.\"));\n+\n \tif (!opt_rebase && opt_autostash != -1)\n \t\tdie(_(\"--[no-]autostash option is only valid with --rebase.\"));\n \n@@ -986,6 +1008,12 @@ int cmd_pull(int argc, const char **argv, const char *prefix)\n \t\t\tret = rebase_submodules();\n \n \t\treturn ret;\n+\t} else if (opt_reset) {\n+\t\tint ret = run_reset();\n+\t\tif (!ret && (recurse_submodules == RECURSE_SUBMODULES_ON ||\n+\t\t\t     recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND))\n+\t\t\tret = update_submodules();\n+\t\treturn ret;\n \t} else {\n \t\tint ret = run_merge();\n \t\tif (!ret && (recurse_submodules == RECURSE_SUBMODULES_ON ||\n-- \n2.21.0\n\n"},{"id":"374011","messageId":"CAPig+cQDU=Nounwiy5CFCfPvnj5eJJXNv+ihgbh2nYYVTYPBCQ@mail.gmail.com","threadId":"50943","inReplyTo":"20190417040733.22200-1-alexhenrie24@gmail.com","subject":"Re: [PATCH] Give git-pull a --reset option","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2019-04-17T08:51:08Z","receivedAt":"2019-04-17T08:51:23Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Wed, Apr 17, 2019 at 12:07 AM Alex Henrie <alexhenrie24@gmail.com> wrote:\n> A common workflow is to make a commit on a local branch, push the branch\n> to the remote, check out the remote branch on a second computer, amend\n> the commit on the second computer, force-push back to the remote branch,\n> and finally submit a pull request. However, if the user switches back to\n> the first computer, they must then run the cumbersome command\n> `git fetch && git reset --hard origin`. (Actually, at this point Git\n> novices often try running `git pull --force`, but it doesn't do what\n> they expect.) This patch adds the shortcut `git pull --reset` to serve\n> as a complement to `git push --force`.\n\nI didn't know this was a particularly common workflow, although I\nadmit to working this way myself often enough.\n\n> Signed-off-by: Alex Henrie <alexhenrie24@gmail.com>\n> ---\n>  Documentation/git-pull.txt |  8 ++++++++\n>  builtin/pull.c             | 28 ++++++++++++++++++++++++++++\n\nPerhaps add a test or two to t/t5520-pull.sh covering this new feature.\n\n> diff --git a/builtin/pull.c b/builtin/pull.c\n> @@ -860,6 +864,21 @@ static int run_rebase(const struct object_id *curr_head,\n> +/**\n> + * Runs git-reset, returning its exit status.\n> + */\n> +static int run_reset(void)\n> +{\n> +       int ret;\n> +       struct argv_array args = ARGV_ARRAY_INIT;\n\nIn this codebase, it's typical to have a blank line following the declarations.\n\n> +       argv_array_pushl(&args, \"reset\", NULL);\n> +       argv_array_push(&args, \"--hard\");\n> +       argv_array_push(&args, \"FETCH_HEAD\");\n\nNot sure why you're using \"pushl\" for the first and then plain \"push\"\nfor the rest. With \"pushl\", the entire setup can be collapsed to:\n\n    argv_array_pushl(&args, \"reset\", \"--hard\", \"FETCH_HEAD\", NULL);\n\nBut, given that this argument list isn't dynamic, you could simplify\nfurther by just declaring:\n\n    const char *argv[] = { \"reset\", \"--hard\", \"FETCH_HEAD\", NULL };\n\n> +       ret = run_command_v_opt(args.argv, RUN_GIT_CMD);\n> +       argv_array_clear(&args);\n\n...and do away with the argv_array_clear() altogether.\n\n> +       return ret;\n> +}\n\nIn fact, taking these suggestions into account, the code collapses to\njust two lines, which you could easily inline into the sole caller,\nthus you don't need a separate function at all.\n\n> @@ -892,6 +911,9 @@ int cmd_pull(int argc, const char **argv, const char *prefix)\n> +       if (opt_rebase && opt_reset)\n> +               die(_(\"--rebase and --reset are mutually exclusive.\"));\n\nModern practice on this project is to not end these messages with a\nperiod, however, as most messages in this file currently end with a\nperiod, this may be okay.\n\n>         if (!opt_rebase && opt_autostash != -1)\n>                 die(_(\"--[no-]autostash option is only valid with --rebase.\"));\n"}]}