{"thread":{"id":"57455","subject":"pull fails after commit dry-run","startedAt":"2022-02-22T06:20:31Z","lastAt":"2022-02-23T23:41:06Z","messageCount":2,"participants":["Maximilian Reichel","Rafael Silva"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"449089","messageId":"B0458F2D-C6B9-41AE-8F2F-39C1D2AEE6BD@icloud.com","threadId":"57455","inReplyTo":null,"subject":"pull fails after commit dry-run","fromName":"Maximilian Reichel","fromEmail":"reichemn@icloud.com","sentAt":"2022-02-22T06:11:40Z","receivedAt":"2022-02-22T06:20:31Z","isPatch":false,"sender":{"key":"reichemn@icloud.com","avatar":null},"body":"﻿Thank you for filling out a Git bug report!\nPlease answer the following questions to help us understand your issue.\n\nWhat did you do before the bug happened? (Steps to reproduce your issue)\nRunning the following two scripts.\n\n\nScript one:\n'#!/bin/bash\n\nmkdir parent\ngit -C parent init\ngit -C parent -c user.name=\"P\" -c user.email=\"m@example.com\" commit -m one --allow-empty \n\nmkdir cloneDir\ncd cloneDir\ngit init\n\ngit pull -v --rebase \"../parent\"\necho git pull exit code: $?'\n\n\n\n\nscript two:\n'#!/bin/bash\n\nmkdir parent\ngit -C parent init\ngit -C parent -c user.name=\"P\" -c user.email=\"m@example.com\" commit -m one --allow-empty \n\nmkdir cloneDir\ncd cloneDir\ngit init\ngit commit -m \"foo\" --dry-run\ngit pull -v --rebase \"../parent\"\necho git pull exit code: $?'\n\n\n\nWhat did you expect to happen? (Expected behavior)\nSince they only differ in the 'git commit -m \"foo\" --dry-run' invocation, I would expect the same outcome for both scripts.\nExpected output of the last two lines:\n'From ../parent\n* branch            HEAD       -> FETCH_HEAD\ngit pull exit code: 0'\n\nWhat happened instead? (Actual behavior)\nThe second script is not able to pull from ../parent.\nOutput of the last lines of the second script:\n'fatal: Updating an unborn branch with changes added to the index.\ngit pull exit code: 128’\n\n\nAnything else you want to add:\nI tested this on git 2.35.1, 2.34.1 and 2.21.0 and they are all affected. \n\n\n[System Info]\ngit version:\ngit version 2.35.1\ncpu: x86_64\nno commit associated with this build\nsizeof-long: 8\nsizeof-size_t: 8\nshell-path: /bin/sh\nuname: Linux 5.10.25-linuxkit #1 SMP Tue Mar 23 09:27:39 UTC 2021 x86_64\ncompiler info: gnuc: 10.2\nlibc info: glibc: 2.31\n$SHELL (typically, interactive shell): <unset>\n\n\n[Enabled Hooks]\nnot run from a git repository - no hooks to show\n"},{"id":"449373","messageId":"878ru1kv8t.fsf@gmail.com","threadId":"57455","inReplyTo":"B0458F2D-C6B9-41AE-8F2F-39C1D2AEE6BD@icloud.com","subject":"Re: pull fails after commit dry-run","fromName":"Rafael Silva","fromEmail":"rafaeloliveira.cs@gmail.com","sentAt":"2022-02-22T23:15:02Z","receivedAt":"2022-02-23T23:41:06Z","isPatch":false,"sender":{"key":"rafaeloliveira.cs@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5935135?v=4"},"body":"\nHi,\n\nMaximilian Reichel <reichemn@icloud.com> writes:\n\n> ﻿Thank you for filling out a Git bug report!\n> Please answer the following questions to help us understand your issue.\n>\n> What did you do before the bug happened? (Steps to reproduce your issue)\n> Running the following two scripts.\n>\n>\n> Script one:\n> '#!/bin/bash\n>\n> mkdir parent\n> git -C parent init\n> git -C parent -c user.name=\"P\" -c user.email=\"m@example.com\" commit -m one --allow-empty \n>\n> mkdir cloneDir\n> cd cloneDir\n> git init\n>\n> git pull -v --rebase \"../parent\"\n> echo git pull exit code: $?'\n>\n>\n>\n>\n> script two:\n> '#!/bin/bash\n>\n> mkdir parent\n> git -C parent init\n> git -C parent -c user.name=\"P\" -c user.email=\"m@example.com\" commit -m one --allow-empty \n>\n> mkdir cloneDir\n> cd cloneDir\n> git init\n> git commit -m \"foo\" --dry-run\n> git pull -v --rebase \"../parent\"\n> echo git pull exit code: $?'\n>\n\nThanks for providing the script to quickly assess the problem.\n\n>\n> What did you expect to happen? (Expected behavior)\n> Since they only differ in the 'git commit -m \"foo\" --dry-run' invocation, I would expect the same outcome for both scripts.\n> Expected output of the last two lines:\n> 'From ../parent\n> * branch            HEAD       -> FETCH_HEAD\n> git pull exit code: 0'\n>\n> What happened instead? (Actual behavior)\n> The second script is not able to pull from ../parent.\n> Output of the last lines of the second script:\n> 'fatal: Updating an unborn branch with changes added to the index.\n> git pull exit code: 128’\n>\n\nFirst of all, as I'm not an experienced contributor, the following\nshould be taken with a grain of salt. Nevertheless, I thought about\ngiven a shot here.\n\nIt seems this boils down to the fact that on the second script, `git\ncommit --dry-run` will create the `.git/index` (the Git Index) in order\nto run the commit process as part of its natural workflow (i.e: `git\nadd`, `git commit`). Even though the index has no entries in it.\n\nLater, when `git pull --rebase` is called, it executes the following\ncondition that evaluates to true (as we can see from the report ;) ):\n\n    # builtin/pull.c:cmd_pull\n    if (is_null_oid(&orig_head) && !is_cache_unborn())\n        die(_(\"Updating an unborn branch with changes added to the index.\"));\n\nOn the condition, according to my understand of the code, we die when\n.git/HEAD does not point to a commit and when the index is there (or\nborn, to use the code terminology). The first will be true, on this\nparticular case, because it's a fresh repository.\n\nIOW, we assume that is not safe to rebase on a \"yet to be born branch\"\nwith a non-empty index, as the index is not based on anything that comes\nfrom the upstream repository. This indicates that there local changes\nthat will be destroy if the rebase is performed.\n\nThis behavior dates back to 19a7fcbf16 (allow pull --rebase on branch\nyet to be born, 2009-08-11). Back then, `git pull` was written in shell\nscript with the following code:\n\n    # On an unborn branch\n    if test -f \"$GIT_DIR/index\"\n    then\n            die \"updating an unborn branch with changes added to the index\"\n    fi\n\nOn the current code (e6ebfd0e8c (The sixth batch, 2022-02-18)), we\nidentify if the index is not born, by checking if the index has no\nentries and if the timestamp is set:\n\n    #define is_cache_unborn() is_index_unborn(&the_index)\n\n    int is_index_unborn(struct index_state *istate)\n    {\n             return (!istate->cache_nr && !istate->timestamp.sec);\n    }\n\nNow, this is where it gets a bit interesting. On this case, the index\ncreated by the `commit --dry-run` is empty in a sense: It doesn't have\nany entries. Which makes me think that we \"should\" be able to `pull\n--rebase`, for such case. For instance, by untighting the condition to\nonly check the number of entries. However, I'm probably missing some\nintrinsic information that will break the code or worse deleting local\nchanges.\n\nJust in order to illustrate better how such change can look like:\n\n--- 8< ---\ndiff --git a/builtin/pull.c b/builtin/pull.c\nindex 3768552e68..c45a880e56 100644\n--- a/builtin/pull.c\n+++ b/builtin/pull.c\n@@ -980,6 +980,20 @@ static void show_advice_pull_non_ff(void)\n \t\t \"invocation.\\n\"));\n }\n\n+/*\n+ * If, for some reason, this turns out to be a good idea,\n+ * it shuold be move to its proper location.\n+ */\n+#define is_cache_empty() is_index_empty(&the_index)\n+\n+static int is_index_empty(struct index_state *istate)\n+{\n+\treturn !istate->cache_nr;\n+}\n+\n+int is_index_unborn(struct index_state *);\n+\n+\n int cmd_pull(int argc, const char **argv, const char *prefix)\n {\n \tconst char *repo, **refspecs;\n@@ -1043,7 +1057,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)\n \t\tif (opt_autostash == -1)\n \t\t\topt_autostash = config_autostash;\n\n-\t\tif (is_null_oid(&orig_head) && !is_cache_unborn())\n+\t\tif (is_null_oid(&orig_head) && !is_cache_empty())\n \t\t\tdie(_(\"Updating an unborn branch with changes added to the index.\"));\n\n \t\tif (!opt_autostash)\n--- >8 ---\n\nWhether this is a good idea or not, I'm not able to tell right now. If\nthis turns out to be a good idea, I can prepare a follow up patch with\nproper testing.\n\n>\n> Anything else you want to add:\n> I tested this on git 2.35.1, 2.34.1 and 2.21.0 and they are all affected. \n>\n>\n> [System Info]\n> git version:\n> git version 2.35.1\n> cpu: x86_64\n> no commit associated with this build\n> sizeof-long: 8\n> sizeof-size_t: 8\n> shell-path: /bin/sh\n> uname: Linux 5.10.25-linuxkit #1 SMP Tue Mar 23 09:27:39 UTC 2021 x86_64\n> compiler info: gnuc: 10.2\n> libc info: glibc: 2.31\n> $SHELL (typically, interactive shell): <unset>\n>\n>\n> [Enabled Hooks]\n> not run from a git repository - no hooks to show\n\n\n-- \nThanks\nRaffs\n"}]}