{"thread":{"id":"30003","subject":"[PATCH v3] push: Provide situational hints for non-fast-forward errors","startedAt":"2012-03-20T04:31:33Z","lastAt":"2012-03-26T20:11:22Z","messageCount":9,"participants":["Christopher Tiwald","Junio C Hamano","Jeff King"],"isPatch":true,"patchVersion":3,"patchTotal":null},"messages":[{"id":"187302","messageId":"20120320043133.GA2755@gmail.com","threadId":"30003","inReplyTo":null,"subject":"[PATCH v3] push: Provide situational hints for non-fast-forward errors","fromName":"Christopher Tiwald","fromEmail":"christiwald@gmail.com","sentAt":"2012-03-20T04:31:33Z","receivedAt":"2012-03-20T04:31:33Z","isPatch":true,"sender":{"key":"christiwald@gmail.com","avatar":"https://avatars.githubusercontent.com/u/667276?v=4"},"body":"Pushing a non-fast-forward update to a remote repository will result in\nan error, but the hint text doesn't provide the correct resolution in\nevery case. Give better resolution advice in three push scenarios:\n\n1) If you push your current branch and it triggers a non-fast-forward\nerror, you should merge remote changes with 'git pull' before pushing\nagain.\n\n2) If you push to a shared repository others push to, and your local\ntracking branches are not kept up to date, the 'matching refs' default\nwill generate non-fast-forward errors on outdated branches. If this is\nyour workflow, the 'matching refs' default is not for you. Consider\nsetting the 'push.default' configuration variable to 'current' or\n'upstream' to ensure only your current branch is pushed.\n\n3) If you explicitly specify a ref that is not your current branch or\npush matching branches with ':', you will generate a non-fast-forward\nerror if any pushed branch tip is out of date. You should checkout the\noffending branch and merge remote changes before pushing again.\n\nTeach transport.c to recognize these scenarios and configure push.c\nto hint for them. If 'git push's default behavior changes or we\ndiscover more scenarios, extension is easy. Standardize on the\nadvice API and add three new advice variables, 'pushNonFFCurrent',\n'pushNonFFDefault', and 'pushNonFFMatching'. Setting any of these\nto 'false' will disable their affiliated advice. Setting\n'pushNonFastForward' to false will disable all three, thus preserving the\nconfig option for users who already set it, but guaranteeing new\nusers won't disable push advice accidentally.\n\nBased-on-patch-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Christopher Tiwald <christiwald@gmail.com>\n---\n Changes since v2:\n\t- Cleaned up commit message language, specifically in scenario\n\t  one.\n\t- Created one config variable per piece of non-ff push advice.\n\t  Additionally, preserved 'pushNonFastForward' as a means of\n\t  disabling all non-ff push advice. Users who set this\n\t  config option should see no change to 'git push'.\n\n Documentation/config.txt |   19 +++++++++++++--\n advice.c                 |    6 +++++\n advice.h                 |    3 +++\n builtin/push.c           |   60 ++++++++++++++++++++++++++++++++++++++++++----\n cache.h                  |    8 +++++--\n environment.c            |    2 +-\n transport.c              |   13 ++++++++--\n 7 files changed, 99 insertions(+), 12 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex c081657..fb386ab 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -138,8 +138,23 @@ advice.*::\n +\n --\n \tpushNonFastForward::\n-\t\tAdvice shown when linkgit:git-push[1] refuses\n-\t\tnon-fast-forward refs.\n+\t\tSet this variable to 'false' if you want to disable\n+\t\t'pushNonFFCurrent', 'pushNonFFDefault', and\n+\t\t'pushNonFFMatching' simultaneously.\n+\tpushNonFFCurrent::\n+\t\tAdvice shown when linkgit:git-push[1] fails due to a\n+\t\tnon-fast-forward update to the current branch.\n+\tpushNonFFDefault::\n+\t\tAdvice to set 'push.default' to 'upstream' or 'current'\n+\t\twhen you ran linkgit:git-push[1] and pushed 'matching\n+\t\trefs' by default (i.e. you did not provide an explicit\n+\t\trefspec, and no 'push.default' configuration was set)\n+\t\tand it resulted in a non-fast-forward error.\n+\tpushNonFFMatching::\n+\t\tAdvice shown when you ran linkgit:git-push[1] and pushed\n+\t\t'matching refs' explicitly (i.e. you used ':', or\n+\t\tspecified a refspec that isn't your current branch) and\n+\t\tit resulted in a non-fast-forward error.\n \tstatusHints::\n \t\tDirections on how to stage/unstage/add shown in the\n \t\toutput of linkgit:git-status[1] and the template shown\ndiff --git a/advice.c b/advice.c\nindex 01130e5..a492eea 100644\n--- a/advice.c\n+++ b/advice.c\n@@ -1,6 +1,9 @@\n #include \"cache.h\"\n \n int advice_push_nonfastforward = 1;\n+int advice_push_non_ff_current = 1;\n+int advice_push_non_ff_default = 1;\n+int advice_push_non_ff_matching = 1;\n int advice_status_hints = 1;\n int advice_commit_before_merge = 1;\n int advice_resolve_conflict = 1;\n@@ -12,6 +15,9 @@ static struct {\n \tint *preference;\n } advice_config[] = {\n \t{ \"pushnonfastforward\", &advice_push_nonfastforward },\n+\t{ \"pushnonffcurrent\", &advice_push_non_ff_current },\n+\t{ \"pushnonffdefault\", &advice_push_non_ff_default },\n+\t{ \"pushnonffmatching\", &advice_push_non_ff_matching },\n \t{ \"statushints\", &advice_status_hints },\n \t{ \"commitbeforemerge\", &advice_commit_before_merge },\n \t{ \"resolveconflict\", &advice_resolve_conflict },\ndiff --git a/advice.h b/advice.h\nindex 7bda45b..f3cdbbf 100644\n--- a/advice.h\n+++ b/advice.h\n@@ -4,6 +4,9 @@\n #include \"git-compat-util.h\"\n \n extern int advice_push_nonfastforward;\n+extern int advice_push_non_ff_current;\n+extern int advice_push_non_ff_default;\n+extern int advice_push_non_ff_matching;\n extern int advice_status_hints;\n extern int advice_commit_before_merge;\n extern int advice_resolve_conflict;\ndiff --git a/builtin/push.c b/builtin/push.c\nindex d315475..8a14e4b 100644\n--- a/builtin/push.c\n+++ b/builtin/push.c\n@@ -24,6 +24,7 @@ static int progress = -1;\n static const char **refspec;\n static int refspec_nr;\n static int refspec_alloc;\n+static int default_matching_used;\n \n static void add_refspec(const char *ref)\n {\n@@ -95,6 +96,9 @@ static void setup_default_push_refspecs(struct remote *remote)\n {\n \tswitch (push_default) {\n \tdefault:\n+\tcase PUSH_DEFAULT_UNSPECIFIED:\n+\t\tdefault_matching_used = 1;\n+\t\t/* fallthru */\n \tcase PUSH_DEFAULT_MATCHING:\n \t\tadd_refspec(\":\");\n \t\tbreak;\n@@ -114,6 +118,45 @@ static void setup_default_push_refspecs(struct remote *remote)\n \t}\n }\n \n+static const char message_advice_pull_before_push[] =\n+\tN_(\"Updates were rejected because the tip of your current branch is behind\\n\"\n+\t   \"its remote counterpart. Merge the remote changes (e.g. 'git pull')\\n\"\n+\t   \"before pushing again.\\n\"\n+\t   \"See the 'Note about fast-forwards' in 'git push --help' for details.\");\n+\n+static const char message_advice_use_upstream[] =\n+\tN_(\"Updates were rejected because a pushed branch tip is behind its remote\\n\"\n+\t   \"counterpart. If you did not intend to push that branch, you may want to\\n\"\n+\t   \"specify branches to push or set the 'push.default' configuration\\n\"\n+\t   \"variable to 'current' or 'upstream' to push only the current branch.\");\n+\n+static const char message_advice_checkout_pull_push[] =\n+\tN_(\"Updates were rejected because a pushed branch tip is behind its remote\\n\"\n+\t   \"counterpart. Check out this branch and merge the remote changes\\n\"\n+\t   \"(e.g. 'git pull') before pushing again.\\n\"\n+\t   \"See the 'Note about fast-forwards' in 'git push --help' for details.\");\n+\n+static void advise_pull_before_push(void)\n+{\n+\tif (!advice_push_non_ff_current || !advice_push_nonfastforward)\n+\t\treturn;\n+\tadvise(_(message_advice_pull_before_push));\n+}\n+\n+static void advise_use_upstream(void)\n+{\n+\tif (!advice_push_non_ff_default || !advice_push_nonfastforward)\n+\t\treturn;\n+\tadvise(_(message_advice_use_upstream));\n+}\n+\n+static void advise_checkout_pull_push(void)\n+{\n+\tif (!advice_push_non_ff_matching || !advice_push_nonfastforward)\n+\t\treturn;\n+\tadvise(_(message_advice_checkout_pull_push));\n+}\n+\n static int push_with_options(struct transport *transport, int flags)\n {\n \tint err;\n@@ -135,14 +178,21 @@ static int push_with_options(struct transport *transport, int flags)\n \t\terror(_(\"failed to push some refs to '%s'\"), transport->url);\n \n \terr |= transport_disconnect(transport);\n-\n \tif (!err)\n \t\treturn 0;\n \n-\tif (nonfastforward && advice_push_nonfastforward) {\n-\t\tfprintf(stderr, _(\"To prevent you from losing history, non-fast-forward updates were rejected\\n\"\n-\t\t\t\t\"Merge the remote changes (e.g. 'git pull') before pushing again.  See the\\n\"\n-\t\t\t\t\"'Note about fast-forwards' section of 'git push --help' for details.\\n\"));\n+\tswitch (nonfastforward) {\n+\tdefault:\n+\t\tbreak;\n+\tcase NON_FF_HEAD:\n+\t\tadvise_pull_before_push();\n+\t\tbreak;\n+\tcase NON_FF_OTHER:\n+\t\tif (default_matching_used)\n+\t\t\tadvise_use_upstream();\n+\t\telse\n+\t\t\tadvise_checkout_pull_push();\n+\t\tbreak;\n \t}\n \n \treturn 1;\ndiff --git a/cache.h b/cache.h\nindex e5e1aa4..427b600 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -625,7 +625,8 @@ enum push_default_type {\n \tPUSH_DEFAULT_NOTHING = 0,\n \tPUSH_DEFAULT_MATCHING,\n \tPUSH_DEFAULT_UPSTREAM,\n-\tPUSH_DEFAULT_CURRENT\n+\tPUSH_DEFAULT_CURRENT,\n+\tPUSH_DEFAULT_UNSPECIFIED\n };\n \n extern enum branch_track git_branch_track;\n@@ -1008,7 +1009,6 @@ struct ref {\n \tchar *symref;\n \tunsigned int force:1,\n \t\tmerge:1,\n-\t\tnonfastforward:1,\n \t\tdeletion:1;\n \tenum {\n \t\tREF_STATUS_NONE = 0,\n@@ -1019,6 +1019,10 @@ struct ref {\n \t\tREF_STATUS_REMOTE_REJECT,\n \t\tREF_STATUS_EXPECTING_REPORT\n \t} status;\n+\tenum {\n+\t\tNON_FF_HEAD = 1,\n+\t\tNON_FF_OTHER\n+\t} nonfastforward;\n \tchar *remote_status;\n \tstruct ref *peer_ref; /* when renaming */\n \tchar name[FLEX_ARRAY]; /* more */\ndiff --git a/environment.c b/environment.c\nindex c93b8f4..d7e6c65 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -52,7 +52,7 @@ enum safe_crlf safe_crlf = SAFE_CRLF_WARN;\n unsigned whitespace_rule_cfg = WS_DEFAULT_RULE;\n enum branch_track git_branch_track = BRANCH_TRACK_REMOTE;\n enum rebase_setup_type autorebase = AUTOREBASE_NEVER;\n-enum push_default_type push_default = PUSH_DEFAULT_MATCHING;\n+enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED;\n #ifndef OBJECT_CREATION_MODE\n #define OBJECT_CREATION_MODE OBJECT_CREATION_USES_HARDLINKS\n #endif\ndiff --git a/transport.c b/transport.c\nindex 181f8f2..7864007 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -721,6 +721,10 @@ void transport_print_push_status(const char *dest, struct ref *refs,\n {\n \tstruct ref *ref;\n \tint n = 0;\n+\tunsigned char head_sha1[20];\n+\tchar *head;\n+\n+\thead = resolve_refdup(\"HEAD\", head_sha1, 1, NULL);\n \n \tif (verbose) {\n \t\tfor (ref = refs; ref; ref = ref->next)\n@@ -738,8 +742,13 @@ void transport_print_push_status(const char *dest, struct ref *refs,\n \t\t    ref->status != REF_STATUS_UPTODATE &&\n \t\t    ref->status != REF_STATUS_OK)\n \t\t\tn += print_one_push_status(ref, dest, n, porcelain);\n-\t\tif (ref->status == REF_STATUS_REJECT_NONFASTFORWARD)\n-\t\t\t*nonfastforward = 1;\n+\t\tif (ref->status == REF_STATUS_REJECT_NONFASTFORWARD &&\n+\t\t    *nonfastforward != NON_FF_HEAD) {\n+\t\t\tif (!strcmp(head, ref->name))\n+\t\t\t\t*nonfastforward = NON_FF_HEAD;\n+\t\t\telse\n+\t\t\t\t*nonfastforward = NON_FF_OTHER;\n+\t\t}\n \t}\n }\n \n-- \n1.7.10.rc1.23.g2a051.dirty\n"},{"id":"187303","messageId":"7v8viv962i.fsf@alter.siamese.dyndns.org","threadId":"30003","inReplyTo":"20120320043133.GA2755@gmail.com","subject":"Re: [PATCH v3] push: Provide situational hints for non-fast-forward errors","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-03-20T05:47:49Z","receivedAt":"2012-03-20T05:47:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Christopher Tiwald <christiwald@gmail.com> writes:\n\n>  Changes since v2:\n> \t- Cleaned up commit message language, specifically in scenario\n> \t  one.\n> \t- Created one config variable per piece of non-ff push advice.\n> \t  Additionally, preserved 'pushNonFastForward' as a means of\n> \t  disabling all non-ff push advice. Users who set this\n> \t  config option should see no change to 'git push'.\n\nThis one looks very sensible.  Thanks.\n"},{"id":"187612","messageId":"20120323214114.GB18198@sigill.intra.peff.net","threadId":"30003","inReplyTo":"20120320043133.GA2755@gmail.com","subject":"Re: [PATCH v3] push: Provide situational hints for non-fast-forward errors","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2012-03-23T21:41:14Z","receivedAt":"2012-03-23T21:41:14Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Mar 20, 2012 at 12:31:33AM -0400, Christopher Tiwald wrote:\n\n>  Changes since v2:\n> \t- Cleaned up commit message language, specifically in scenario\n> \t  one.\n> \t- Created one config variable per piece of non-ff push advice.\n> \t  Additionally, preserved 'pushNonFastForward' as a means of\n> \t  disabling all non-ff push advice. Users who set this\n> \t  config option should see no change to 'git push'.\n\nThis version looks pretty good to me, but I have one question:\n\n> @@ -1008,7 +1009,6 @@ struct ref {\n>  \tchar *symref;\n>  \tunsigned int force:1,\n>  \t\tmerge:1,\n> -\t\tnonfastforward:1,\n>  \t\tdeletion:1;\n>  \tenum {\n>  \t\tREF_STATUS_NONE = 0,\n> @@ -1019,6 +1019,10 @@ struct ref {\n>  \t\tREF_STATUS_REMOTE_REJECT,\n>  \t\tREF_STATUS_EXPECTING_REPORT\n>  \t} status;\n> +\tenum {\n> +\t\tNON_FF_HEAD = 1,\n> +\t\tNON_FF_OTHER\n> +\t} nonfastforward;\n>  \tchar *remote_status;\n>  \tstruct ref *peer_ref; /* when renaming */\n>  \tchar name[FLEX_ARRAY]; /* more */\n\nWhy is this enum stored inside the ref? It doesn't actually know whether\nit is a HEAD or not, and we never actually store that value there. We\nalways just store a boolean (remote.c, ll. 1294-1298) and access it as\none (remote.c, l. 1300; transport.c, l. 1259).\n\nThe only time we use the enum values is via the \"int nonfastforward\"\npassed to transport_push.  I think it would be a lot clearer to leave\nnonfastforward as a single bit in the ref, and then define the enum\nelsewhere (or even just use #define if we are not going to use the enum\ntype). Like this on top of your patch:\n\ndiff --git a/cache.h b/cache.h\nindex 427b600..35f3075 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1009,6 +1009,7 @@ struct ref {\n \tchar *symref;\n \tunsigned int force:1,\n \t\tmerge:1,\n+\t\tnonfastforward:1,\n \t\tdeletion:1;\n \tenum {\n \t\tREF_STATUS_NONE = 0,\n@@ -1019,10 +1020,6 @@ struct ref {\n \t\tREF_STATUS_REMOTE_REJECT,\n \t\tREF_STATUS_EXPECTING_REPORT\n \t} status;\n-\tenum {\n-\t\tNON_FF_HEAD = 1,\n-\t\tNON_FF_OTHER\n-\t} nonfastforward;\n \tchar *remote_status;\n \tstruct ref *peer_ref; /* when renaming */\n \tchar name[FLEX_ARRAY]; /* more */\ndiff --git a/transport.h b/transport.h\nindex ce99ef8..1631a35 100644\n--- a/transport.h\n+++ b/transport.h\n@@ -138,6 +138,8 @@ int transport_set_option(struct transport *transport, const char *name,\n void transport_set_verbosity(struct transport *transport, int verbosity,\n \tint force_progress);\n \n+#define NON_FF_HEAD 1\n+#define NON_FF_OTHER 2\n int transport_push(struct transport *connection,\n \t\t   int refspec_nr, const char **refspec, int flags,\n \t\t   int * nonfastforward);\n\n\nI don't think your patch is buggy, because the enum is perfectly capable\nof being used as a single bit. But it's confusing to read, because\nref->nonfastforward will never actually be set to the NON_FF_OTHER enum\nvalue.\n\n-Peff\n"},{"id":"187769","messageId":"20120326192001.GB32387@gmail.com","threadId":"30003","inReplyTo":"20120323214114.GB18198@sigill.intra.peff.net","subject":"Re: [PATCH v3] push: Provide situational hints for non-fast-forward errors","fromName":"Christopher Tiwald","fromEmail":"christiwald@gmail.com","sentAt":"2012-03-26T19:20:01Z","receivedAt":"2012-03-26T19:20:01Z","isPatch":true,"sender":{"key":"christiwald@gmail.com","avatar":"https://avatars.githubusercontent.com/u/667276?v=4"},"body":"On Fri, Mar 23, 2012 at 05:41:14PM -0400, Jeff King wrote:\n> The only time we use the enum values is via the \"int nonfastforward\"\n> passed to transport_push.  I think it would be a lot clearer to leave\n> nonfastforward as a single bit in the ref, and then define the enum\n> elsewhere (or even just use #define if we are not going to use the enum\n> type).\n\nI used the REF_STATUS_* enum as a template for what I wanted to accomplish\nwhen authoring v1, but did notice there was no other place my new\noptions made much sense (Junio helped me remove one other call between v1\nand v2). I like the readability fixup, but it won't compile as both push.c\nand transport.c need to see these. Would something like the following\nwork? It simply moves the define statements to cache.h, so that both push and\ntransport can use them.\n\ndiff --git a/cache.h b/cache.h\nindex 427b600..cb960c6 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1009,6 +1009,7 @@ struct ref {\n \tchar *symref;\n \tunsigned int force:1,\n \t\tmerge:1,\n+\t\tnonfastforward:1,\n \t\tdeletion:1;\n \tenum {\n \t\tREF_STATUS_NONE = 0,\n@@ -1019,15 +1020,14 @@ struct ref {\n \t\tREF_STATUS_REMOTE_REJECT,\n \t\tREF_STATUS_EXPECTING_REPORT\n \t} status;\n-\tenum {\n-\t\tNON_FF_HEAD = 1,\n-\t\tNON_FF_OTHER\n-\t} nonfastforward;\n \tchar *remote_status;\n \tstruct ref *peer_ref; /* when renaming */\n \tchar name[FLEX_ARRAY]; /* more */\n };\n \n+#define NON_FF_HEAD  1\n+#define NON_FF_OTHER 2\n+\n #define REF_NORMAL\t(1u << 0)\n #define REF_HEADS\t(1u << 1)\n #define REF_TAGS\t(1u << 2)\n\n\nIt tests fine locally for me using the same test cases I've been using\nall along.\n\n--\nChristopher Tiwald\n"},{"id":"187774","messageId":"20120326195150.GA13098@sigill.intra.peff.net","threadId":"30003","inReplyTo":"20120326192001.GB32387@gmail.com","subject":"Re: [PATCH v3] push: Provide situational hints for non-fast-forward errors","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2012-03-26T19:51:50Z","receivedAt":"2012-03-26T19:51:50Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Mar 26, 2012 at 03:20:01PM -0400, Christopher Tiwald wrote:\n\n> I used the REF_STATUS_* enum as a template for what I wanted to accomplish\n> when authoring v1, but did notice there was no other place my new\n> options made much sense (Junio helped me remove one other call between v1\n> and v2). I like the readability fixup, but it won't compile as both push.c\n> and transport.c need to see these. Would something like the following\n> work? It simply moves the define statements to cache.h, so that both push and\n> transport can use them.\n\nMy suggestion put them in transport.h, which is included from both\nplaces. It compiles fine for me. Am I missing something?\n\nGenerally I would try to keep their definition near the function\ninterface which uses them (i.e., transport_push). But I don't feel that\nstrongly about it.\n\nYour patch is already in 'next', so we will have to build on top rather\nthan squashing. So here it is with an actual commit message:\n\n-- >8 --\nSubject: [PATCH] clean up struct ref's nonfastforward field\n\nEach ref structure contains a \"nonfastforward\" field which\nis set during push to show whether the ref rewound history.\nOriginally this was a single bit, but it was changed in\nf25950f (push: Provide situational hints for non-fast-forward\nerrors) to an enum differentiating a non-ff of the current\nbranch versus another branch.\n\nHowever, we never actually set the member according to the\nenum values, nor did we ever read it expecting anything but\na boolean value. But we did use the side effect of declaring\nthe enum constants to store those values in a totally\ndifferent integer variable. The code as-is isn't buggy, but\nthe enum declaration inside \"struct ref\" is somewhat\nmisleading.\n\nLet's convert nonfastforward back into a single bit, and\nthen define the NON_FF_* constants closer to where they\nwould be used (they are returned via the \"int *nonfastforward\"\nparameter to transport_push, so we can define them there).\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\nThis is the least-invasive patch. You could also turn the \"int\n*nonfastforward\" into an enum, which might be even more readable.\n\n cache.h     |    5 +----\n transport.h |    2 ++\n 2 files changed, 3 insertions(+), 4 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 427b600..35f3075 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1009,6 +1009,7 @@ struct ref {\n \tchar *symref;\n \tunsigned int force:1,\n \t\tmerge:1,\n+\t\tnonfastforward:1,\n \t\tdeletion:1;\n \tenum {\n \t\tREF_STATUS_NONE = 0,\n@@ -1019,10 +1020,6 @@ struct ref {\n \t\tREF_STATUS_REMOTE_REJECT,\n \t\tREF_STATUS_EXPECTING_REPORT\n \t} status;\n-\tenum {\n-\t\tNON_FF_HEAD = 1,\n-\t\tNON_FF_OTHER\n-\t} nonfastforward;\n \tchar *remote_status;\n \tstruct ref *peer_ref; /* when renaming */\n \tchar name[FLEX_ARRAY]; /* more */\ndiff --git a/transport.h b/transport.h\nindex ce99ef8..1631a35 100644\n--- a/transport.h\n+++ b/transport.h\n@@ -138,6 +138,8 @@ int transport_set_option(struct transport *transport, const char *name,\n void transport_set_verbosity(struct transport *transport, int verbosity,\n \tint force_progress);\n \n+#define NON_FF_HEAD 1\n+#define NON_FF_OTHER 2\n int transport_push(struct transport *connection,\n \t\t   int refspec_nr, const char **refspec, int flags,\n \t\t   int * nonfastforward);\n-- \n1.7.10.rc2.3.g0850\n"},{"id":"187777","messageId":"20120326195743.GD32387@gmail.com","threadId":"30003","inReplyTo":"20120326195150.GA13098@sigill.intra.peff.net","subject":"Re: [PATCH v3] push: Provide situational hints for non-fast-forward errors","fromName":"Christopher Tiwald","fromEmail":"christiwald@gmail.com","sentAt":"2012-03-26T19:57:43Z","receivedAt":"2012-03-26T19:57:43Z","isPatch":true,"sender":{"key":"christiwald@gmail.com","avatar":"https://avatars.githubusercontent.com/u/667276?v=4"},"body":"On Mon, Mar 26, 2012 at 03:51:50PM -0400, Jeff King wrote:\n> On Mon, Mar 26, 2012 at 03:20:01PM -0400, Christopher Tiwald wrote:\n> \n> > I used the REF_STATUS_* enum as a template for what I wanted to accomplish\n> > when authoring v1, but did notice there was no other place my new\n> > options made much sense (Junio helped me remove one other call between v1\n> > and v2). I like the readability fixup, but it won't compile as both push.c\n> > and transport.c need to see these. Would something like the following\n> > work? It simply moves the define statements to cache.h, so that both push and\n> > transport can use them.\n> \n> My suggestion put them in transport.h, which is included from both\n> places. It compiles fine for me. Am I missing something?\n\nAh nope. That was me. Sorry about the noise. This otherwise makes sense\nto me.\n\n--\nChristopher Tiwald\n"},{"id":"187778","messageId":"20120326200020.GA23777@sigill.intra.peff.net","threadId":"30003","inReplyTo":"20120326195743.GD32387@gmail.com","subject":"Re: [PATCH v3] push: Provide situational hints for non-fast-forward errors","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2012-03-26T20:00:20Z","receivedAt":"2012-03-26T20:00:20Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Mar 26, 2012 at 03:57:43PM -0400, Christopher Tiwald wrote:\n\n> > My suggestion put them in transport.h, which is included from both\n> > places. It compiles fine for me. Am I missing something?\n> \n> Ah nope. That was me. Sorry about the noise. This otherwise makes sense\n> to me.\n\nOK. Junio, can you throw the patch from the grandparent on top of\nct/advise-push-default?\n\n-Peff\n"},{"id":"187780","messageId":"7vk427nn4v.fsf@alter.siamese.dyndns.org","threadId":"30003","inReplyTo":"20120326195150.GA13098@sigill.intra.peff.net","subject":"Re: [PATCH v3] push: Provide situational hints for non-fast-forward errors","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-03-26T20:05:52Z","receivedAt":"2012-03-26T20:05:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> Generally I would try to keep their definition near the function\n> interface which uses them (i.e., transport_push). But I don't feel that\n> strongly about it.\n\nI think that advice makes sense.\n\n> Your patch is already in 'next', so we will have to build on top rather\n> than squashing. So here it is with an actual commit message:\n\nIf the patch were already in 'next', we would have to build on top, but I\nthought I kept it out of 'next' because I knew this deserved a bit more\nreview time.  Perhaps I screwed up, or you are reading the history\nincorrectly?\n\n\t... goes and looks ...\n\n> -- >8 --\n> Subject: [PATCH] clean up struct ref's nonfastforward field\n>\n> Each ref structure contains a \"nonfastforward\" field which\n> is set during push to show whether the ref rewound history.\n> Originally this was a single bit, but it was changed in\n> f25950f (push: Provide situational hints for non-fast-forward\n\nWhew. \"git log remotes/ko/next..f25950f\" says we are OK.\n\nI'm however tempted to keep this follow-up patch as separate without\nsquashing.\n"},{"id":"187781","messageId":"20120326201122.GA24138@sigill.intra.peff.net","threadId":"30003","inReplyTo":"7vk427nn4v.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v3] push: Provide situational hints for non-fast-forward errors","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2012-03-26T20:11:22Z","receivedAt":"2012-03-26T20:11:22Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Mar 26, 2012 at 01:05:52PM -0700, Junio C Hamano wrote:\n\n> > Your patch is already in 'next', so we will have to build on top rather\n> > than squashing. So here it is with an actual commit message:\n> \n> If the patch were already in 'next', we would have to build on top, but I\n> thought I kept it out of 'next' because I knew this deserved a bit more\n> review time.  Perhaps I screwed up, or you are reading the history\n> incorrectly?\n> \n> \t... goes and looks ...\n\nOops, you're right. I don't know why I thought it was, and obviously I\nshould check before speaking next time. :)\n\n> I'm however tempted to keep this follow-up patch as separate without\n> squashing.\n\nEither way is fine with me.\n\nBTW, I was on a semi-vacation when Christopher posted the patch, so I\nmissed out on most of the timely review. But I really like how it ended\nup; it's exactly what I was hoping for when we discussed this a month or\ntwo ago. So thanks for working on it, Christopher.\n\n-Peff\n"}]}