{"thread":{"id":"10503","subject":"[PATCH 05/10] rename ref_matches_abbrev() to ref_abbrev_matches_full_with_fetch_rules()","startedAt":"2007-10-28T17:46:11Z","lastAt":"2007-11-02T20:19:58Z","messageCount":53,"participants":["Steffen Prohaska","Junio C Hamano","Andreas Ericsson","Daniel Barkalow","Wincent Colaiuta","Johannes Schindelin","Tom Prince"],"isPatch":true,"patchVersion":1,"patchTotal":10},"messages":[{"id":"57443","messageId":"1193593581312-git-send-email-prohaska@zib.de","threadId":"10503","inReplyTo":null,"subject":"[PATCH 0/10 v3] improve refspec handling in push","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2007-10-28T17:46:11Z","receivedAt":"2007-10-28T17:46:11Z","isPatch":true,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"This is a replacement for sp/push-refspec\n(93e296613306311ef02dabb19a6538be2f52aa1c).\n\nCompared to the v2 series the following changed (v2 patch numbers):\n    1/8 implementation should be better readable.\n    2/8 adjusted to 1/8 changes.\n    3/8 removed.\n    4/8 removed.\n    5/8 much simpler implementation, second patch \"git push HEAD\" added.\n    6/8 chose more explicit naming\n        ref_abbrev_matches_full_with_rev_parse_rules;\n        unified argument order with ref_matches_abbrev,\n        which was renamed to ref_abbrev_matches_full_with_fetch_rules.\n    7/8 adjusted to 6/8 changes.\n    8/8 report summary;\n        --verbose fixed;\n        added test that remote tracking branches are unchanged.\n\nAll tests pass.\n\nHere's a summary of the series:\n\n Documentation/git-http-push.txt |    6 ++\n Documentation/git-push.txt      |   16 +++-\n Documentation/git-send-pack.txt |   18 +++-\n builtin-push.c                  |   23 +++++-\n cache.h                         |    1 +\n http-push.c                     |    9 ++-\n remote.c                        |   50 +++++++-----\n remote.h                        |    2 +-\n send-pack.c                     |   77 +++++++++++++----\n sha1_name.c                     |   14 +++\n t/t5516-fetch-push.sh           |  181 ++++++++++++++++++++++++++++++++++++++-\n transport.c                     |   12 ++-\n transport.h                     |    2 +\n 13 files changed, 358 insertions(+), 53 deletions(-)\n\n [PATCH 01/10] push: change push to fail if short refname does not exist\n [PATCH 02/10] push: teach push new flag --create\n\n [PATCH 03/10] push: support pushing HEAD to real branch name\n [PATCH 04/10] push: add \"git push HEAD\" shorthand for 'push current branch to default repo'\n    Junio doesn't like this patch. But I had it ready, so here it is.\n    Junio described an alternative in\n    http://marc.info/?l=git&m=119358745026345&w=2\n\n [PATCH 05/10] rename ref_matches_abbrev() to ref_abbrev_matches_full_with_fetch_rules()\n [PATCH 06/10] add ref_abbrev_matches_full_with_rev_parse_rules() comparing abbrev with full ref name\n [PATCH 07/10] push: use same rules as git-rev-parse to resolve refspecs\n    Maybe the matching rules could be further unified.\n    Code cleanup would be needed here.\n    But this is a different story.\n\n [PATCH 08/10] push: teach push to accept --verbose option\n [PATCH 09/10] push: teach push to pass --verbose option to transport layer\n [PATCH 10/10] push: teach push to be quiet if local ref is strict subset of remote ref\n\n    Steffen\n"},{"id":"57444","messageId":"11935935812741-git-send-email-prohaska@zib.de","threadId":"10503","inReplyTo":"1193593581312-git-send-email-prohaska@zib.de","subject":"[PATCH 01/10] push: change push to fail if short refname does not exist","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2007-10-28T17:46:12Z","receivedAt":"2007-10-28T17:46:12Z","isPatch":true,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"Pushing a short refname used to create a new ref on on the\nremote side if it did not yet exist. If you specified the wrong\nbranch accidentally it was created. A safety valve that pushes\nonly existing branches may help to avoid errors.\n\nThis commit changes push to fail if the remote ref does not yet\nexist and the refspec does not start with refs/. Remote refs must\nexplicitly be created with their full name. If you specify a\nbranch name that does not yet exist on the remote side, git push\nwill print a suggestion to push the full refname instead.\n\nThe new behaviour is more defensive than the old one. You can\nnow explicitly distinguish between \"push existing branch\" and\n\"create new branch on the remote side\". The old implementation\nallowed the same command line in both cases.\n\nA follow-up patch will add a flag '--create' that provides an\nalternative to using full refnames if creation of new refs is\nintended.\n\nAnother follow-up patch will support \"push origin HEAD\". In this\ncase, the existence check is important. If you're on the wrong\nbranch and push HEAD you may be surprised if a new branch is\ncreated. This can be avoided by requiring either a full ref or\nthe '--create' flag.\n\nThe implementation in this patch is less \"clever\" and hopefully\nbetter readable than an ealier version of the patch. Thanks for\nthe suggestions to Daniel Barkalow <barkalow@iabervon.org>.\n\nSigned-off-by: Steffen Prohaska <prohaska@zib.de>\n---\n remote.c              |   25 ++++++++++++++++---------\n t/t5516-fetch-push.sh |   34 ++++++++++++++++++++++++++++++++--\n 2 files changed, 48 insertions(+), 11 deletions(-)\n\ndiff --git a/remote.c b/remote.c\nindex 170015a..cf6441a 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -610,7 +610,8 @@ static int match_explicit(struct ref *src, struct ref *dst,\n {\n \tstruct ref *matched_src, *matched_dst;\n \n-\tconst char *dst_value = rs->dst;\n+\tconst char *lit_dst_value;\n+\tconst char *search_dst_value;\n \n \tif (rs->pattern)\n \t\treturn errs;\n@@ -637,27 +638,33 @@ static int match_explicit(struct ref *src, struct ref *dst,\n \tif (!matched_src)\n \t\terrs = 1;\n \n-\tif (!dst_value) {\n+\tif (rs->dst) {\n+\t\tlit_dst_value = search_dst_value = rs->dst;\n+\t} else {\n \t\tif (!matched_src)\n \t\t\treturn errs;\n-\t\tdst_value = matched_src->name;\n+\t\tlit_dst_value = rs->src;\n+\t\tsearch_dst_value = matched_src->name;\n \t}\n \n-\tswitch (count_refspec_match(dst_value, dst, &matched_dst)) {\n+\tswitch (count_refspec_match(search_dst_value, dst, &matched_dst)) {\n \tcase 1:\n \t\tbreak;\n \tcase 0:\n-\t\tif (!memcmp(dst_value, \"refs/\", 5))\n-\t\t\tmatched_dst = make_linked_ref(dst_value, dst_tail);\n-\t\telse\n+\t\tif (!memcmp(lit_dst_value , \"refs/\", 5))\n+\t\t\tmatched_dst = make_linked_ref(lit_dst_value, dst_tail);\n+\t\telse {\n \t\t\terror(\"dst refspec %s does not match any \"\n \t\t\t      \"existing ref on the remote and does \"\n-\t\t\t      \"not start with refs/.\", dst_value);\n+\t\t\t      \"not start with refs/.\", lit_dst_value);\n+\t\t\tif (!rs->dst)\n+\t\t\t\terror(\"Did you mean %s?\\n\", search_dst_value);\n+\t\t}\n \t\tbreak;\n \tdefault:\n \t\tmatched_dst = NULL;\n \t\terror(\"dst refspec %s matches more than one.\",\n-\t\t      dst_value);\n+\t\t      lit_dst_value);\n \t\tbreak;\n \t}\n \tif (errs || !matched_dst)\ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex 4fbd5b1..5ba09e2 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -126,6 +126,36 @@ test_expect_success 'push with wildcard' '\n \t)\n '\n \n+test_expect_success 'push nonexisting (1)' '\n+\n+\tmk_test &&\n+\tif git push testrepo master\n+\tthen\n+\t\techo \"Oops, should have failed\"\n+\t\tfalse\n+\tfi\n+\n+'\n+\n+test_expect_success 'push nonexisting (2)' '\n+\n+\tmk_test &&\n+\tif git push testrepo heads/master\n+\tthen\n+\t\techo \"Oops, should have failed\"\n+\t\tfalse\n+\tfi\n+\n+'\n+\n+test_expect_success 'push nonexisting (3)' '\n+\n+\tmk_test &&\n+\tgit push testrepo refs/heads/master &&\n+\tcheck_push_result $the_commit heads/master\n+\n+'\n+\n test_expect_success 'push with matching heads' '\n \n \tmk_test heads/master &&\n@@ -225,7 +255,7 @@ test_expect_success 'push with colon-less refspec (3)' '\n \t\tgit tag -d frotz\n \tfi &&\n \tgit branch -f frotz master &&\n-\tgit push testrepo frotz &&\n+\tgit push testrepo refs/heads/frotz &&\n \tcheck_push_result $the_commit heads/frotz &&\n \ttest 1 = $( cd testrepo && git show-ref | wc -l )\n '\n@@ -238,7 +268,7 @@ test_expect_success 'push with colon-less refspec (4)' '\n \t\tgit branch -D frotz\n \tfi &&\n \tgit tag -f frotz &&\n-\tgit push testrepo frotz &&\n+\tgit push testrepo refs/tags/frotz &&\n \tcheck_push_result $the_commit tags/frotz &&\n \ttest 1 = $( cd testrepo && git show-ref | wc -l )\n \n-- \n1.5.3.4.439.ge8b49\n"},{"id":"57440","messageId":"1193593581114-git-send-email-prohaska@zib.de","threadId":"10503","inReplyTo":"11935935812741-git-send-email-prohaska@zib.de","subject":"[PATCH 02/10] push: teach push new flag --create","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2007-10-28T17:46:13Z","receivedAt":"2007-10-28T17:46:13Z","isPatch":true,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"If you want to push a branch that does not yet exist on the\nremote side you can push using a full refspec. For example you\ncan \"push origin refs/heads/master\".\n\nThis commit changes push such that refs that do not start with\n'refs/' will be created at the remote as the matching local ref\nif --create is used. If you want to create a new ref at the\nremote, you can now say \"git push --create origin master\".\n\nSigned-off-by: Steffen Prohaska <prohaska@zib.de>\n---\n Documentation/git-http-push.txt |    6 ++++++\n Documentation/git-push.txt      |    8 +++++++-\n Documentation/git-send-pack.txt |   14 +++++++++++---\n builtin-push.c                  |    6 +++++-\n http-push.c                     |    9 +++++++--\n remote.c                        |   24 +++++++++++++++---------\n remote.h                        |    2 +-\n send-pack.c                     |    9 +++++++--\n t/t5516-fetch-push.sh           |    8 ++++++++\n transport.c                     |    8 ++++++--\n transport.h                     |    1 +\n 11 files changed, 74 insertions(+), 21 deletions(-)\n\ndiff --git a/Documentation/git-http-push.txt b/Documentation/git-http-push.txt\nindex 3a69b71..8753611 100644\n--- a/Documentation/git-http-push.txt\n+++ b/Documentation/git-http-push.txt\n@@ -30,6 +30,12 @@ OPTIONS\n \tthe remote repository can lose commits; use it with\n \tcare.\n \n+\\--create::\n+\tUsually, the command refuses to create a remote ref that is\n+\tnot specified by its full name, i.e. starting with 'refs/'.\n+\tThis flag tells the command to create the remote ref under\n+\tthe full name of the local matching ref.\n+\n --dry-run::\n \tDo everything except actually send the updates.\n \ndiff --git a/Documentation/git-push.txt b/Documentation/git-push.txt\nindex e5dd4c1..67b354b 100644\n--- a/Documentation/git-push.txt\n+++ b/Documentation/git-push.txt\n@@ -9,7 +9,7 @@ git-push - Update remote refs along with associated objects\n SYNOPSIS\n --------\n [verse]\n-'git-push' [--all] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>]\n+'git-push' [--all] [--dry-run] [--create] [--tags] [--receive-pack=<git-receive-pack>]\n            [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]\n \n DESCRIPTION\n@@ -86,6 +86,12 @@ the remote repository.\n \tThis flag disables the check.  This can cause the\n \tremote repository to lose commits; use it with care.\n \n+\\--create::\n+\tUsually, the command refuses to create a remote ref that is\n+\tnot specified by its full name, i.e. starting with 'refs/'.\n+\tThis flag tells the command to create the remote ref under\n+\tthe full name of the local matching ref.\n+\n \\--repo=<repo>::\n \tWhen no repository is specified the command defaults to\n \t\"origin\"; this overrides it.\ndiff --git a/Documentation/git-send-pack.txt b/Documentation/git-send-pack.txt\nindex 2fa01d4..01495df 100644\n--- a/Documentation/git-send-pack.txt\n+++ b/Documentation/git-send-pack.txt\n@@ -44,6 +44,12 @@ OPTIONS\n \tthe remote repository can lose commits; use it with\n \tcare.\n \n+\\--create::\n+\tUsually, the command refuses to create a remote ref that is\n+\tnot specified by its full name, i.e. starting with 'refs/'.\n+\tThis flag tells the command to create the remote ref under\n+\tthe full name of the local matching ref.\n+\n \\--verbose::\n \tRun verbosely.\n \n@@ -97,9 +103,11 @@ destination side.\n    * it has to start with \"refs/\"; <dst> is used as the\n      destination literally in this case.\n \n-   * <src> == <dst> and the ref that matched the <src> must not\n-     exist in the set of remote refs; the ref matched <src>\n-     locally is used as the name of the destination.\n+   * Only <src> is specified and the ref that matched\n+     <src> must not exist in the set of remote refs;\n+     and the '--create' flag is used;\n+     the ref matched <src> locally is used as the name of\n+     the destination.\n \n Without '--force', the <src> ref is stored at the remote only if\n <dst> does not exist, or <dst> is a proper subset (i.e. an\ndiff --git a/builtin-push.c b/builtin-push.c\nindex 4b39ef3..4ab1401 100644\n--- a/builtin-push.c\n+++ b/builtin-push.c\n@@ -8,7 +8,7 @@\n #include \"remote.h\"\n #include \"transport.h\"\n \n-static const char push_usage[] = \"git-push [--all] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]\";\n+static const char push_usage[] = \"git-push [--all] [--dry-run] [--create] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]\";\n \n static int thin, verbose;\n static const char *receivepack;\n@@ -113,6 +113,10 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n \t\t\tflags |= TRANSPORT_PUSH_DRY_RUN;\n \t\t\tcontinue;\n \t\t}\n+\t\tif (!strcmp(arg, \"--create\")) {\n+\t\t\tflags |= TRANSPORT_PUSH_CREATE;\n+\t\t\tcontinue;\n+\t\t}\n \t\tif (!strcmp(arg, \"--tags\")) {\n \t\t\tadd_refspec(\"refs/tags/*\");\n \t\t\tcontinue;\ndiff --git a/http-push.c b/http-push.c\nindex c02a3af..4ad9f26 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -13,7 +13,7 @@\n #include <expat.h>\n \n static const char http_push_usage[] =\n-\"git-http-push [--all] [--dry-run] [--force] [--verbose] <remote> [<head>...]\\n\";\n+\"git-http-push [--all] [--dry-run] [--create] [--force] [--verbose] <remote> [<head>...]\\n\";\n \n #ifndef XML_STATUS_OK\n enum XML_Status {\n@@ -81,6 +81,7 @@ static int push_verbosely;\n static int push_all;\n static int force_all;\n static int dry_run;\n+static int create;\n \n static struct object_list *objects;\n \n@@ -2307,6 +2308,10 @@ int main(int argc, char **argv)\n \t\t\t\tdry_run = 1;\n \t\t\t\tcontinue;\n \t\t\t}\n+\t\t\tif (!strcmp(arg, \"--create\")) {\n+\t\t\t\tcreate = 1;\n+\t\t\t\tcontinue;\n+\t\t\t}\n \t\t\tif (!strcmp(arg, \"--verbose\")) {\n \t\t\t\tpush_verbosely = 1;\n \t\t\t\tcontinue;\n@@ -2389,7 +2394,7 @@ int main(int argc, char **argv)\n \tif (!remote_tail)\n \t\tremote_tail = &remote_refs;\n \tif (match_refs(local_refs, remote_refs, &remote_tail,\n-\t\t       nr_refspec, refspec, push_all))\n+\t\t       nr_refspec, refspec, push_all, create))\n \t\treturn -1;\n \tif (!remote_refs) {\n \t\tfprintf(stderr, \"No refs in common and none specified; doing nothing.\\n\");\ndiff --git a/remote.c b/remote.c\nindex cf6441a..687eb8e 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -606,7 +606,7 @@ static struct ref *make_linked_ref(const char *name, struct ref ***tail)\n static int match_explicit(struct ref *src, struct ref *dst,\n \t\t\t  struct ref ***dst_tail,\n \t\t\t  struct refspec *rs,\n-\t\t\t  int errs)\n+\t\t\t  int errs, int create)\n {\n \tstruct ref *matched_src, *matched_dst;\n \n@@ -653,13 +653,19 @@ static int match_explicit(struct ref *src, struct ref *dst,\n \tcase 0:\n \t\tif (!memcmp(lit_dst_value , \"refs/\", 5))\n \t\t\tmatched_dst = make_linked_ref(lit_dst_value, dst_tail);\n-\t\telse {\n+\t\telse if (!memcmp(search_dst_value, \"refs/\", 5))\n+\t\t\tif (create)\n+\t\t\t\tmatched_dst = make_linked_ref(search_dst_value, dst_tail);\n+\t\t\telse\n+\t\t\t\terror(\"dst refspec %s does not match any \"\n+\t\t\t\t      \"existing ref on the remote.\\n\"\n+\t\t\t\t      \"To create it use --create \"\n+\t\t\t\t      \"or the full ref %s.\",\n+\t\t\t\t       lit_dst_value, search_dst_value);\n+\t\telse\n \t\t\terror(\"dst refspec %s does not match any \"\n \t\t\t      \"existing ref on the remote and does \"\n \t\t\t      \"not start with refs/.\", lit_dst_value);\n-\t\t\tif (!rs->dst)\n-\t\t\t\terror(\"Did you mean %s?\\n\", search_dst_value);\n-\t\t}\n \t\tbreak;\n \tdefault:\n \t\tmatched_dst = NULL;\n@@ -683,11 +689,11 @@ static int match_explicit(struct ref *src, struct ref *dst,\n \n static int match_explicit_refs(struct ref *src, struct ref *dst,\n \t\t\t       struct ref ***dst_tail, struct refspec *rs,\n-\t\t\t       int rs_nr)\n+\t\t\t       int rs_nr, int create)\n {\n \tint i, errs;\n \tfor (i = errs = 0; i < rs_nr; i++)\n-\t\terrs |= match_explicit(src, dst, dst_tail, &rs[i], errs);\n+\t\terrs |= match_explicit(src, dst, dst_tail, &rs[i], errs, create);\n \treturn -errs;\n }\n \n@@ -717,12 +723,12 @@ static const struct refspec *check_pattern_match(const struct refspec *rs,\n  * without thinking.\n  */\n int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,\n-\t       int nr_refspec, char **refspec, int all)\n+\t       int nr_refspec, char **refspec, int all, int create)\n {\n \tstruct refspec *rs =\n \t\tparse_ref_spec(nr_refspec, (const char **) refspec);\n \n-\tif (match_explicit_refs(src, dst, dst_tail, rs, nr_refspec))\n+\tif (match_explicit_refs(src, dst, dst_tail, rs, nr_refspec, create))\n \t\treturn -1;\n \n \t/* pick the remainder */\ndiff --git a/remote.h b/remote.h\nindex c62636d..7d731b1 100644\n--- a/remote.h\n+++ b/remote.h\n@@ -57,7 +57,7 @@ void ref_remove_duplicates(struct ref *ref_map);\n struct refspec *parse_ref_spec(int nr_refspec, const char **refspec);\n \n int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,\n-\t       int nr_refspec, char **refspec, int all);\n+\t       int nr_refspec, char **refspec, int all, int create);\n \n /*\n  * Given a list of the remote refs and the specification of things to\ndiff --git a/send-pack.c b/send-pack.c\nindex e9b9a39..77acae1 100644\n--- a/send-pack.c\n+++ b/send-pack.c\n@@ -7,7 +7,7 @@\n #include \"remote.h\"\n \n static const char send_pack_usage[] =\n-\"git-send-pack [--all] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\\n\"\n+\"git-send-pack [--all] [--dry-run] [--create] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\\n\"\n \"  --all and explicit <ref> specification are mutually exclusive.\";\n static const char *receivepack = \"git-receive-pack\";\n static int verbose;\n@@ -15,6 +15,7 @@ static int send_all;\n static int force_update;\n static int use_thin_pack;\n static int dry_run;\n+static int create;\n \n /*\n  * Make a pack stream and spit it out into file descriptor fd\n@@ -201,7 +202,7 @@ static int send_pack(int in, int out, struct remote *remote, int nr_refspec, cha\n \tif (!remote_tail)\n \t\tremote_tail = &remote_refs;\n \tif (match_refs(local_refs, remote_refs, &remote_tail,\n-\t\t       nr_refspec, refspec, send_all))\n+\t\t       nr_refspec, refspec, send_all, create))\n \t\treturn -1;\n \n \tif (!remote_refs) {\n@@ -398,6 +399,10 @@ int main(int argc, char **argv)\n \t\t\t\tdry_run = 1;\n \t\t\t\tcontinue;\n \t\t\t}\n+\t\t\tif (!strcmp(arg, \"--create\")) {\n+\t\t\t\tcreate = 1;\n+\t\t\t\tcontinue;\n+\t\t\t}\n \t\t\tif (!strcmp(arg, \"--force\")) {\n \t\t\t\tforce_update = 1;\n \t\t\t\tcontinue;\ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex 5ba09e2..42ca0ff 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -156,6 +156,14 @@ test_expect_success 'push nonexisting (3)' '\n \n '\n \n+test_expect_success 'push nonexisting (4)' '\n+\n+\tmk_test &&\n+\tgit push testrepo --create master &&\n+\tcheck_push_result $the_commit heads/master\n+\n+'\n+\n test_expect_success 'push with matching heads' '\n \n \tmk_test heads/master &&\ndiff --git a/transport.c b/transport.c\nindex 400af71..fbdbd0d 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -385,7 +385,7 @@ static int curl_transport_push(struct transport *transport, int refspec_nr, cons\n \tint argc;\n \tint err;\n \n-\targv = xmalloc((refspec_nr + 11) * sizeof(char *));\n+\targv = xmalloc((refspec_nr + 12) * sizeof(char *));\n \targv[0] = \"http-push\";\n \targc = 1;\n \tif (flags & TRANSPORT_PUSH_ALL)\n@@ -394,6 +394,8 @@ static int curl_transport_push(struct transport *transport, int refspec_nr, cons\n \t\targv[argc++] = \"--force\";\n \tif (flags & TRANSPORT_PUSH_DRY_RUN)\n \t\targv[argc++] = \"--dry-run\";\n+\tif (flags & TRANSPORT_PUSH_CREATE)\n+\t\targv[argc++] = \"--create\";\n \targv[argc++] = transport->url;\n \twhile (refspec_nr--)\n \t\targv[argc++] = *refspec++;\n@@ -658,7 +660,7 @@ static int git_transport_push(struct transport *transport, int refspec_nr, const\n \tint argc;\n \tint err;\n \n-\targv = xmalloc((refspec_nr + 11) * sizeof(char *));\n+\targv = xmalloc((refspec_nr + 12) * sizeof(char *));\n \targv[0] = \"send-pack\";\n \targc = 1;\n \tif (flags & TRANSPORT_PUSH_ALL)\n@@ -667,6 +669,8 @@ static int git_transport_push(struct transport *transport, int refspec_nr, const\n \t\targv[argc++] = \"--force\";\n \tif (flags & TRANSPORT_PUSH_DRY_RUN)\n \t\targv[argc++] = \"--dry-run\";\n+\tif (flags & TRANSPORT_PUSH_CREATE)\n+\t\targv[argc++] = \"--create\";\n \tif (data->receivepack) {\n \t\tchar *rp = xmalloc(strlen(data->receivepack) + 16);\n \t\tsprintf(rp, \"--receive-pack=%s\", data->receivepack);\ndiff --git a/transport.h b/transport.h\nindex df12ea7..1d6a926 100644\n--- a/transport.h\n+++ b/transport.h\n@@ -30,6 +30,7 @@ struct transport {\n #define TRANSPORT_PUSH_ALL 1\n #define TRANSPORT_PUSH_FORCE 2\n #define TRANSPORT_PUSH_DRY_RUN 4\n+#define TRANSPORT_PUSH_CREATE 8\n \n /* Returns a transport suitable for the url */\n struct transport *transport_get(struct remote *, const char *);\n-- \n1.5.3.4.439.ge8b49\n"},{"id":"57442","messageId":"1193593581486-git-send-email-prohaska@zib.de","threadId":"10503","inReplyTo":"1193593581114-git-send-email-prohaska@zib.de","subject":"[PATCH 03/10] push: support pushing HEAD to real branch name","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2007-10-28T17:46:14Z","receivedAt":"2007-10-28T17:46:14Z","isPatch":true,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"This teaches \"push <remote> HEAD\" to resolve HEAD on the local\nside to its real branch name, e.g. master, and then act as if\nthe real branch name was specified. So we have a shorthand for\npushing the current branch. Besides HEAD, no other symbolic ref\nis resolved.\n\nThanks to Daniel Barkalow <barkalow@iabervon.org> for suggesting\nthis implementation, which is much simpler than the\nimplementation proposed before.\n\nSigned-off-by: Steffen Prohaska <prohaska@zib.de>\n---\n builtin-push.c        |    9 +++++++++\n t/t5516-fetch-push.sh |   31 +++++++++++++++++++++++++++++++\n 2 files changed, 40 insertions(+), 0 deletions(-)\n\ndiff --git a/builtin-push.c b/builtin-push.c\nindex 4ab1401..2e3c8c6 100644\n--- a/builtin-push.c\n+++ b/builtin-push.c\n@@ -40,6 +40,15 @@ static void set_refspecs(const char **refs, int nr)\n \t\t\tstrcat(tag, refs[i]);\n \t\t\tref = tag;\n \t\t}\n+\t\tif (!strcmp(\"HEAD\", ref)) {\n+\t\t\tunsigned char sha1_dummy[20];\n+\t\t\tref = resolve_ref(ref, sha1_dummy, 1, NULL);\n+\t\t\tif (!ref)\n+\t\t\t\tdie(\"HEAD cannot be resolved.\");\n+\t\t\tif (strncmp(ref, \"refs/heads/\", 11))\n+\t\t\t\tdie(\"HEAD cannot be resolved to branch.\");\n+\t\t\tref = xstrdup(ref + 11);\n+\t\t}\n \t\tadd_refspec(ref);\n \t}\n }\ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex 42ca0ff..8becaf8 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -282,6 +282,37 @@ test_expect_success 'push with colon-less refspec (4)' '\n \n '\n \n+test_expect_success 'push with HEAD' '\n+\n+\tmk_test heads/master &&\n+\tgit checkout master &&\n+\tgit push testrepo HEAD &&\n+\tcheck_push_result $the_commit heads/master\n+\n+'\n+\n+test_expect_success 'push with HEAD (--create)' '\n+\n+\tmk_test &&\n+\tgit checkout master &&\n+\tgit push --create testrepo HEAD &&\n+\tcheck_push_result $the_commit heads/master\n+\n+'\n+\n+test_expect_success 'push with HEAD nonexisting at remote' '\n+\n+\tmk_test heads/master &&\n+\tgit checkout -b local master &&\n+\tif git push testrepo HEAD\n+\tthen\n+\t\techo \"Oops, should have failed\"\n+\t\tfalse\n+\telse\n+\t\tcheck_push_result $the_first_commit heads/master\n+\tfi\n+'\n+\n test_expect_success 'push with dry-run' '\n \n \tmk_test heads/master &&\n-- \n1.5.3.4.439.ge8b49\n"},{"id":"57446","messageId":"11935935812185-git-send-email-prohaska@zib.de","threadId":"10503","inReplyTo":"1193593581486-git-send-email-prohaska@zib.de","subject":"[PATCH 04/10] push: add \"git push HEAD\" shorthand for 'push current branch to default repo'","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2007-10-28T17:46:15Z","receivedAt":"2007-10-28T17:46:15Z","isPatch":true,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"Sometimes it is handy to push only the current branch to the\ndefault remote repository. For example, if you created a branch\nusing the '--track' option git knows that the current branch\nis linked to a specific remote. But up to now you needed to say\n\"git push <defaultremote> <thisbranch>\", which was quite\nannoying.  You could have said \"git push\" but then _all_ branches\nwould have been pushed to the default remote.\n\nThis commit introduces \"git push HEAD\", which resolves HEAD to\nthe current branch and pushes only the current branch to its\ndefault remote.\n\nSetups that have a remote named HEAD will break. But such a setup\nif unlikely to exist; and is not very sensible anyway.\n\nSigned-off-by: Steffen Prohaska <prohaska@zib.de>\n---\n Documentation/git-push.txt |    6 +++++-\n builtin-push.c             |    2 ++\n t/t5516-fetch-push.sh      |   12 ++++++++++++\n 3 files changed, 19 insertions(+), 1 deletions(-)\n\ndiff --git a/Documentation/git-push.txt b/Documentation/git-push.txt\nindex 67b354b..236898f 100644\n--- a/Documentation/git-push.txt\n+++ b/Documentation/git-push.txt\n@@ -10,7 +10,7 @@ SYNOPSIS\n --------\n [verse]\n 'git-push' [--all] [--dry-run] [--create] [--tags] [--receive-pack=<git-receive-pack>]\n-           [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]\n+           [--repo=all] [-f | --force] [-v] [HEAD | <repository> <refspec>...]\n \n DESCRIPTION\n -----------\n@@ -25,6 +25,10 @@ documentation for gitlink:git-receive-pack[1].\n \n OPTIONS\n -------\n+HEAD::\n+\tTells push to push the current branch to the default\n+\tremote repository.\n+\n <repository>::\n \tThe \"remote\" repository that is destination of a push\n \toperation.  See the section <<URLS,GIT URLS>> below.\ndiff --git a/builtin-push.c b/builtin-push.c\nindex 2e3c8c6..7c08e19 100644\n--- a/builtin-push.c\n+++ b/builtin-push.c\n@@ -102,6 +102,8 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n \t\tconst char *arg = argv[i];\n \n \t\tif (arg[0] != '-') {\n+\t\t\tif (!strcmp(\"HEAD\", arg))\n+\t\t\t\tbreak;\n \t\t\trepo = arg;\n \t\t\ti++;\n \t\t\tbreak;\ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex 8becaf8..2650e36 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -291,6 +291,18 @@ test_expect_success 'push with HEAD' '\n \n '\n \n+test_expect_success 'push HEAD' '\n+\n+\tmk_test heads/track &&\n+\tgit remote add test testrepo &&\n+\tgit fetch test &&\n+\tgit checkout -b track test/track &&\n+\tgit reset --hard master &&\n+\tgit push HEAD &&\n+\tcheck_push_result $the_commit heads/track\n+\n+'\n+\n test_expect_success 'push with HEAD (--create)' '\n \n \tmk_test &&\n-- \n1.5.3.4.439.ge8b49\n"},{"id":"57439","messageId":"11935935822846-git-send-email-prohaska@zib.de","threadId":"10503","inReplyTo":"11935935812185-git-send-email-prohaska@zib.de","subject":"[PATCH 05/10] rename ref_matches_abbrev() to ref_abbrev_matches_full_with_fetch_rules()","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2007-10-28T17:46:16Z","receivedAt":"2007-10-28T17:46:16Z","isPatch":true,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"The new naming makes the order of the arguments and the rules used\nfor matching more explicit. This will avoid confusion with\nref_abbrev_matches_full_with_rev_parse_rules(), which will be\nintroduced in a follow-up commit.\n\nSigned-off-by: Steffen Prohaska <prohaska@zib.de>\n---\n remote.c |    6 +++---\n 1 files changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/remote.c b/remote.c\nindex 687eb8e..59e6485 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -421,7 +421,7 @@ int remote_has_url(struct remote *remote, const char *url)\n  * Returns true if, under the matching rules for fetching, name is the\n  * same as the given full name.\n  */\n-static int ref_matches_abbrev(const char *name, const char *full)\n+static int ref_abbrev_matches_full_with_fetch_rules(const char *name, const char *full)\n {\n \tif (!prefixcmp(name, \"refs/\") || !strcmp(name, \"HEAD\"))\n \t\treturn !strcmp(name, full);\n@@ -820,7 +820,7 @@ int branch_merge_matches(struct branch *branch,\n {\n \tif (!branch || i < 0 || i >= branch->merge_nr)\n \t\treturn 0;\n-\treturn ref_matches_abbrev(branch->merge[i]->src, refname);\n+\treturn ref_abbrev_matches_full_with_fetch_rules(branch->merge[i]->src, refname);\n }\n \n static struct ref *get_expanded_map(struct ref *remote_refs,\n@@ -859,7 +859,7 @@ static struct ref *find_ref_by_name_abbrev(struct ref *refs, const char *name)\n {\n \tstruct ref *ref;\n \tfor (ref = refs; ref; ref = ref->next) {\n-\t\tif (ref_matches_abbrev(name, ref->name))\n+\t\tif (ref_abbrev_matches_full_with_fetch_rules(name, ref->name))\n \t\t\treturn ref;\n \t}\n \treturn NULL;\n-- \n1.5.3.4.439.ge8b49\n"},{"id":"57445","messageId":"11935935821136-git-send-email-prohaska@zib.de","threadId":"10503","inReplyTo":"11935935822846-git-send-email-prohaska@zib.de","subject":"[PATCH 06/10] add ref_abbrev_matches_full_with_rev_parse_rules() comparing abbrev with full ref name","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2007-10-28T17:46:17Z","receivedAt":"2007-10-28T17:46:17Z","isPatch":true,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"ref_abbrev_matches_full_with_rev_parse_rules(abbrev_name, full_name)\nexpands abbrev_name according to the rules documented in\ngit-rev-parse and compares the expanded name with full_name. It\nreports a match by returning 0.\n\nThis function makes the rules for resolving refs to sha1s available\nfor string comparison. Before this change, the rules were buried in\nget_sha1*() and dwim_ref().\n\nThe function name is very long to make the rule set used\nexplicit. We have a different set of rules for matching refspecs.\nIt would be a good thing to unify all different rule sets. But\nthis commit doesn't address this challenge. It only makes the\ngit-rev-parse rules available for string comparison.\n\nref_abbrev_matches_full_with_rev_parse_rules() will be used for\nmatching refspecs in git-send-pack.\n\nThanks to Daniel Barkalow <barkalow@iabervon.org> for pointing\nout that ref_matches_abbrev in remote.c solves a similar problem\nand care should be take to avoid confusion.\n\nSigned-off-by: Steffen Prohaska <prohaska@zib.de>\n---\n cache.h     |    1 +\n sha1_name.c |   14 ++++++++++++++\n 2 files changed, 15 insertions(+), 0 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 27485d3..bb10ade 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -405,6 +405,7 @@ extern int get_sha1_hex(const char *hex, unsigned char *sha1);\n extern char *sha1_to_hex(const unsigned char *sha1);\t/* static buffer result! */\n extern int read_ref(const char *filename, unsigned char *sha1);\n extern const char *resolve_ref(const char *path, unsigned char *sha1, int, int *);\n+extern int ref_abbrev_matches_full_with_rev_parse_rules(const char *abbrev_name, const char *full_name);\n extern int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref);\n extern int dwim_log(const char *str, int len, unsigned char *sha1, char **ref);\n \ndiff --git a/sha1_name.c b/sha1_name.c\nindex 2d727d5..944e318 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -249,6 +249,20 @@ static const char *ref_fmt[] = {\n \tNULL\n };\n \n+int ref_abbrev_matches_full_with_rev_parse_rules(const char *abbrev_name, const char *full_name)\n+{\n+\tconst char **p;\n+\tconst int abbrev_name_len = strlen(abbrev_name);\n+\n+\tfor (p = ref_fmt; *p; p++) {\n+\t\tif (!strcmp(full_name, mkpath(*p, abbrev_name_len, abbrev_name))) {\n+\t\t\treturn 0;\n+\t\t}\n+\t}\n+\n+\treturn -1;\n+}\n+\n int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref)\n {\n \tconst char **p, *r;\n-- \n1.5.3.4.439.ge8b49\n"},{"id":"57447","messageId":"11935935823045-git-send-email-prohaska@zib.de","threadId":"10503","inReplyTo":"11935935821136-git-send-email-prohaska@zib.de","subject":"[PATCH 07/10] push: use same rules as git-rev-parse to resolve refspecs","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2007-10-28T17:46:18Z","receivedAt":"2007-10-28T17:46:18Z","isPatch":true,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"This commit changes the rules for resolving refspecs to match the\nrules for resolving refs in rev-parse. git-rev-parse uses clear rules\nto resolve a short ref to its full name, which are well documented.\nThe rules for resolving refspecs documented in git-send-pack were\nless strict and harder to understand. This commit replaces them by\nthe rules of git-rev-parse.\n\nThe unified rules are easier to understand and better resolve ambiguous\ncases. You can now push from a repository containing several branches\nending on the same short name.\n\nNote, this may break existing setups. For example \"master\" will no longer\nresolve to \"origin/master\".\n\nSigned-off-by: Steffen Prohaska <prohaska@zib.de>\n---\n Documentation/git-send-pack.txt |    4 +++-\n remote.c                        |    5 +----\n t/t5516-fetch-push.sh           |   12 +++++++++++-\n 3 files changed, 15 insertions(+), 6 deletions(-)\n\ndiff --git a/Documentation/git-send-pack.txt b/Documentation/git-send-pack.txt\nindex 01495df..08bcc25 100644\n--- a/Documentation/git-send-pack.txt\n+++ b/Documentation/git-send-pack.txt\n@@ -91,7 +91,9 @@ Each pattern pair consists of the source side (before the colon)\n and the destination side (after the colon).  The ref to be\n pushed is determined by finding a match that matches the source\n side, and where it is pushed is determined by using the\n-destination side.\n+destination side. The rules used to match a ref are the same\n+rules used by gitlink:git-rev-parse[1] to resolve a symbolic ref\n+name.\n \n  - It is an error if <src> does not match exactly one of the\n    local refs.\ndiff --git a/remote.c b/remote.c\nindex 59e6485..9c33fcf 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -519,10 +519,7 @@ static int count_refspec_match(const char *pattern,\n \t\tchar *name = refs->name;\n \t\tint namelen = strlen(name);\n \n-\t\tif (namelen < patlen ||\n-\t\t    memcmp(name + namelen - patlen, pattern, patlen))\n-\t\t\tcontinue;\n-\t\tif (namelen != patlen && name[namelen - patlen - 1] != '/')\n+\t\tif (ref_abbrev_matches_full_with_rev_parse_rules(pattern, name))\n \t\t\tcontinue;\n \n \t\t/* A match is \"weak\" if it is with refs outside\ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex 2650e36..6708ec1 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -183,11 +183,21 @@ test_expect_success 'push with no ambiguity (1)' '\n test_expect_success 'push with no ambiguity (2)' '\n \n \tmk_test remotes/origin/master &&\n-\tgit push testrepo master:master &&\n+\tgit push testrepo master:origin/master &&\n \tcheck_push_result $the_commit remotes/origin/master\n \n '\n \n+test_expect_success 'push with colon-less refspec, no ambiguity' '\n+\n+\tmk_test heads/master heads/t/master &&\n+\tgit branch -f t/master master &&\n+\tgit push testrepo master &&\n+\tcheck_push_result $the_commit heads/master &&\n+\tcheck_push_result $the_first_commit heads/t/master\n+\n+'\n+\n test_expect_success 'push with weak ambiguity (1)' '\n \n \tmk_test heads/master remotes/origin/master &&\n-- \n1.5.3.4.439.ge8b49\n"},{"id":"57448","messageId":"11935935821800-git-send-email-prohaska@zib.de","threadId":"10503","inReplyTo":"11935935823045-git-send-email-prohaska@zib.de","subject":"[PATCH 08/10] push: teach push to accept --verbose option","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2007-10-28T17:46:19Z","receivedAt":"2007-10-28T17:46:19Z","isPatch":true,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"Before this commit, git push only knew '-v'.\n\nSigned-off-by: Steffen Prohaska <prohaska@zib.de>\n---\n Documentation/git-push.txt |    4 ++--\n builtin-push.c             |    4 ++++\n 2 files changed, 6 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-push.txt b/Documentation/git-push.txt\nindex 236898f..865f183 100644\n--- a/Documentation/git-push.txt\n+++ b/Documentation/git-push.txt\n@@ -10,7 +10,7 @@ SYNOPSIS\n --------\n [verse]\n 'git-push' [--all] [--dry-run] [--create] [--tags] [--receive-pack=<git-receive-pack>]\n-           [--repo=all] [-f | --force] [-v] [HEAD | <repository> <refspec>...]\n+           [--repo=all] [-f | --force] [-v | --verbose] [HEAD | <repository> <refspec>...]\n \n DESCRIPTION\n -----------\n@@ -105,7 +105,7 @@ the remote repository.\n \ttransfer spends extra cycles to minimize the number of\n \tobjects to be sent and meant to be used on slower connection.\n \n--v::\n+-v, \\--verbose::\n \tRun verbosely.\n \n include::urls-remotes.txt[]\ndiff --git a/builtin-push.c b/builtin-push.c\nindex 7c08e19..9103d57 100644\n--- a/builtin-push.c\n+++ b/builtin-push.c\n@@ -112,6 +112,10 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n \t\t\tverbose=1;\n \t\t\tcontinue;\n \t\t}\n+\t\tif (!strcmp(arg, \"--verbose\")) {\n+\t\t\tverbose=1;\n+\t\t\tcontinue;\n+\t\t}\n \t\tif (!prefixcmp(arg, \"--repo=\")) {\n \t\t\trepo = arg+7;\n \t\t\tcontinue;\n-- \n1.5.3.4.439.ge8b49\n"},{"id":"57449","messageId":"11935935823496-git-send-email-prohaska@zib.de","threadId":"10503","inReplyTo":"11935935821800-git-send-email-prohaska@zib.de","subject":"[PATCH 09/10] push: teach push to pass --verbose option to transport layer","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2007-10-28T17:46:20Z","receivedAt":"2007-10-28T17:46:20Z","isPatch":true,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"A --verbose option to push should also be passed to the\ntransport layer, i.e. git-send-pack, git-http-push.\n\ngit push is modified to do so.\n\nSigned-off-by: Steffen Prohaska <prohaska@zib.de>\n---\n builtin-push.c |    2 ++\n transport.c    |    8 ++++++--\n transport.h    |    1 +\n 3 files changed, 9 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin-push.c b/builtin-push.c\nindex 9103d57..27eaca5 100644\n--- a/builtin-push.c\n+++ b/builtin-push.c\n@@ -110,10 +110,12 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n \t\t}\n \t\tif (!strcmp(arg, \"-v\")) {\n \t\t\tverbose=1;\n+\t\t\tflags |= TRANSPORT_PUSH_VERBOSE;\n \t\t\tcontinue;\n \t\t}\n \t\tif (!strcmp(arg, \"--verbose\")) {\n \t\t\tverbose=1;\n+\t\t\tflags |= TRANSPORT_PUSH_VERBOSE;\n \t\t\tcontinue;\n \t\t}\n \t\tif (!prefixcmp(arg, \"--repo=\")) {\ndiff --git a/transport.c b/transport.c\nindex fbdbd0d..e6bca93 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -385,7 +385,7 @@ static int curl_transport_push(struct transport *transport, int refspec_nr, cons\n \tint argc;\n \tint err;\n \n-\targv = xmalloc((refspec_nr + 12) * sizeof(char *));\n+\targv = xmalloc((refspec_nr + 13) * sizeof(char *));\n \targv[0] = \"http-push\";\n \targc = 1;\n \tif (flags & TRANSPORT_PUSH_ALL)\n@@ -396,6 +396,8 @@ static int curl_transport_push(struct transport *transport, int refspec_nr, cons\n \t\targv[argc++] = \"--dry-run\";\n \tif (flags & TRANSPORT_PUSH_CREATE)\n \t\targv[argc++] = \"--create\";\n+\tif (flags & TRANSPORT_PUSH_VERBOSE)\n+\t\targv[argc++] = \"--verbose\";\n \targv[argc++] = transport->url;\n \twhile (refspec_nr--)\n \t\targv[argc++] = *refspec++;\n@@ -660,7 +662,7 @@ static int git_transport_push(struct transport *transport, int refspec_nr, const\n \tint argc;\n \tint err;\n \n-\targv = xmalloc((refspec_nr + 12) * sizeof(char *));\n+\targv = xmalloc((refspec_nr + 13) * sizeof(char *));\n \targv[0] = \"send-pack\";\n \targc = 1;\n \tif (flags & TRANSPORT_PUSH_ALL)\n@@ -671,6 +673,8 @@ static int git_transport_push(struct transport *transport, int refspec_nr, const\n \t\targv[argc++] = \"--dry-run\";\n \tif (flags & TRANSPORT_PUSH_CREATE)\n \t\targv[argc++] = \"--create\";\n+\tif (flags & TRANSPORT_PUSH_VERBOSE)\n+\t\targv[argc++] = \"--verbose\";\n \tif (data->receivepack) {\n \t\tchar *rp = xmalloc(strlen(data->receivepack) + 16);\n \t\tsprintf(rp, \"--receive-pack=%s\", data->receivepack);\ndiff --git a/transport.h b/transport.h\nindex 1d6a926..a387eed 100644\n--- a/transport.h\n+++ b/transport.h\n@@ -31,6 +31,7 @@ struct transport {\n #define TRANSPORT_PUSH_FORCE 2\n #define TRANSPORT_PUSH_DRY_RUN 4\n #define TRANSPORT_PUSH_CREATE 8\n+#define TRANSPORT_PUSH_VERBOSE 16\n \n /* Returns a transport suitable for the url */\n struct transport *transport_get(struct remote *, const char *);\n-- \n1.5.3.4.439.ge8b49\n"},{"id":"57441","messageId":"11935935821192-git-send-email-prohaska@zib.de","threadId":"10503","inReplyTo":"11935935823496-git-send-email-prohaska@zib.de","subject":"[PATCH 10/10] push: teach push to be quiet if local ref is strict subset of remote ref","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2007-10-28T17:46:21Z","receivedAt":"2007-10-28T17:46:21Z","isPatch":true,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"git push reports errors if a remote ref is not a strict subset\nof a local ref. The push wouldn't be a fast-forward and is\ntherefore refused. This is in general a good idea.\n\nBut these messages can be annoying if you work with a shared\nremote repository. Branches at the remote may have advanced and\nyou haven't pulled to all of your local branches. In this\nsituation, local branches may be strict subsets of the remote\nheads. Pushing such branches wouldn't add any information to the\nremote. It would only reset the remote to an ancestor. A merge\nbetween the remote and the local branch is not very interested\neither because it would just be a fast forward of the local\nbranch. In these cases you're not interested in the error\nmessage.\n\nThis commit teaches git push to be quiet for local refs that are\nstrict subsets of the matching remote refs and no refspec is\nspecified on the command line. If the --verbose flag is used a\n\"note\" is printed instead of silently ignoring the refs.\nIf no notes have been printed the number of ignored refs will\nbe reported in the final summary.\n\nIf refs are ignored their matching remote tracking refs will not\nbe changed.\n\ngit push now allows you pushing a couple of branches that have\nadvanced, while ignoring all branches that have no local changes,\nbut are lagging behind their matching remote refs. This is done\nwithout reporting errors.\n\nThanks to Junio C. Hamano <gitster@pobox.com> for suggesting to\nreport in the summary that refs have been ignored.\n\nSigned-off-by: Steffen Prohaska <prohaska@zib.de>\n---\n send-pack.c           |   68 +++++++++++++++++++++++++++++++---------\n t/t5516-fetch-push.sh |   84 +++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 137 insertions(+), 15 deletions(-)\n\ndiff --git a/send-pack.c b/send-pack.c\nindex 77acae1..68a4692 100644\n--- a/send-pack.c\n+++ b/send-pack.c\n@@ -187,6 +187,7 @@ static int send_pack(int in, int out, struct remote *remote, int nr_refspec, cha\n \tint ask_for_status_report = 0;\n \tint allow_deleting_refs = 0;\n \tint expect_status_report = 0;\n+\tint ignored_refs = 0;\n \n \t/* No funny business with the matcher */\n \tremote_tail = get_remote_heads(in, &remote_refs, 0, NULL, REF_NORMAL);\n@@ -259,24 +260,56 @@ static int send_pack(int in, int out, struct remote *remote, int nr_refspec, cha\n \t\t    !will_delete_ref &&\n \t\t    !is_null_sha1(ref->old_sha1) &&\n \t\t    !ref->force) {\n-\t\t\tif (!has_sha1_file(ref->old_sha1) ||\n-\t\t\t    !ref_newer(ref->peer_ref->new_sha1,\n-\t\t\t\t       ref->old_sha1)) {\n-\t\t\t\t/* We do not have the remote ref, or\n-\t\t\t\t * we know that the remote ref is not\n-\t\t\t\t * an ancestor of what we are trying to\n-\t\t\t\t * push.  Either way this can be losing\n-\t\t\t\t * commits at the remote end and likely\n-\t\t\t\t * we were not up to date to begin with.\n+\t\t\tif (!has_sha1_file(ref->old_sha1)) {\n+\t\t\t\t/* We do not have the remote ref.\n+\t\t\t\t * This can be losing commits at\n+\t\t\t\t * the remote end.\n \t\t\t\t */\n-\t\t\t\terror(\"remote '%s' is not a strict \"\n-\t\t\t\t      \"subset of local ref '%s'. \"\n-\t\t\t\t      \"maybe you are not up-to-date and \"\n-\t\t\t\t      \"need to pull first?\",\n-\t\t\t\t      ref->name,\n-\t\t\t\t      ref->peer_ref->name);\n+\t\t\t\terror(\"You don't have the commit\"\n+\t\t\t\t      \"for the remote ref '%s'.\"\n+\t\t\t\t      \"This may cause losing commits\"\n+\t\t\t\t      \"that cannot be recovered.\",\n+\t\t\t\t      ref->name);\n \t\t\t\tret = -2;\n \t\t\t\tcontinue;\n+\t\t\t} else if (!ref_newer(ref->peer_ref->new_sha1,\n+\t\t\t                      ref->old_sha1)) {\n+\t\t\t\t/* We know that the remote ref is not\n+\t\t\t\t * an ancestor of what we are trying to\n+\t\t\t\t * push. This can be losing commits at\n+\t\t\t\t * the remote end and likely we were not\n+\t\t\t\t * up to date to begin with.\n+\t\t\t\t *\n+\t\t\t\t * Therefore, we don't push.\n+\t\t\t\t *\n+\t\t\t\t * If no explicit refspec was passed on the\n+\t\t\t\t * commandline, then we only report an error\n+\t\t\t\t * if the local is not a strict subset of the\n+\t\t\t\t * remote.  If the local is a strict subset we\n+\t\t\t\t * don't have new commits for the remote.\n+\t\t\t\t * Pulling and pushing wouldn't add anything to\n+\t\t\t\t * the remote.\n+\t\t\t\t *\n+\t\t\t\t */\n+\t\t\t\tif (nr_refspec ||\n+\t\t\t\t    !ref_newer(ref->old_sha1, ref->peer_ref->new_sha1)) {\n+\t\t\t\t\terror(\"remote '%s' is not a strict \"\n+\t\t\t\t\t      \"subset of local ref '%s'. \"\n+\t\t\t\t\t      \"maybe you are not up-to-date and \"\n+\t\t\t\t\t      \"need to pull first?\",\n+\t\t\t\t\t      ref->name,\n+\t\t\t\t\t      ref->peer_ref->name);\n+\t\t\t\t\tret = -2;\n+\t\t\t\t} else if (verbose) {\n+\t\t\t\t\tfprintf(stderr,\n+\t\t\t\t\t        \"note: ignoring local ref '%s' \"\n+\t\t\t\t\t        \"because it is a strict \"\n+\t\t\t\t\t        \"subset of remote '%s'.\\n\",\n+\t\t\t\t\t        ref->peer_ref->name,\n+\t\t\t\t\t        ref->name);\n+\t\t\t\t} else\n+\t\t\t\t\tignored_refs++;\n+\t\t\t\tcontinue;\n \t\t\t}\n \t\t}\n \t\thashcpy(ref->new_sha1, ref->peer_ref->new_sha1);\n@@ -335,6 +368,11 @@ static int send_pack(int in, int out, struct remote *remote, int nr_refspec, cha\n \t\t\tret = -4;\n \t}\n \n+\tif (ignored_refs)\n+\t\tfprintf(stderr,\n+\t\t\t\"Ignored %d local refs that are strict subsets of matching remote ref. \"\n+\t\t\t\"Use --verbose for more details.\\n\",\n+\t\t\tignored_refs);\n \tif (!new_refs && ret == 0)\n \t\tfprintf(stderr, \"Everything up-to-date\\n\");\n \treturn ret;\ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex 6708ec1..1f740b2 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -56,6 +56,22 @@ check_push_result () {\n \t)\n }\n \n+check_local_result () {\n+\t(\n+\t\tit=\"$1\" &&\n+\t\tshift\n+\t\tfor ref in \"$@\"\n+\t\tdo\n+\t\t\tr=$(git show-ref -s --verify refs/$ref) &&\n+\t\t\ttest \"z$r\" = \"z$it\" || {\n+\t\t\t\techo \"Oops, refs/$ref is wrong\"\n+\t\t\t\texit 1\n+\t\t\t}\n+\t\tdone &&\n+\t\tgit fsck --full\n+\t)\n+}\n+\n test_expect_success setup '\n \n \t: >path1 &&\n@@ -345,4 +361,72 @@ test_expect_success 'push with dry-run' '\n \tcheck_push_result $old_commit heads/master\n '\n \n+test_expect_success 'push with local is strict subset (must not report error)' '\n+\n+\tmk_test heads/foo &&\n+\tgit push testrepo $the_commit:refs/heads/foo &&\n+\tgit branch -f foo $old_commit &&\n+\tif git push testrepo 2>&1 | grep ^error\n+\tthen\n+\t\techo \"Oops, should not report error\"\n+\t\tfalse\n+\telse\n+\t\tcheck_push_result $the_commit heads/foo\n+\tfi\n+\n+'\n+\n+test_expect_success 'push with local is strict subset (must not update remotes)' '\n+\n+\tmk_test heads/foo &&\n+\tgit push testrepo $the_commit:refs/heads/foo &&\n+\tgit branch -f foo $old_commit &&\n+\tgit fetch test &&\n+\tcheck_local_result $the_commit remotes/test/foo &&\n+\tif git push test 2>&1 | grep ^error\n+\tthen\n+\t\techo \"Oops, should not report error\"\n+\t\tfalse\n+\telse\n+\t\tcheck_push_result $the_commit heads/foo &&\n+\t\tcheck_local_result $the_commit remotes/test/foo\n+\tfi\n+\n+'\n+\n+test_expect_success 'push with explicit refname, local is strict subset (must report error)' '\n+\n+\tmk_test heads/foo &&\n+\tgit push testrepo $the_commit:refs/heads/foo &&\n+\tgit branch -f foo $old_commit &&\n+\tif ! git push testrepo foo 2>&1 | grep ^error\n+\tthen\n+\t\techo \"Oops, should have reported error\"\n+\t\tfalse\n+\telse\n+\t\tcheck_push_result $the_commit heads/foo\n+\tfi\n+\n+'\n+\n+test_expect_success 'push with neither local nor remote is strict subset (must report error)' '\n+\n+\tmk_test heads/foo &&\n+\tgit push testrepo $the_commit:refs/heads/foo &&\n+\tgit branch -f foo $old_commit &&\n+\tgit checkout foo &&\n+\t: >path3 &&\n+\tgit add path3 &&\n+\ttest_tick &&\n+\tgit commit -a -m branched &&\n+\tif ! git push testrepo 2>&1 | grep ^error\n+\tthen\n+\t\techo \"Oops, should have reported error\"\n+\t\tfalse\n+\telse\n+\t\tcheck_push_result $the_commit heads/foo\n+\tfi\n+\n+'\n+\n test_done\n-- \n1.5.3.4.439.ge8b49\n"},{"id":"57539","messageId":"7vejfdngzt.fsf@gitster.siamese.dyndns.org","threadId":"10503","inReplyTo":"1193593581486-git-send-email-prohaska@zib.de","subject":"Re: [PATCH 03/10] push: support pushing HEAD to real branch name","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-10-30T08:28:38Z","receivedAt":"2007-10-30T08:28:38Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nice.\n"},{"id":"57542","messageId":"7v8x5lngzo.fsf@gitster.siamese.dyndns.org","threadId":"10503","inReplyTo":"11935935812185-git-send-email-prohaska@zib.de","subject":"Re: [PATCH 04/10] push: add \"git push HEAD\" shorthand for 'push current branch to default repo'","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-10-30T08:28:43Z","receivedAt":"2007-10-30T08:28:43Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Will drop this as you already know why.\n"},{"id":"57541","messageId":"7v3avtngzc.fsf@gitster.siamese.dyndns.org","threadId":"10503","inReplyTo":"11935935823045-git-send-email-prohaska@zib.de","subject":"Re: [PATCH 07/10] push: use same rules as git-rev-parse to resolve refspecs","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-10-30T08:28:55Z","receivedAt":"2007-10-30T08:28:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Steffen Prohaska <prohaska@zib.de> writes:\n\n> This commit changes the rules for resolving refspecs to match the\n> rules for resolving refs in rev-parse. git-rev-parse uses clear rules\n> to resolve a short ref to its full name, which are well documented.\n> The rules for resolving refspecs documented in git-send-pack were\n> less strict and harder to understand. This commit replaces them by\n> the rules of git-rev-parse.\n>\n> The unified rules are easier to understand and better resolve ambiguous\n> cases. You can now push from a repository containing several branches\n> ending on the same short name.\n\nAs you introduced long names around 5/10 to have two different\nones for clarity with the goal of unifying them, so once you\nunified the rules, it probably is a good idea to rename the long\n\"do_this_with_X_rule()\" and \"do_this_with_Y_rule()\" functions\nback to \"do_this()\", isn't it?\n"},{"id":"57543","messageId":"7vwst5m2eq.fsf@gitster.siamese.dyndns.org","threadId":"10503","inReplyTo":"11935935812741-git-send-email-prohaska@zib.de","subject":"Re: [PATCH 01/10] push: change push to fail if short refname does not exist","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-10-30T08:29:01Z","receivedAt":"2007-10-30T08:29:01Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Steffen Prohaska <prohaska@zib.de> writes:\n\n> Pushing a short refname used to create a new ref on on the\n> remote side if it did not yet exist. If you specified the wrong\n> branch accidentally it was created. A safety valve that pushes\n> only existing branches may help to avoid errors.\n\nOn the other hand, if you specified a wrong branch that exists\non the remote end accidentally, it still was pushed.  Do we want\nto have a new \"--i-really-want-to-push\" option to make it safer?\n\nI do not think so.  Why should a new branch be treated any\ndifferently?\n\nWill drop 1/10 and 2/10 for now.\n"},{"id":"57545","messageId":"7vfxztm2dx.fsf@gitster.siamese.dyndns.org","threadId":"10503","inReplyTo":"11935935821192-git-send-email-prohaska@zib.de","subject":"Re: [PATCH 10/10] push: teach push to be quiet if local ref is strict subset of remote ref","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-10-30T08:29:30Z","receivedAt":"2007-10-30T08:29:30Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Steffen Prohaska <prohaska@zib.de> writes:\n\n> git push now allows you pushing a couple of branches that have\n> advanced, while ignoring all branches that have no local changes,\n> but are lagging behind their matching remote refs. This is done\n> without reporting errors.\n>\n> Thanks to Junio C. Hamano <gitster@pobox.com> for suggesting to\n> report in the summary that refs have been ignored.\n\nI do not think this is a good idea at all.  Furthermore, I never\nsuggested anything about summary.  You are robbing the\ninformation from the pusher which ones are pushed and which ones\nare left behind.\n\nIt simply is insane to make this strange rule 10/10 introduces\nthe default behaviour.  It is too specific to a particular\nworkflow (that is, working with a shared central repository,\nhaving many locally tracking branches that are not often used\nand become stale, and working on only things to completion\nbetween pushes).\n\nI think we could live with an optional behaviour, in addition to\nthe current \"matching refs\" behaviour, that is \"matching refs,\nignoring strict ancestors\", though, but I doubt it is worth the\naddition.\n"},{"id":"57547","messageId":"13414001-D708-41E2-A35B-FDBB1103F1AC@zib.de","threadId":"10503","inReplyTo":"7v3avtngzc.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 07/10] push: use same rules as git-rev-parse to resolve refspecs","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2007-10-30T08:49:23Z","receivedAt":"2007-10-30T08:49:23Z","isPatch":true,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"\nOn Oct 30, 2007, at 9:28 AM, Junio C Hamano wrote:\n\n> Steffen Prohaska <prohaska@zib.de> writes:\n>\n>> This commit changes the rules for resolving refspecs to match the\n>> rules for resolving refs in rev-parse. git-rev-parse uses clear rules\n>> to resolve a short ref to its full name, which are well documented.\n>> The rules for resolving refspecs documented in git-send-pack were\n>> less strict and harder to understand. This commit replaces them by\n>> the rules of git-rev-parse.\n>>\n>> The unified rules are easier to understand and better resolve  \n>> ambiguous\n>> cases. You can now push from a repository containing several branches\n>> ending on the same short name.\n>\n> As you introduced long names around 5/10 to have two different\n> ones for clarity with the goal of unifying them, so once you\n> unified the rules, it probably is a good idea to rename the long\n> \"do_this_with_X_rule()\" and \"do_this_with_Y_rule()\" functions\n> back to \"do_this()\", isn't it?\n\nAbsolutely.\n\nBut I'm not sure if I'm the one who unifies them.\n\n\tSteffen\n"},{"id":"57549","messageId":"AD10F15D-0F77-42BB-86CA-6404063C784B@zib.de","threadId":"10503","inReplyTo":"7vwst5m2eq.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 01/10] push: change push to fail if short refname does not exist","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2007-10-30T08:56:43Z","receivedAt":"2007-10-30T08:56:43Z","isPatch":true,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"\nOn Oct 30, 2007, at 9:29 AM, Junio C Hamano wrote:\n\n> Steffen Prohaska <prohaska@zib.de> writes:\n>\n>> Pushing a short refname used to create a new ref on on the\n>> remote side if it did not yet exist. If you specified the wrong\n>> branch accidentally it was created. A safety valve that pushes\n>> only existing branches may help to avoid errors.\n>\n> On the other hand, if you specified a wrong branch that exists\n> on the remote end accidentally, it still was pushed.  Do we want\n> to have a new \"--i-really-want-to-push\" option to make it safer?\n\nMaybe not a bad idea ;)\n\nBut not as a command line flag but after printing the results\nof a '--dry-run' and than asking the user for confirmation:\n\"do you want to push this?\".\n\n\n> I do not think so.  Why should a new branch be treated any\n> differently?\n\nBecause \"updating an existing branch\" and \"creating a new branch\"\nare two slightly different tasks.\n\nIf git provides a way to make this difference explicit, it\nwould be safer to use.\n\n\n> Will drop 1/10 and 2/10 for now.\n\nThen they'll be dropped and I'll rely on the the --dry-run flag.\n\nOr someone else needs to step in and support my point.\n\n\tSteffen\n"},{"id":"57551","messageId":"7v7il5lzxe.fsf@gitster.siamese.dyndns.org","threadId":"10503","inReplyTo":"AD10F15D-0F77-42BB-86CA-6404063C784B@zib.de","subject":"Re: [PATCH 01/10] push: change push to fail if short refname does not exist","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-10-30T09:22:37Z","receivedAt":"2007-10-30T09:22:37Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Steffen Prohaska <prohaska@zib.de> writes:\n\n> On Oct 30, 2007, at 9:29 AM, Junio C Hamano wrote:\n> ...\n>> Will drop 1/10 and 2/10 for now.\n>\n> Then they'll be dropped and I'll rely on the the --dry-run flag.\n>\n> Or someone else needs to step in and support my point.\n\nYup, you exactly got what I meant by \"for now\".  I reserve the\nright to be convinced and converted later ;-).\n"},{"id":"57556","messageId":"52171BF7-50E2-473E-A0BD-CB64D38FD502@zib.de","threadId":"10503","inReplyTo":"7vfxztm2dx.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 10/10] push: teach push to be quiet if local ref is strict subset of remote ref","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2007-10-30T10:15:59Z","receivedAt":"2007-10-30T10:15:59Z","isPatch":true,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"\nOn Oct 30, 2007, at 9:29 AM, Junio C Hamano wrote:\n\n> Steffen Prohaska <prohaska@zib.de> writes:\n>\n>> git push now allows you pushing a couple of branches that have\n>> advanced, while ignoring all branches that have no local changes,\n>> but are lagging behind their matching remote refs. This is done\n>> without reporting errors.\n>>\n>> Thanks to Junio C. Hamano <gitster@pobox.com> for suggesting to\n>> report in the summary that refs have been ignored.\n>\n> I do not think this is a good idea at all.  Furthermore, I never\n> suggested anything about summary.\n\nYeah, sorry. You only asked if the summary does mention\nsomething; not suggesting it should do so.\n\n\n> You are robbing the\n> information from the pusher which ones are pushed and which ones\n> are left behind.\n\nAbsolutely; because the branches left behind are not\ninteresting. The remote already is ahead of the local\nbranches. The local branches are just left were they are. They\nhave no new information on them.  Forcing an push would _rewind_\nthe remote without adding anything to it.\n\nIf you really intended to do a rewind you should have passed\n'--force' in the first place and my report would never be\nprinted.\n\n\n> It simply is insane to make this strange rule 10/10 introduces\n> the default behaviour.  It is too specific to a particular\n> workflow (that is, working with a shared central repository,\n> having many locally tracking branches that are not often used\n> and become stale, and working on only things to completion\n> between pushes).\n\nI don't think its very strange behaviour if you see it in the\nlight of what the user wants to achieve. We are talking about\nthe case were only fast forward pushes are allowed. So, we\nonly talk about a push that has the goal of adding new local\nchanges to the remote. The user says \"git push\" and means\npush my new local changes to the remote.\n\nUnfortunately, the remote may have advanced differently from\nthe local branch, and the push must fail because someone needs\nto merge first. git push recommends to do a pull and retry, which\nis the right thing to do.\n\nMy strange rule 10/10 adds a check that verifies if the local\nside has something interesting to push. Only in this case a\npull make sense. If you do not have something new, a pull will\nbe a fast-forward, and just a waste of time.\n\nIn this light I think the current behaviour is insane, because\nit asks the user to spend time on things that do not add any\nvalue. No new commits, no new information, no need to merge, no\nneed to push again, no need to report errors ...\n\n> I think we could live with an optional behaviour, in addition to\n> the current \"matching refs\" behaviour, that is \"matching refs,\n> ignoring strict ancestors\", though, but I doubt it is worth the\n> addition.\n\n... just ignore strict ancestors by default.\n\n\tSteffen\n"},{"id":"57558","messageId":"472706DB.1040106@op5.se","threadId":"10503","inReplyTo":"52171BF7-50E2-473E-A0BD-CB64D38FD502@zib.de","subject":"Re: [PATCH 10/10] push: teach push to be quiet if local ref is strict subset of remote ref","fromName":"Andreas Ericsson","fromEmail":"ae@op5.se","sentAt":"2007-10-30T10:26:35Z","receivedAt":"2007-10-30T10:26:35Z","isPatch":true,"sender":{"key":"ae@op5.se","avatar":"https://gravatar.com/avatar/426e89595c75a8f5252dd0c989e5fabe5bcac616e68557427ad9aef6b0ca342a?d=mp&s=160"},"body":"Steffen Prohaska wrote:\n> \n> My strange rule 10/10 adds a check that verifies if the local\n> side has something interesting to push. Only in this case a\n> pull make sense. If you do not have something new, a pull will\n> be a fast-forward, and just a waste of time.\n> \n\nErr... fast-forward pulls are not a waste of time. What a strange\nnotion. Perhaps I misunderstood, but this sentence jumped out at\nme and immediately got filed under \"decidedly odd\".\n\n-- \nAndreas Ericsson                   andreas.ericsson@op5.se\nOP5 AB                             www.op5.se\nTel: +46 8-230225                  Fax: +46 8-230231\n"},{"id":"57562","messageId":"49830F09-FFBF-4195-9D12-ED7B7F56A142@zib.de","threadId":"10503","inReplyTo":"472706DB.1040106@op5.se","subject":"Re: [PATCH 10/10] push: teach push to be quiet if local ref is strict subset of remote ref","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2007-10-30T10:53:45Z","receivedAt":"2007-10-30T10:53:45Z","isPatch":true,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"\nOn Oct 30, 2007, at 11:26 AM, Andreas Ericsson wrote:\n\n> Steffen Prohaska wrote:\n>> My strange rule 10/10 adds a check that verifies if the local\n>> side has something interesting to push. Only in this case a\n>> pull make sense. If you do not have something new, a pull will\n>> be a fast-forward, and just a waste of time.\n>\n> Err... fast-forward pulls are not a waste of time. What a strange\n> notion. Perhaps I misunderstood, but this sentence jumped out at\n> me and immediately got filed under \"decidedly odd\".\n\nIf the local branch is a strict ancestor, a pull is only\ninteresting if you want to start to work on such a branch\nlocally. But pull is a waste of time if you're only goal is to\npush. Push suggests to pull first. So you pull; and then you\npush again; and the result on the remote is the same. Only\nthe error message is gone that could have been avoided in the\nfirst place. -> waste of time.\n\nIf you _pull_ it would be interesting to learn that you probably\nwant to merge to more than the current local branch. At that\ntime you expressed the intention to integrate new changes from\nthe remote. And it's probably a good idea to integrate changes\non all local branches that are set up to automatically merge\nfrom the same remote you just pulled.\n\nBut if you push you want to push. You'd probably only interested\nin pulls that add immediate value to the push. That is if the\nresult of a subsequent push modified the remote.\n\n\tSteffen\n"},{"id":"57583","messageId":"Pine.LNX.4.64.0710301306210.7357@iabervon.org","threadId":"10503","inReplyTo":"7vfxztm2dx.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 10/10] push: teach push to be quiet if local ref is strict subset of remote ref","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2007-10-30T18:00:22Z","receivedAt":"2007-10-30T18:00:22Z","isPatch":true,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"On Tue, 30 Oct 2007, Junio C Hamano wrote:\n\n> Steffen Prohaska <prohaska@zib.de> writes:\n> \n> > git push now allows you pushing a couple of branches that have\n> > advanced, while ignoring all branches that have no local changes,\n> > but are lagging behind their matching remote refs. This is done\n> > without reporting errors.\n> >\n> > Thanks to Junio C. Hamano <gitster@pobox.com> for suggesting to\n> > report in the summary that refs have been ignored.\n> \n> I do not think this is a good idea at all.  Furthermore, I never\n> suggested anything about summary.  You are robbing the\n> information from the pusher which ones are pushed and which ones\n> are left behind.\n\nI think this case should be a warning rather than an error, though. It is \ncertainly true that the user isn't intending to update those remote refs, \nbecause there is no local change to update them with. And it is also true \nthat those local refs being stale is no impediment to updating the refs \nwhich are not stale, which is what the user does intend to do. I can't see \na workflow which would be hurt by this change, because we know that, if \nthe user follows the instructions and then tries the push again, it will \nhave no effect.\n\nIf the concern is robbing the user of information, we should simply \nprovide the information, rather than interrupting the user's work to make \nthem act on the information before completing the essentially independant \noperation they're attempting.\n\nIn any case, it's misleading to suggest that the user \"pull first\", \nbecause we know that there would be no effect to pushing again after \nmerging. In this case, it would be more accurate to suggest that the user \n\"pull instead\". Perhaps the message should be\n\"%s: nothing to push to %s, but you are not up-to-date and may want to \npull\"\n\n\t-Daniel\n*This .sig left intentionally blank*\n"},{"id":"57601","messageId":"7vejfcl8aj.fsf@gitster.siamese.dyndns.org","threadId":"10503","inReplyTo":"52171BF7-50E2-473E-A0BD-CB64D38FD502@zib.de","subject":"Re: [PATCH 10/10] push: teach push to be quiet if local ref is strict subset of remote ref","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-10-30T19:19:32Z","receivedAt":"2007-10-30T19:19:32Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Steffen Prohaska <prohaska@zib.de> writes:\n\n> On Oct 30, 2007, at 9:29 AM, Junio C Hamano wrote:\n>\n>> It simply is insane to make this strange rule 10/10 introduces\n>> the default behaviour.  It is too specific to a particular\n>> workflow (that is, working with a shared central repository,\n>> having many locally tracking branches that are not often used\n>> and become stale, and working on only things to completion\n>> between pushes).\n>\n> I don't think its very strange behaviour if you see it in the\n> light of what the user wants to achieve. We are talking about\n> the case were only fast forward pushes are allowed. So, we\n> only talk about a push that has the goal of adding new local\n> changes to the remote. The user says \"git push\" and means\n> push my new local changes to the remote.\n\nIf you want to push a specific subset of branches, you should\nnot be invoking the \"matching refs\" to begin with.  And breaking\nthe \"matching refs\" behaviour is not the way to fix it.\n\nYou can rewind a wrong branch by mistake locally and run push.\nWith your change you would not notice that mistake.\n\n        $ git checkout bar\n        $ work work work; commit commit commit\n\t$ git checkout test\n        $ git merge bar\n\t... integrate, build, test\n        ... notice that the tip commit of bar is not ready\n        $ git checkout foo ;# oops, mistake\n        $ git reset --hard HEAD^\n\t$ git push\n\nIf you checked out foo instead of bar by mistake at the last\n\"git checkout\" step like this, your change will make 'foo' an\nancestor of the other side of the connection, and push silently\nignores it instead of failing.\n\nAlso, the behaviour is too specific to your workflow of working\non things only to completion between pushes.  If you work a bit\non branch 'foo' (but not complete), and work much on branch\n'bar', 'baz', and 'boo' making all of them ready to be\npublished, you cannot say \"git push\" anyway.  Instead you have\nto say \"git push $remote bar baz boo\".\n\nThis discourages people from making commits that are not ready\nto be published, which is a very wrong thing to do, as a major\nselling point of distributed revision control is the\ndissociation between committing and publishing.\n\nYou work and commit freely, and at any point some of your\nbranches are ready to be published while some others\naren't. Inconvenience of \"matching refs\" may need to be worked\naround.  I liked your \"current branch only\", with \"git push\n$remote HEAD\" (I presume that \"remote.$remote.push = HEAD\" and\n\"branch.$current.remote = $remote\" would let you do that with\n\"git push\"), exactly because the way it specifies which branch\nis to be published is very clearly defined and easy to\nunderstand.  This \"matching but only ff\" does not have that\nattractive clarity.\n"},{"id":"57663","messageId":"F5F68690-68A3-4AFC-A79C-FF02910F0359@zib.de","threadId":"10503","inReplyTo":"7vejfcl8aj.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 10/10] push: teach push to be quiet if local ref is strict subset of remote ref","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2007-10-31T07:53:06Z","receivedAt":"2007-10-31T07:53:06Z","isPatch":true,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"\nOn Oct 30, 2007, at 8:19 PM, Junio C Hamano wrote:\n\n> Steffen Prohaska <prohaska@zib.de> writes:\n>\n>> On Oct 30, 2007, at 9:29 AM, Junio C Hamano wrote:\n>>\n>>> It simply is insane to make this strange rule 10/10 introduces\n>>> the default behaviour.  It is too specific to a particular\n>>> workflow (that is, working with a shared central repository,\n>>> having many locally tracking branches that are not often used\n>>> and become stale, and working on only things to completion\n>>> between pushes).\n>>\n>> I don't think its very strange behaviour if you see it in the\n>> light of what the user wants to achieve. We are talking about\n>> the case were only fast forward pushes are allowed. So, we\n>> only talk about a push that has the goal of adding new local\n>> changes to the remote. The user says \"git push\" and means\n>> push my new local changes to the remote.\n>\n> If you want to push a specific subset of branches, you should\n> not be invoking the \"matching refs\" to begin with.  And breaking\n> the \"matching refs\" behaviour is not the way to fix it.\n\nok.\n\nSo, git push shall guarantee that all matching refs point\nto the _same_ commit if a push was successful. Otherwise,\ngit push shall report an error.\n\nWould it be acceptable if the error was less severe in the\ncase of local being a strict subset of remote?\nDaniel proposed\n\"%s: nothing to push to %s, but you are not up-to-date and\nmay want to pull\"\nIt would still be an error, but a less severe one.\n\nIt could also be a good idea to teach git push transactional\nbehaviour. It could check in advance ('--dry-run') if the\npush will succeed. If not it should report the errors without\nactually pushing. Then, _nothing_ would have been changed on\nthe remote. Only if everything is ok \"git push\" would modify\nthe remote. Well, I think it might be hard to avoid the race\ncondition when someone else pushes simultaneously to a shared\nrepo. But this hopefully rarely happens.\n\n\n> You can rewind a wrong branch by mistake locally and run push.\n> With your change you would not notice that mistake.\n>\n>         $ git checkout bar\n>         $ work work work; commit commit commit\n> \t$ git checkout test\n>         $ git merge bar\n> \t... integrate, build, test\n>         ... notice that the tip commit of bar is not ready\n>         $ git checkout foo ;# oops, mistake\n>         $ git reset --hard HEAD^\n> \t$ git push\n>\n> If you checked out foo instead of bar by mistake at the last\n> \"git checkout\" step like this, your change will make 'foo' an\n> ancestor of the other side of the connection, and push silently\n> ignores it instead of failing.\n\nYes, there are many ways you can mess up ;)\n\n\n> Also, the behaviour is too specific to your workflow of working\n> on things only to completion between pushes.  If you work a bit\n> on branch 'foo' (but not complete), and work much on branch\n> 'bar', 'baz', and 'boo' making all of them ready to be\n> published, you cannot say \"git push\" anyway.  Instead you have\n> to say \"git push $remote bar baz boo\".\n\nOk and this is the root why I work only to completion between\npushes. I tried to figure out a \"safe\" workflow. If you\naccidentally type \"git push\" nothing wrong should happen. I\nam sure that people will sometimes type \"git push\" forgetting\nto mention anything. At least, I am sure that _I_ will do this.\n\nThe only comfortable way to make \"git push\" safe with\nthe current behaviour is to work on local branches only to\ncompletion. Then, you can push to any repository at any time\nand nothing bad can happen.\n\nAlternatives with existing git are\n\n- never use \"git push\", but always tell git explicitly what you\n   want. This is too dangerous for me because at some point I'll\n   type \"git push\". The problem with \"git push\" is that it's\n   really hard to undo. It's near to impossible if you pushed\n   to a public remote. Therefore, I really want to avoid this danger.\n\n- Configure specific push rules for remotes that switch off\n   the \"matching branches\" default. You can for example 'switch'\n   off the default by configuring\n   \"remote.$remote.push = nonexisting\". But then I started\n   to get annoyed by all the configuration work. I do not want\n   to explain such details to people who get started with git.\n   And you do not get reasonable messages either. And btw I'd\n   prefer if git push just did the right thing.\n\n\nAlternatives that require changing git push are\n\n- git push would do _nothing_ by default. git push would ask\n   \"what do you mean? Need at least a remote, or better remote\n    and branch.\"\n   Options could be provided to push current branch (--current)\n   or all matching branches (--matching).\n\n- git push _by default_ would only push the current branch. This\n   would at least be a \"safer\" default.\n\n- git push would first run --dry-run and then ask for\n   confirmation. Something like:\n   \"Do you really want to push this to that remote? Here is\n   the URL and the branches. Did you really mean this?\n   WARNING: you can't undo this operation. And btw if you say\n   yes, I'll report errors anyway because some remotes are not\n   strict subsets. So maybe you want to fix things first.\"\n\n- git push can be configuration to push only the current\n   branch, as outlined below. This would certainly work. What\n   I do not like is that you first need to do some configuration\n   before you get a safe working environment.\n\n\n> This discourages people from making commits that are not ready\n> to be published, which is a very wrong thing to do, as a major\n> selling point of distributed revision control is the\n> dissociation between committing and publishing.\n\nYes, the current default behaviour of git push discourages me\nto work that way.\n\n\n> You work and commit freely, and at any point some of your\n> branches are ready to be published while some others\n> aren't. Inconvenience of \"matching refs\" may need to be worked\n> around.  I liked your \"current branch only\", with \"git push\n> $remote HEAD\" (I presume that \"remote.$remote.push = HEAD\" and\n> \"branch.$current.remote = $remote\" would let you do that with\n> \"git push\"), exactly because the way it specifies which branch\n> is to be published is very clearly defined and easy to\n> understand.  This \"matching but only ff\" does not have that\n> attractive clarity.\n\nIn my view, that would be safer than what we have now.\n\n\tSteffen\n"},{"id":"57671","messageId":"7v8x5jiseh.fsf@gitster.siamese.dyndns.org","threadId":"10503","inReplyTo":"F5F68690-68A3-4AFC-A79C-FF02910F0359@zib.de","subject":"Re: [PATCH 10/10] push: teach push to be quiet if local ref is strict subset of remote ref","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-10-31T08:45:42Z","receivedAt":"2007-10-31T08:45:42Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Steffen Prohaska <prohaska@zib.de> writes:\n\n> Would it be acceptable if the error was less severe in the\n> case of local being a strict subset of remote?\n> Daniel proposed\n> \"%s: nothing to push to %s, but you are not up-to-date and\n> may want to pull\"\n> It would still be an error, but a less severe one.\n\nI am not convinced there is one true total order of \"error\nseverity\" that applies uniformly across different workflows, so\nI would not immediately agree if you are suggesting to introduce\n\"severity levels\".  But it certainly makes a lot of sense to be\nable to _differentiate_ kinds of errors, and to have the calling\nscripts and the push command itself react to them.\n\nWhat are the possible error conditions?\n\n 1. Error on the sending side.  The ref parameters given to\n    git-push were bogus, or they were good commits but they were\n    not fully connected to the commits the other side has\n    (i.e. local repository corruption).  pack-objects will abort\n    and no remote (nor local tracking ref that tracks what we\n    pushed to the remote) would be updated.  This should be\n    \"most severe\" in _any_ workflow, so I do not mind calling\n    this \"fatal\".\n\n 2. Push to a ref does fast forward, but the update hook on the\n    remote side declines.  The ref on the remote nor the\n    corresponding local tracking ref would not be updated, and\n    the command would fail.\n\nFor all the other classes of errors, the ref on the remote nor\nthe corresponding local tracking ref would not be updated, and\nby default, an error on any ref causes the command to error out.\nFor each of these classes of errors, we _could_ have an option\nto let you tell the command not to error out because of it.\n\n 3. Push to a ref does not fast forward and --force is not\n    given, but you can prove the remote is strict subset of\n    local (what your 10/10 wants to do).\n\n 4. Same as #3 but you cannot prove the remote is strict subset\n    of local.\n\nAny other classes?\n\nIt might be a good idea to generalize 3 & 4, by the way.  The\nremote being a strict descendant of what is being pushed might\nbe something you happened to want today, but somebody else may\ncome up with a different rule tomorrow.  So, \n\n 3'. Push to a ref does not fast forward and --force is not\n     given, but there is a configuration (would this be per\n     remote?, per remote branch?, or per local branch?) that\n     tells git-push to call a hook on the local side that takes\n     <ref being pushed, ref on the remote> as its parameter.\n     The result from the hook does not change the fact that this\n     is still an error, but it can instruct git-push not to\n     error out due to this condition.\n\nIn some other workflows, it might make sense to maybe even\nmaking 2. not to cause the error from git-push.  I dunno.\n\n> It could also be a good idea to teach git push transactional\n> behaviour.\n\nThat is certainly true.  I am not sure about other transports,\nbut it should be a relatively straightforward protocol extension\nfor the git native transport.\n\n> - git push can be configuration to push only the current\n>   branch, as outlined below. This would certainly work. What\n>   I do not like is that you first need to do some configuration\n>   before you get a safe working environment.\n\nI would not doubt it would be safer for _your_ workflow, but you\nshould consider the risk of making things more cumbersome for\nworkflows of others by enforcing that policy.\n\nIn other words, don't change anything unless you have a very\ngood reason to convince everybody else that it is universally\na good change to the default.\n"},{"id":"57673","messageId":"7vzlxzhchr.fsf@gitster.siamese.dyndns.org","threadId":"10503","inReplyTo":"7v8x5jiseh.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 10/10] push: teach push to be quiet if local ref is strict subset of remote ref","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-10-31T09:14:40Z","receivedAt":"2007-10-31T09:14:40Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n>  1. Error on the sending side.  The ref parameters given to\n>     git-push were bogus, or they were good commits but they were\n>     not fully connected to the commits the other side has\n>     (i.e. local repository corruption).  pack-objects will abort\n>     and no remote (nor local tracking ref that tracks what we\n>     pushed to the remote) would be updated.  This should be\n>     \"most severe\" in _any_ workflow, so I do not mind calling\n>     this \"fatal\".\n\nBy the way, as git-push allows an arbitrary SHA-1 on the left\nhand side of a refspec, you can have the above error without a\ncorrupted repository.  Here is how.\n\n * You run git-fetch from elsewhere.  It is a small fetch and we\n   decide not to keep the pack (iow, run unpack-objects instead\n   of index-pack on the local side).  Or the fetch is over dumb\n   transport that walks commits one-by-one.\n\n   This git-fetch is interrupted.  We do _not_ update any refs\n   in such a case, but we do not eradicate loose objects that\n   were downloaded.  They stay dangling.\n\n * You push one of the commits downloaded above.  I.e. it is\n   not connected to any of your ref.\n"},{"id":"57680","messageId":"B3C76DB8-076D-4C43-AC28-99119A05325C@zib.de","threadId":"10503","inReplyTo":"7v8x5jiseh.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 10/10] push: teach push to be quiet if local ref is strict subset of remote ref","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2007-10-31T10:50:01Z","receivedAt":"2007-10-31T10:50:01Z","isPatch":true,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"\nOn Oct 31, 2007, at 9:45 AM, Junio C Hamano wrote:\n\n>> - git push can be configuration to push only the current\n>>   branch, as outlined below. This would certainly work. What\n>>   I do not like is that you first need to do some configuration\n>>   before you get a safe working environment.\n>\n> I would not doubt it would be safer for _your_ workflow, but you\n> should consider the risk of making things more cumbersome for\n> workflows of others by enforcing that policy.\n\nTogether with the '--create' flag it would be safer in all\ncases, because it would always do _less_ than what git push\ncurrently does. The safest choice would be if \"git push\"\nrefused to do anything until configured appropriately.\n\n\"safer\" is independent of the workflow.\n\nBut I see that it may be more cumbersome depending on the\nworkflow.\n\nI'm mainly interested in using git against a shared repo,\nand make it as simple and as safe as possible to use in\nsuch a setup. I suspect that git is more optimized for the\nworkflow used for the Linux kernel and for developing git,\nwhich heavily rely on sending patches to mailing lists and\npulling fro read-only repos.\n\n\n> In other words, don't change anything unless you have a very\n> good reason to convince everybody else that it is universally\n> a good change to the default.\n\nWhat I can imagine would not be universally better, but it\nwould be universally safer. You'd need to either explicitly\ntell git push how to act (e.g. '--current' or '--matching'\nflags), or you could explicitly configure git to always act in\na specific way. But it would only start to act this way _after_\nbeing configured appropriately.\n\n\tSteffen\n"},{"id":"57717","messageId":"7vve8nglrt.fsf@gitster.siamese.dyndns.org","threadId":"10503","inReplyTo":"B3C76DB8-076D-4C43-AC28-99119A05325C@zib.de","subject":"Re: [PATCH 10/10] push: teach push to be quiet if local ref is strict subset of remote ref","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-10-31T18:51:50Z","receivedAt":"2007-10-31T18:51:50Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Steffen Prohaska <prohaska@zib.de> writes:\n\n> On Oct 31, 2007, at 9:45 AM, Junio C Hamano wrote:\n>\n>> I would not doubt it would be safer for _your_ workflow, but you\n>> should consider the risk of making things more cumbersome for\n>> workflows of others by enforcing that policy.\n>\n> Together with the '--create' flag it would be safer in all\n> cases, because it would always do _less_ than what git push\n> currently does. The safest choice would be if \"git push\"\n> refused to do anything until configured appropriately.\n>\n> \"safer\" is independent of the workflow.\n\nBy your definition, a command that does not do anything by\ndefault is safer regardless of the workflow.\n\nThat may be theoretically true --- it cannot do any harm by\ndefault.  But that is not useful.\n\n> I'm mainly interested in using git against a shared repo,\n> and make it as simple and as safe as possible to use in\n> such a setup. I suspect that git is more optimized for the\n> workflow used for the Linux kernel and for developing git,\n> which heavily rely on sending patches to mailing lists and\n> pulling fro read-only repos.\n\nYou forgot a lot more important part.  Pushing into publishing\nrepositories.  And the discussion is about git-push command.\n"},{"id":"57734","messageId":"B16F7DA1-E3E5-47A4-AFD3-6680741F38F1@zib.de","threadId":"10503","inReplyTo":"7vve8nglrt.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 10/10] push: teach push to be quiet if local ref is strict subset of remote ref","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2007-10-31T21:09:21Z","receivedAt":"2007-10-31T21:09:21Z","isPatch":true,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"\nOn Oct 31, 2007, at 7:51 PM, Junio C Hamano wrote:\n\n> Steffen Prohaska <prohaska@zib.de> writes:\n>\n>> On Oct 31, 2007, at 9:45 AM, Junio C Hamano wrote:\n>>\n>>> I would not doubt it would be safer for _your_ workflow, but you\n>>> should consider the risk of making things more cumbersome for\n>>> workflows of others by enforcing that policy.\n>>\n>> Together with the '--create' flag it would be safer in all\n>> cases, because it would always do _less_ than what git push\n>> currently does. The safest choice would be if \"git push\"\n>> refused to do anything until configured appropriately.\n>>\n>> \"safer\" is independent of the workflow.\n>\n> By your definition, a command that does not do anything by\n> default is safer regardless of the workflow.\n>\n> That may be theoretically true --- it cannot do any harm by\n> default.  But that is not useful.\n\nIf different workflows have contradicting needs, doing nothing\nby default might be a good choice. Not theoretically, but in\npractice.\n\n\n>> I'm mainly interested in using git against a shared repo,\n>> and make it as simple and as safe as possible to use in\n>> such a setup. I suspect that git is more optimized for the\n>> workflow used for the Linux kernel and for developing git,\n>> which heavily rely on sending patches to mailing lists and\n>> pulling from read-only repos.\n>>\n>\n> You forgot a lot more important part.  Pushing into publishing\n> repositories.  And the discussion is about git-push command.\n\nExactly, here are two examples:\n\nIf you push only to publishing repositories that are read\nonly by others, you'll never encounter the problem that\n10/10 tried to solve. The publishing repository is never\nchanged by others. You are the only one who pushes to this\nrepository. Therefore the remote never advances unexpectedly.\n\nA shared repository behaves differently. Others push to the\nrepository as well. Hence, branches can advance unexpectedly.\n\n\nAnother difference is the way changes are integrated. In\na workflow without shared repositories, only pull is used\nfor integration, while push in only used for publishing the\nchanges. After a push you always need to request someone else\nto pull. For example:\n\n- Alice publishes branch foo.\n- Bob clones Alice's repository and checks out foo as his\n   local branch bar.\n- Bob later publishes his branch by pushing bar to his\n   public repository and asks Alice to pull.\n- Alice pulls bar from Bobs public repository and merges\n   with foo. She then publishes the integrated changes\n   by pushing foo to her public repository.\n\nMy point is: there is no need to push from branch bar to\nbranch foo. Alice and Bob both push to branches that are named\nidentical in their private and their public repositories.\nOnly pull is used to merge changes from the branch named bar\nto the branch named foo.\n\nThis is different if you work with a shared repository. Bob\nchecks out the shared branch foo to his local branch bar and\nlater he needs to push bar back to the shared branch foo. Bob\nneeds to push changes from his local branch bar to the branch\nfoo in the remote repository, a branch with a different name.\nThis need does not emerge when working with two publishing\nrepositories, as described above.\n\n\nThis was the extended version of what I meant above. The\nworkflow used for the Linux kernel and for developing git is\nfocused on pull. Push is normally only used for publishing\nbranches under identical name. The interesting stuff happens\nduring the pull.\n\n\tSteffen\n"},{"id":"57745","messageId":"7vlk9jgeee.fsf@gitster.siamese.dyndns.org","threadId":"10503","inReplyTo":"B16F7DA1-E3E5-47A4-AFD3-6680741F38F1@zib.de","subject":"Re: [PATCH 10/10] push: teach push to be quiet if local ref is strict subset of remote ref","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-10-31T21:31:05Z","receivedAt":"2007-10-31T21:31:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Steffen Prohaska <prohaska@zib.de> writes:\n\n>> You forgot a lot more important part.  Pushing into publishing\n>> repositories.  And the discussion is about git-push command.\n>\n> Exactly, here are two examples:\n>\n> If you push only to publishing repositories that are read\n> only by others, you'll never encounter the problem that\n> 10/10 tried to solve. The publishing repository is never\n> changed by others. You are the only one who pushes to this\n> repository. Therefore the remote never advances unexpectedly.\n\nWrong.\n\nPeople can and do work from more than one private repositories\n(I do).  In a sense, that is sharing the repository with\noneself.\n\nI may do an emergency patch to fix breakage on 'maint' (and\n'maint' only) from a location that is not my primary development\nbox and push the fix out.  I fully expect that the push will\npush out 'maint' and expect the other branches such as 'master'\non the remote side to stay the same, as I haven't touched\n'master' on that box for quite a while and it is now stale.  In\nthat situation, I _want_ the \"git push\" itself to report failure\nto notify me that it did not push what _I_ asked it to push out,\nso that I can be reminded that I'd better do \"git push $remote\nmaint\" the next time.  In the meantime, even though it reports\na failure, 'master' on the remote side is _not_ updated, so the\nbehaviour is still _safe_.\n\n> Another difference is the way changes are integrated. In\n> a workflow without shared repositories, only pull is used\n> for integration, while push in only used for publishing the\n> changes.\n\nWrong.  push is a mirror of fetch and does not do _any_\nintegration.  It is just a safe (because it insists on\nfast-forward) propagation mechanism.  Your integration still\nhappens with pull (actually, shared repository people seem to\nprefer \"fetch + rebase\" over \"pull\" which is \"fetch + merge\").\n\n> This is different if you work with a shared repository. Bob\n> checks out the shared branch foo to his local branch bar and\n> later he needs to push bar back to the shared branch foo. Bob\n> needs to push changes from his local branch bar to the branch\n> foo in the remote repository, a branch with a different name.\n> This need does not emerge when working with two publishing\n> repositories, as described above.\n\nSo you do \"git push $remote bar:foo\".  If you do that regulary,\nthere are configuration mechanisms to help you reduce your\nkeyboard wear.  What's the problem?\n"},{"id":"57788","messageId":"6B0CD829-A964-410B-8C23-74D26BD2C0FA@zib.de","threadId":"10503","inReplyTo":"7vlk9jgeee.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 10/10] push: teach push to be quiet if local ref is strict subset of remote ref","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2007-11-01T07:03:57Z","receivedAt":"2007-11-01T07:03:57Z","isPatch":true,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"\nOn Oct 31, 2007, at 10:31 PM, Junio C Hamano wrote:\n\n> Steffen Prohaska <prohaska@zib.de> writes:\n>\n>>> You forgot a lot more important part.  Pushing into publishing\n>>> repositories.  And the discussion is about git-push command.\n>>\n>> Exactly, here are two examples:\n>>\n>> If you push only to publishing repositories that are read\n>> only by others, you'll never encounter the problem that\n>> 10/10 tried to solve. The publishing repository is never\n>> changed by others. You are the only one who pushes to this\n>> repository. Therefore the remote never advances unexpectedly.\n>\n> Wrong.\n>\n> People can and do work from more than one private repositories\n> (I do).  In a sense, that is sharing the repository with\n> oneself.\n\nI do, too. But as long as I do not forget what I've done, the\nbranches do not advance _unexpectedly_. I am in full control.\n\n\n> I may do an emergency patch to fix breakage on 'maint' (and\n> 'maint' only) from a location that is not my primary development\n> box and push the fix out.  I fully expect that the push will\n> push out 'maint' and expect the other branches such as 'master'\n> on the remote side to stay the same, as I haven't touched\n> 'master' on that box for quite a while and it is now stale.  In\n> that situation, I _want_ the \"git push\" itself to report failure\n> to notify me that it did not push what _I_ asked it to push out,\n> so that I can be reminded that I'd better do \"git push $remote\n> maint\" the next time.  In the meantime, even though it reports\n> a failure, 'master' on the remote side is _not_ updated, so the\n> behaviour is still _safe_.\n\nYou're right it is safe, but it may be confusing.\n\n\n>> Another difference is the way changes are integrated. In\n>> a workflow without shared repositories, only pull is used\n>> for integration, while push in only used for publishing the\n>> changes.\n>\n> Wrong.  push is a mirror of fetch and does not do _any_\n> integration.  It is just a safe (because it insists on\n> fast-forward) propagation mechanism.  Your integration still\n> happens with pull (actually, shared repository people seem to\n> prefer \"fetch + rebase\" over \"pull\" which is \"fetch + merge\").\n\nRight; but you can't push without doing the integration. If you\nhave new changes on the remote side you _must_ pull before\nyou can push. You're forced to do the integration immediately.\nYour main objective was to push, but the shared workflow forces\nyou to do the integration _now_ (by using pull). In a pull-only\nworkflow, you can just push and defere the integration for later.\n\nSome people claim fetch + rebase is superior to fetch + merge.\nThe only point I can see is that fetch + rebase gives a linear\nhistory without loops, which is nicer to visualize. I recently\nasked on the list if there are any benefits of fetch + rebase\nover fetch + merge, besides a nicer visualization. I didn't\nreceive many interesting comments. One comment explained\nthat rebase can shift the merge conflict resolution from\nthe maintainer (merge) to the original author (rebase). But\nthis is not very interesting in a shared workflow, because\nthe author must resolve conflicts in any case before he can\npush. It doesn't matter much if he uses merge or rebase to\ndo so.\n\nI evaluated if teaching people fetch + rebase before teaching\nfetch + merge is a good idea. Therefore I tested some scenarios\nwith people who are new to git. The result is that there are\ntoo many situations where fetch + rebase might be confusing.\nI abandoned my idea.\n\nI decided that fetch + merge is _easier_. It works in all\nsituations, it's easier to explain, it's better supported\n(automerge), it can be used to work on shared topic branches.\nDefinitely fetch + merge is the first workflow you should\nlearn. At the moment I'm not anymore interested in the fetch +\nrebase approach.\n\n\n>> This is different if you work with a shared repository. Bob\n>> checks out the shared branch foo to his local branch bar and\n>> later he needs to push bar back to the shared branch foo. Bob\n>> needs to push changes from his local branch bar to the branch\n>> foo in the remote repository, a branch with a different name.\n>> This need does not emerge when working with two publishing\n>> repositories, as described above.\n>\n> So you do \"git push $remote bar:foo\".  If you do that regulary,\n> there are configuration mechanisms to help you reduce your\n> keyboard wear.  What's the problem?\n\nToo complex and not flexible enough.\n\nThe configuration is in the remote section. Therefore I can\ntell git what to do only on a per-branch basis. What do you\nthink about my recent proposal to add branch.$name.push?\n\n\nAnd I want to avoid that people need to learn about the details\nof the configuration mechanism on the first time they use git.\n\nI am searching for a solution that just works for them. They\ncurrently use CVS. I'll give them a detailed getting started\ndocument for git. The workflow described should be as simple as\npossible, but safe and reliable. No confusing error messages\nshould appear. Only a few commands should be needed to\ncontribute to a shared branch. The workflow described should\nuse git in a sane way that provides opportunities to use more\nof its power later.\n\nSo here is what I'd like to have.\n\n    git clone ssh://server/git/project.git project\n\n    [ On Windows the hassel already starts because it actually is\n\n\tgit clone -n ssh://sever/git/project.git project\n\tgit config core.autocrlf true\n\n      And here's the next point. git config doesn't validate the\n      variable. It accepts _any_ variable. If you have a typo\n      you go without autocrlf. ... but this is a different story. ]\n\n    cd project\n    git checkout -b devel origin/devel\n    # work, commit, work, commit\n    git push  # maybe git pull first, but git would tell you\n\nThe last command, git push, can already cause trouble. git\nautomatically created a local master and the remote master\nmay have advanced, so git push would complain with an error.\nCurrently the correct command would be\n\"git push origin devel\".\n\n\nAn alternative scenario is that you want to start work that\nwill not be ready right away. So you start a topic branch\n\n    git checkout -b topic origin/devel\n    # work, commit, some time passes, work, commit\n    git pull \t# integrate changes from devel\n    # work, commit\n    git pull\n    git push \t# this one should push to origin/devel\n\n\nIn scenario three you planned to finish your work right away\nbut the problem turned out to be harder. Here, the following\nwould be nice\n\n    git checkout -b devel origin/devel\n    # work, commit, hmm... much harder ...\n    git branch -m devel dolater\n\n    # do something else\n\n    git checkout dolater\n    # finish work\n    git pull    # integrate with other work on devel\n    git push    # push back to shared branch\n\n\nAnother question is what to do with a local branch after\nyou finished work. We recently had the\n\"Re: best git practices, was Re: Git User's Survey 2007\nunfinished summary continued\" aka the 200-local-branches\ndiscussion.\n\nThere were different suggestions what to do. A reasonable\nsuggestion was to delete the local branch after you're done.\nThis clearly distinguishes between remote branches (which are\nmirrored as a remote tracking branch) and local branches. Local\nbranches are _your_ branches while the remote branches contain\nthe shared work. If you're done with your local work, delete\nyour local branch. So maybe you should do\n\n    git checkout origin/devel\n    git branch -d devel\n\nNow you're on a detached branch that points to origin/work.\nBut how to do you get new changes from others? git pull would\nnot work and git fetch neither.\n\nIndependently of what the best practice is, leaving the local\nwork branch there shouldn't do any harm because I'm sure that\nsome devs will forget to clean up, independently of what I tell\nthem.\n\n\tSteffen\n"},{"id":"57791","messageId":"47298BD7.2000902@op5.se","threadId":"10503","inReplyTo":"7vlk9jgeee.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 10/10] push: teach push to be quiet if local ref is strict subset of remote ref","fromName":"Andreas Ericsson","fromEmail":"ae@op5.se","sentAt":"2007-11-01T08:18:31Z","receivedAt":"2007-11-01T08:18:31Z","isPatch":true,"sender":{"key":"ae@op5.se","avatar":"https://gravatar.com/avatar/426e89595c75a8f5252dd0c989e5fabe5bcac616e68557427ad9aef6b0ca342a?d=mp&s=160"},"body":"Junio C Hamano wrote:\n> Steffen Prohaska <prohaska@zib.de> writes:\n> \n>>> You forgot a lot more important part.  Pushing into publishing\n>>> repositories.  And the discussion is about git-push command.\n>> Exactly, here are two examples:\n>>\n>> If you push only to publishing repositories that are read\n>> only by others, you'll never encounter the problem that\n>> 10/10 tried to solve. The publishing repository is never\n>> changed by others. You are the only one who pushes to this\n>> repository. Therefore the remote never advances unexpectedly.\n> \n> Wrong.\n> \n> People can and do work from more than one private repositories\n> (I do).  In a sense, that is sharing the repository with\n> oneself.\n> \n\nI believe your troubles are alleviated a great deal by the fact\nthat you actually know when upstream has changes, and what those\nchanges are supposed to be. A communications breakdown with only\none person involved is sort of hard to imagine.\n\n> (actually, shared repository people seem to\n> prefer \"fetch + rebase\" over \"pull\" which is \"fetch + merge\").\n> \n\nThat's definitely true. The number of useless merge-commits we\nhave in our repos is annoying, and has twice made bisect a bit\ntroublesome for no good reason.\n\n-- \nAndreas Ericsson                   andreas.ericsson@op5.se\nOP5 AB                             www.op5.se\nTel: +46 8-230225                  Fax: +46 8-230231\n"},{"id":"57792","messageId":"0A8A6A99-4C8B-4056-9068-DA54B69B08B5@zib.de","threadId":"10503","inReplyTo":"47298BD7.2000902@op5.se","subject":"Re: [PATCH 10/10] push: teach push to be quiet if local ref is strict subset of remote ref","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2007-11-01T08:36:24Z","receivedAt":"2007-11-01T08:36:24Z","isPatch":true,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"\nOn Nov 1, 2007, at 9:18 AM, Andreas Ericsson wrote:\n\n> Junio C Hamano wrote:\n>\n>> (actually, shared repository people seem to\n>> prefer \"fetch + rebase\" over \"pull\" which is \"fetch + merge\").\n>\n> That's definitely true. The number of useless merge-commits we\n> have in our repos is annoying, and has twice made bisect a bit\n> troublesome for no good reason.\n\nCan you describe a bit more what's \"annoying\" about them?\nIs it the visualization? Or are there more problems; like\nthe trouble with bisect?\n\nI'm trying to estimate if it's worth teaching _all_\ndevelopers rebase or if we should just live with the \"useless\"\nmerge-commits.\n\n\tSteffen\n"},{"id":"57795","messageId":"47299855.9010204@op5.se","threadId":"10503","inReplyTo":"6B0CD829-A964-410B-8C23-74D26BD2C0FA@zib.de","subject":"Re: [PATCH 10/10] push: teach push to be quiet if local ref is strict subset of remote ref","fromName":"Andreas Ericsson","fromEmail":"ae@op5.se","sentAt":"2007-11-01T09:11:49Z","receivedAt":"2007-11-01T09:11:49Z","isPatch":true,"sender":{"key":"ae@op5.se","avatar":"https://gravatar.com/avatar/426e89595c75a8f5252dd0c989e5fabe5bcac616e68557427ad9aef6b0ca342a?d=mp&s=160"},"body":"Steffen Prohaska wrote:\n> \n> On Oct 31, 2007, at 10:31 PM, Junio C Hamano wrote:\n> \n>> Steffen Prohaska <prohaska@zib.de> writes:\n>>\n>>>> You forgot a lot more important part.  Pushing into publishing\n>>>> repositories.  And the discussion is about git-push command.\n>>>\n>>> Exactly, here are two examples:\n>>>\n>>> If you push only to publishing repositories that are read\n>>> only by others, you'll never encounter the problem that\n>>> 10/10 tried to solve. The publishing repository is never\n>>> changed by others. You are the only one who pushes to this\n>>> repository. Therefore the remote never advances unexpectedly.\n>>\n>> Wrong.\n>>\n>> People can and do work from more than one private repositories\n>> (I do).  In a sense, that is sharing the repository with\n>> oneself.\n> \n> I do, too. But as long as I do not forget what I've done, the\n> branches do not advance _unexpectedly_. I am in full control.\n> \n> \n>> I may do an emergency patch to fix breakage on 'maint' (and\n>> 'maint' only) from a location that is not my primary development\n>> box and push the fix out.  I fully expect that the push will\n>> push out 'maint' and expect the other branches such as 'master'\n>> on the remote side to stay the same, as I haven't touched\n>> 'master' on that box for quite a while and it is now stale.  In\n>> that situation, I _want_ the \"git push\" itself to report failure\n>> to notify me that it did not push what _I_ asked it to push out,\n>> so that I can be reminded that I'd better do \"git push $remote\n>> maint\" the next time.  In the meantime, even though it reports\n>> a failure, 'master' on the remote side is _not_ updated, so the\n>> behaviour is still _safe_.\n> \n> You're right it is safe, but it may be confusing.\n> \n> \n>>> Another difference is the way changes are integrated. In\n>>> a workflow without shared repositories, only pull is used\n>>> for integration, while push in only used for publishing the\n>>> changes.\n>>\n>> Wrong.  push is a mirror of fetch and does not do _any_\n>> integration.  It is just a safe (because it insists on\n>> fast-forward) propagation mechanism.  Your integration still\n>> happens with pull (actually, shared repository people seem to\n>> prefer \"fetch + rebase\" over \"pull\" which is \"fetch + merge\").\n> \n> Right; but you can't push without doing the integration. If you\n> have new changes on the remote side you _must_ pull before\n> you can push.\n\nYes, because otherwise you'd rewrite published history. That's not\na good thing.\n\n> You're forced to do the integration immediately.\n\nYes, but you get to choose how. Perhaps git-push should list more\noptions than just git-pull, such as the three commands required to\nrebase the currently checked out branch onto its remote counterpart.\nThat would support more workflows.\n\n> Your main objective was to push, but the shared workflow forces\n> you to do the integration _now_ (by using pull). In a pull-only\n> workflow, you can just push and defere the integration for later.\n> \n\nNo, you can also fetch + rebase.\n\n> Some people claim fetch + rebase is superior to fetch + merge.\n> The only point I can see is that fetch + rebase gives a linear\n> history without loops, which is nicer to visualize. I recently\n> asked on the list if there are any benefits of fetch + rebase\n> over fetch + merge, besides a nicer visualization.\n\n\nIt's easier to bisect. If git bisect lands you on a merge-commit,\nyou need to start a new bisect for each of the parents included\nin the merge. Hopefully the nature of the merge gives a clue so\nthe user can make an educated guess as to which parent introduced\nthe bogus commit, but for an \"evil octopus\" (unusual) or if the\nmerge had conflicts which were resolved in a buggy way (not\nexactly uncommon), it can be quite a hassle to get things right.\nWith a mostly linear history, this problem goes away.\n\n\n> I didn't\n> receive many interesting comments. One comment explained\n> that rebase can shift the merge conflict resolution from\n> the maintainer (merge) to the original author (rebase). But\n> this is not very interesting in a shared workflow, because\n> the author must resolve conflicts in any case before he can\n> push. It doesn't matter much if he uses merge or rebase to\n> do so.\n> \n\nIt depends. When commit ordering doesn't matter the original\nauthor can use \"git rebase --skip\" and then continue with the\nrebase to get as much as possible out as quickly as possible.\nI'm in the unfortunate position of having a boss that likes\nto fiddle with help-texts in code when it's in alpha-testing.\nSometimes that causes conflicts but it's often not important\nenough to spend 30 minutes figuring out how to resolve it\nproperly. I tend to just skip those patches and send them as\nemails to our tech-writer instead, asking him to rephrase the\ntext to incorporate both changes, and then manually applying\nthe text to the end result.\n\n> \n> I am searching for a solution that just works for them. They\n> currently use CVS. I'll give them a detailed getting started\n> document for git. The workflow described should be as simple as\n> possible, but safe and reliable.\n\n\nIf they're used to CVS and want to use more than one branch without\nhaving to learn additional syntax, nothing can help, methinks.\n\n> \n> Another question is what to do with a local branch after\n> you finished work. We recently had the\n> \"Re: best git practices, was Re: Git User's Survey 2007\n> unfinished summary continued\" aka the 200-local-branches\n> discussion.\n> \n\nWe're at 224 branches now, having added 7 new repos.\n\n> There were different suggestions what to do. A reasonable\n> suggestion was to delete the local branch after you're done.\n\nExcept that it doesn't work unless you either detach the HEAD\n(which prints a big fat ugly message) or give it -D to force\nit, which I really, really don't recommend. We use git because\nI'm pretty confident in its capabilities of never ever losing\nanything. Using the seemingly harmless -D switch to git-branch\nputs us at risk of wiping history quite without noticing.\n\n> This clearly distinguishes between remote branches (which are\n> mirrored as a remote tracking branch) and local branches. Local\n> branches are _your_ branches while the remote branches contain\n> the shared work. If you're done with your local work, delete\n> your local branch. So maybe you should do\n> \n>    git checkout origin/devel\n\nExcept that this gives a warning-esque message:\nNote: moving to \"origin/devel\" which isn't a local branch\nIf you want to create a new branch from this checkout, you may do so\n(now or later) by using -b with the checkout command again. Example:\n  git checkout -b <new_branch_name>\nHEAD is now at deadbeef... Ma! Pa butchered all the cows!\n\nTo me, this indicates I've done something git thinks I shouldn't have.\n\n> \n> Independently of what the best practice is, leaving the local\n> work branch there shouldn't do any harm because I'm sure that\n> some devs will forget to clean up, independently of what I tell\n> them.\n> \n\nI wholeheartedly agree with this one.\n\n-- \nAndreas Ericsson                   andreas.ericsson@op5.se\nOP5 AB                             www.op5.se\nTel: +46 8-230225                  Fax: +46 8-230231\n"},{"id":"57796","messageId":"47299C67.1090309@op5.se","threadId":"10503","inReplyTo":"0A8A6A99-4C8B-4056-9068-DA54B69B08B5@zib.de","subject":"Re: [PATCH 10/10] push: teach push to be quiet if local ref is strict subset of remote ref","fromName":"Andreas Ericsson","fromEmail":"ae@op5.se","sentAt":"2007-11-01T09:29:11Z","receivedAt":"2007-11-01T09:29:11Z","isPatch":true,"sender":{"key":"ae@op5.se","avatar":"https://gravatar.com/avatar/426e89595c75a8f5252dd0c989e5fabe5bcac616e68557427ad9aef6b0ca342a?d=mp&s=160"},"body":"Steffen Prohaska wrote:\n> \n> On Nov 1, 2007, at 9:18 AM, Andreas Ericsson wrote:\n> \n>> Junio C Hamano wrote:\n>>\n>>> (actually, shared repository people seem to\n>>> prefer \"fetch + rebase\" over \"pull\" which is \"fetch + merge\").\n>>\n>> That's definitely true. The number of useless merge-commits we\n>> have in our repos is annoying, and has twice made bisect a bit\n>> troublesome for no good reason.\n> \n> Can you describe a bit more what's \"annoying\" about them?\n> Is it the visualization? Or are there more problems; like\n> the trouble with bisect?\n> \n\nVisualization is a small nuissance. git-bisect troubles are more\nworrisome. I've been in the seat where useless merges means git\nbisect needs constant babysitting and constant manual handling.\nIt's no fun at all, so we're sticking with the fetch+rebase flow.\n\n> I'm trying to estimate if it's worth teaching _all_\n> developers rebase or if we should just live with the \"useless\"\n> merge-commits.\n> \n\nI'd say that depends on how valuable you find gitk, qgit and\ngit-bisect are. To me, I'd happily use any scm in the world,\nso long as it has git-bisect. Otoh, I'm a lazy bastard and\nlove bisect so much that all our automated tests are focused\naround \"git bisect run\". This means bugs in software released\nto customers are few and far apart. When we get one reported,\nwe just create a new test that exposes it, fire up git-bisect\nand then go to lunch. Quality costs, however. We pay that bill\nby using a workflow that's perhaps more convoluted than\nnecessary.\n\n-- \nAndreas Ericsson                   andreas.ericsson@op5.se\nOP5 AB                             www.op5.se\nTel: +46 8-230225                  Fax: +46 8-230231\n"},{"id":"57844","messageId":"3550D197-CA8C-4B06-9A95-3C7F18EBEFA7@zib.de","threadId":"10503","inReplyTo":"47299855.9010204@op5.se","subject":"Re: [PATCH 10/10] push: teach push to be quiet if local ref is strict subset of remote ref","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2007-11-01T16:43:29Z","receivedAt":"2007-11-01T16:43:29Z","isPatch":true,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"\nOn Nov 1, 2007, at 10:11 AM, Andreas Ericsson wrote:\n\n> Steffen Prohaska wrote:\n>> On Oct 31, 2007, at 10:31 PM, Junio C Hamano wrote:\n>>> Steffen Prohaska <prohaska@zib.de> writes:\n>>>\n>>>> Another difference is the way changes are integrated. In\n>>>> a workflow without shared repositories, only pull is used\n>>>> for integration, while push in only used for publishing the\n>>>> changes.\n>>>\n>>> Wrong.  push is a mirror of fetch and does not do _any_\n>>> integration.  It is just a safe (because it insists on\n>>> fast-forward) propagation mechanism.  Your integration still\n>>> happens with pull (actually, shared repository people seem to\n>>> prefer \"fetch + rebase\" over \"pull\" which is \"fetch + merge\").\n>> Right; but you can't push without doing the integration. If you\n>> have new changes on the remote side you _must_ pull before\n>> you can push.\n>\n> Yes, because otherwise you'd rewrite published history. That's not\n> a good thing.\n>\n>> You're forced to do the integration immediately.\n>\n> Yes, but you get to choose how. Perhaps git-push should list more\n> options than just git-pull, such as the three commands required to\n> rebase the currently checked out branch onto its remote counterpart.\n> That would support more workflows.\n\nI agree. Providing better hints would be good.\n\n\n>> Your main objective was to push, but the shared workflow forces\n>> you to do the integration _now_ (by using pull). In a pull-only\n>> workflow, you can just push and defer the integration for later.\n>\n> No, you can also fetch + rebase.\n\nRight. My point was than one cannot defer the integration. It\nmust be addressed immediately.\n\n\n>> Some people claim fetch + rebase is superior to fetch + merge.\n>> The only point I can see is that fetch + rebase gives a linear\n>> history without loops, which is nicer to visualize. I recently\n>> asked on the list if there are any benefits of fetch + rebase\n>> over fetch + merge, besides a nicer visualization.\n>\n>\n> It's easier to bisect. If git bisect lands you on a merge-commit,\n> you need to start a new bisect for each of the parents included\n> in the merge. Hopefully the nature of the merge gives a clue so\n> the user can make an educated guess as to which parent introduced\n> the bogus commit, but for an \"evil octopus\" (unusual) or if the\n> merge had conflicts which were resolved in a buggy way (not\n> exactly uncommon), it can be quite a hassle to get things right.\n> With a mostly linear history, this problem goes away.\n\nThis is really an interesting point. I did not start to use\ngit bisect regularly. But I certainly plan to do so in the future.\n\nCouldn't bisect learn to better cope with non-linear history?\n\n[...]\n\n\n>> I am searching for a solution that just works for them. They\n>> currently use CVS. I'll give them a detailed getting started\n>> document for git. The workflow described should be as simple as\n>> possible, but safe and reliable.\n>\n>\n> If they're used to CVS and want to use more than one branch without\n> having to learn additional syntax, nothing can help, methinks.\n\nThey will learn. But they must not get frustrated too early.\nI also don't wont to see them lining up in front of my office.\n\n\nBTW, what do you thing about the proposal to add branch.$name.push [1]?\n\n[1] http://marc.info/?l=git&m=119384331712996&w=2\n\n\n[...]\n\n>> There were different suggestions what to do. A reasonable\n>> suggestion was to delete the local branch after you're done.\n>\n> Except that it doesn't work unless you either detach the HEAD\n> (which prints a big fat ugly message) or give it -D to force\n> it, which I really, really don't recommend. We use git because\n> I'm pretty confident in its capabilities of never ever losing\n> anything. Using the seemingly harmless -D switch to git-branch\n> puts us at risk of wiping history quite without noticing.\n\nI don't like -D either. I liked the idea mentioned recently\nto check -d against the remotes. If a remote tracking branch\nhas the history it should be considered fully merged.\n\nAnother idea may be to distinguish between detached head and\ncheckout of remote tracking branch. Maybe we could do some\nuseful things if get knew that the user is 'on a remote tracking\nbranch'. Committing could be forbidden. A suggestion would be\nprinted instead to use \"git checkout -b something\", which could act\nas if the remote branch was mentioned on the command line.\n\nSomething like that would be needed before I'd seriously\nsuggest to delete local branches after you finished your work.\n\n\n>> This clearly distinguishes between remote branches (which are\n>> mirrored as a remote tracking branch) and local branches. Local\n>> branches are _your_ branches while the remote branches contain\n>> the shared work. If you're done with your local work, delete\n>> your local branch. So maybe you should do\n>>    git checkout origin/devel\n>\n> Except that this gives a warning-esque message:\n> Note: moving to \"origin/devel\" which isn't a local branch\n> If you want to create a new branch from this checkout, you may do so\n> (now or later) by using -b with the checkout command again. Example:\n>  git checkout -b <new_branch_name>\n> HEAD is now at deadbeef... Ma! Pa butchered all the cows!\n>\n> To me, this indicates I've done something git thinks I shouldn't have.\n\nI agree. This could probably be suppressed if git handled remote\ntracking branches a bit differently from other detached heads.\n\n\n>> Independently of what the best practice is, leaving the local\n>> work branch there shouldn't do any harm because I'm sure that\n>> some devs will forget to clean up, independently of what I tell\n>> them.\n>\n> I wholeheartedly agree with this one.\n\nSo I think we need to resolve this first.\n\nDo you already have post-checkout script that makes useful\nsuggestions.  I remember you mentioned something like that\nduring the 200-local-branches discussion.\n\n\tSteffen\n"},{"id":"57852","messageId":"7vfxzpbtxv.fsf@gitster.siamese.dyndns.org","threadId":"10503","inReplyTo":"3550D197-CA8C-4B06-9A95-3C7F18EBEFA7@zib.de","subject":"Re: [PATCH 10/10] push: teach push to be quiet if local ref is strict subset of remote ref","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-11-01T20:18:52Z","receivedAt":"2007-11-01T20:18:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Steffen Prohaska <prohaska@zib.de> writes:\n\n> On Nov 1, 2007, at 10:11 AM, Andreas Ericsson wrote:\n>\n>> Steffen Prohaska wrote:\n>>\n>>> You're forced to do the integration immediately.\n\nThe context of this \"forced\" is that you say (in the following\nparagraph) the user's main objective was to \"push\", but I do not\nthink \"to push\" is ever the main objective.\n\n - If it is to give integrated result for others to work further\n   on, then you need to resolve before being able to achieve\n   that goal.  There is no escaping from it.\n\n - On the other hand, if it is to show what you did as early as\n   possible in a working shape, and if the updated shared\n   repository has changes from somebody else that conflicts you,\n   in a CVS/SVN style shared workflow, there is no way for you\n   to show what you did in isolation.  If you try to follow that\n   model in git and insist pushing to the same branch, then you\n   are forced to resolve first.\n\n   But you do not have to.  You could push out to another new\n   branch, and say \"Here is how you could do it, although this\n   is based on an older codebase and conflicts with what\n   recently happened to the tip\".  You could even ask other\n   party whose changes conflict with yours to help with the\n   merge by saying \"I pushed it out, you are more familiar with\n   that area of the code and with your changes near the tip of\n   the trunk, so could you merge it and push out the result?\"\n\n>> Yes, but you get to choose how. Perhaps git-push should list more\n>> options than just git-pull, such as the three commands required to\n>> rebase the currently checked out branch onto its remote counterpart.\n>> That would support more workflows.\n>\n> I agree. Providing better hints would be good.\n\nI am not so sure about that.  If there are three different\nworkflows, should git-push give hints suitable for all of them?\n\nThe current hint was added in response to users' requests, and I\nthink it could be generalized.  What we would want the end user\nto realize is:\n\n    What I tried to push out is stale, I do not want to push out\n    something that does not contain what the other side has\n    done, so I need to integrate my work with what the other\n    side have before pushing to that branch at the remote.\n\n    In my workflow, that means doing rebase of the branch I\n    tried to push out on top of the remote branch I was trying\n    to push to.\n\nThe second paragraph depends on the workflow.  Do we want to\n(can we afford the space to) give a laundry list here?  Probably\nnot.\n\n>>> Your main objective was to push, but the shared workflow forces\n>>> you to do the integration _now_ (by using pull). In a pull-only\n>>> workflow, you can just push and defer the integration for later.\n>>\n>> No, you can also fetch + rebase.\n>\n> Right. My point was than one cannot defer the integration. It\n> must be addressed immediately.\n\nSee above.\n\n>>> Some people claim fetch + rebase is superior to fetch + merge.\n>>> The only point I can see is that fetch + rebase gives a linear\n>>> history without loops, which is nicer to visualize. I recently\n>>> asked on the list if there are any benefits of fetch + rebase\n>>> over fetch + merge, besides a nicer visualization.\n>>\n>>\n>> It's easier to bisect...\n>> With a mostly linear history, this problem goes away.\n>\n> This is really an interesting point. I did not start to use\n> git bisect regularly. But I certainly plan to do so in the future.\n>\n> Couldn't bisect learn to better cope with non-linear history?\n\nIt copes with it as best as it can.\n\nAnother thing to think about is how \"everybody fetches, merges\nand pushes out\" would interact with the concept of \"mainline\".\nStrictly speaking, the point of distributed development is that\nthere is no mainline, but workflows based on \"fetch + rebase\"\nallows --first-parent to give a reasonable approximation of what\npeople would naively expect how the mainline would look like.\nIf everybody fetches, merges and pushes out, there is no\n\"mainline\" and --first-parent would give totally useless\nhistory.\n"},{"id":"57930","messageId":"63FCD695-B952-4624-854C-0F1C662D94D1@zib.de","threadId":"10503","inReplyTo":"7vfxzpbtxv.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 10/10] push: teach push to be quiet if local ref is strict subset of remote ref","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2007-11-02T07:21:26Z","receivedAt":"2007-11-02T07:21:26Z","isPatch":true,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"\nOn Nov 1, 2007, at 9:18 PM, Junio C Hamano wrote:\n\n> Steffen Prohaska <prohaska@zib.de> writes:\n>\n>> On Nov 1, 2007, at 10:11 AM, Andreas Ericsson wrote:\n>>\n>>> Steffen Prohaska wrote:\n>>>\n>>>> You're forced to do the integration immediately.\n>\n> The context of this \"forced\" is that you say (in the following\n> paragraph) the user's main objective was to \"push\", but I do not\n> think \"to push\" is ever the main objective.\n\nRight. I should probably describe a bit more of the context.\n\nWe have a shared branch for a group of developer who are located\nin the same building. We are allowed to commit reasonably stable\ncode to this branch. Changes should compile and the commiter\nshould be convinced that it does something useful without\nbreaking other code. But failing to meet these requirements\nis acceptable. For example it is sufficient to compile on\nonly one architecture and have good reason to believe that\nthe other architectures will work, too.\n\nA nightly job builds the shared branch on all of our\narchitectures and creates a report that is available the next\nday. If problems happen you should fix them asap. If someone\nspots problems causes by others that need to be addressed\nright away, he can walk over to the office of the one who\ncaused the problem.\n\nIn this setting a user really want to push. Because only then\nthe code will be tested and available for all others. ...\n\n\n\n>  - If it is to give integrated result for others to work further\n>    on, then you need to resolve before being able to achieve\n>    that goal.  There is no escaping from it.\n>\n>  - On the other hand, if it is to show what you did as early as\n>    possible in a working shape, and if the updated shared\n>    repository has changes from somebody else that conflicts you,\n>    in a CVS/SVN style shared workflow, there is no way for you\n>    to show what you did in isolation.  If you try to follow that\n>    model in git and insist pushing to the same branch, then you\n>    are forced to resolve first.\n>\n>    But you do not have to.  You could push out to another new\n>    branch, and say \"Here is how you could do it, although this\n>    is based on an older codebase and conflicts with what\n>    recently happened to the tip\".  You could even ask other\n>    party whose changes conflict with yours to help with the\n>    merge by saying \"I pushed it out, you are more familiar with\n>    that area of the code and with your changes near the tip of\n>    the trunk, so could you merge it and push out the result?\"\n\n\n... I know we could use git to establish a more complex workflow\nthat would give better guarantees on the published branches.\n\nBut it's a judgement how much complexity you want to\nadd. Pushing to a different branch instead of solving\nconflicts right away may be a good model to postpone conflict\nresolution. But it requires more knowledge of git and more\ncommands. Right now, the users are trained on a CVS workflow\nand they expect that conflicts may occur and if so need to\nbe addressed right away. The next step is probably to learn\nhow git could help them to do this.  (index vs. work tree,\nmergetool, ...)\n\nBtw, I have another 'stable' branch, which I have full control\nover. This branch is built and tested prior to pushing to the\npublic repository. So, if the shared branch completely breaks\ndown, we can fall-back to the stable branch.\n\nWe haven't figured out much more of our workflow. The first\nmilestone is to migrate from CVS to git continuing to use a\nCVS-style workflow.\n\n\n\n>>> Yes, but you get to choose how. Perhaps git-push should list more\n>>> options than just git-pull, such as the three commands required to\n>>> rebase the currently checked out branch onto its remote counterpart.\n>>> That would support more workflows.\n>>\n>> I agree. Providing better hints would be good.\n>\n> I am not so sure about that.  If there are three different\n> workflows, should git-push give hints suitable for all of them?\n>\n> The current hint was added in response to users' requests, and I\n> think it could be generalized.  What we would want the end user\n> to realize is:\n>\n>     What I tried to push out is stale, I do not want to push out\n>     something that does not contain what the other side has\n>     done, so I need to integrate my work with what the other\n>     side have before pushing to that branch at the remote.\n>\n>     In my workflow, that means doing rebase of the branch I\n>     tried to push out on top of the remote branch I was trying\n>     to push to.\n>\n> The second paragraph depends on the workflow.  Do we want to\n> (can we afford the space to) give a laundry list here?  Probably\n> not.\n\nI agree.\n\nBut how many different ways of integrating do we have? I only know\nof merge or rebase. So, we may just mention both.\n\nOr we only print an extended message if '--verbose' is given. The\nshort message could be even shorter and refer to '--verbose':\n\nerror: remote 'refs/heads/master' is ahead of local 'refs/heads/ \nmaster'. Use --verbose for more details.\n\nIf the user passes --verbose he gets the full story:\n\n- A more detailed description of 'ahead'. For example,\n   local could be a strict subset of remote, or local could have\n   new commits that are not already at remote.\n\n- We could give all sorts of hints, for example how to list the\n   commits that are new on the local side. Recommendations how to\n   solve the issue (merge, rebase). The message shouldn't get\n   too verbose, though.\n\n\n\n>>>> Your main objective was to push, but the shared workflow forces\n>>>> you to do the integration _now_ (by using pull). In a pull-only\n>>>> workflow, you can just push and defer the integration for later.\n>>>\n>>> No, you can also fetch + rebase.\n>>\n>> Right. My point was than one cannot defer the integration. It\n>> must be addressed immediately.\n>\n> See above.\n\nSee above.\n\n\n>>>> Some people claim fetch + rebase is superior to fetch + merge.\n>>>> The only point I can see is that fetch + rebase gives a linear\n>>>> history without loops, which is nicer to visualize. I recently\n>>>> asked on the list if there are any benefits of fetch + rebase\n>>>> over fetch + merge, besides a nicer visualization.\n>>>\n>>>\n>>> It's easier to bisect...\n>>> With a mostly linear history, this problem goes away.\n>>\n>> This is really an interesting point. I did not start to use\n>> git bisect regularly. But I certainly plan to do so in the future.\n>>\n>> Couldn't bisect learn to better cope with non-linear history?\n>\n> It copes with it as best as it can.\n\nI should try out git bisect to understand the details.\n\n\n> Another thing to think about is how \"everybody fetches, merges\n> and pushes out\" would interact with the concept of \"mainline\".\n> Strictly speaking, the point of distributed development is that\n> there is no mainline, but workflows based on \"fetch + rebase\"\n> allows --first-parent to give a reasonable approximation of what\n> people would naively expect how the mainline would look like.\n> If everybody fetches, merges and pushes out, there is no\n> \"mainline\" and --first-parent would give totally useless\n> history.\n\nBuilding a main line needs more control and more knowledge\nabout git.\n\nHere is what I think can be done. It's only a sketch so\nfar. It's not yet reality. Therefore it might turn out to be\ninfeasible. I'd adjust my plans then.\n\nWe actually have at least three groups of developers that work\nat three different locations. They'll work on different shared\nbranches. We also will create shared topic branches if a smaller\ngroup of developers needs to work together on a prototype.\n\nAt some point shared branches need to become stable. They\nneed to be tested and maybe some of the changes need to be\nreverted if they turn out to be useless. Finally we'll have a\ntip of a shared branch that is stable. Stable depends on the\nquality criteria, which may vary depending on where we are\nin the release cycle. But at least some minimal requirements,\nlike \"compiles on all platforms\" or \"passes all tests\" will be\nverified. Such a stable tip will now be merged with '--no-ff'\nto the mainline. The merge will be thoroughly tested.\n\nThe chain of commits along first parent establishes a mainline\nthat matches certain quality criteria. The criteria are not\nnecessarily met by commits on the side branches. Therefore\nfast-forward must not be used for the merge.\n\nIf we feel comfortable with git, we may consider creating\nbetter topic branches in the first place. But for now I want\nto start with shared branches containing a mixed bag of\ncommits.\n\nDo all this make sense?\n\n\tSteffen\n"},{"id":"57935","messageId":"7vk5p15bkv.fsf@gitster.siamese.dyndns.org","threadId":"10503","inReplyTo":"63FCD695-B952-4624-854C-0F1C662D94D1@zib.de","subject":"Re: [PATCH 10/10] push: teach push to be quiet if local ref is strict subset of remote ref","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-11-02T07:52:00Z","receivedAt":"2007-11-02T07:52:00Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Steffen Prohaska <prohaska@zib.de> writes:\n\n> On Nov 1, 2007, at 9:18 PM, Junio C Hamano wrote:\n>\n>> The context of this \"forced\" is that you say (in the following\n>> paragraph) the user's main objective was to \"push\", but I do not\n>> think \"to push\" is ever the main objective.\n>\n> Right. I should probably describe a bit more of the context.\n\nBoring ;-)\n\n> We have a shared branch for a group of developer who are located\n> ...\n> In this setting a user really want to push. Because only then\n> the code will be tested and available for all others. ...\n\nPretty much expected, sane, and unsurprising.  Then you are in\nthe first category I quoted, and...\n\n>>  - If it is to give integrated result for others to work further\n>>    on, then you need to resolve before being able to achieve\n>>    that goal.  There is no escaping from it.\n\n... it still holds that what the developer wants to do is not\njust \"to push\", but \"to push after making sure what he is going\nto push is in a good enough shape to be pushed\".  Your _workflow_\nis forcing to integrate right away before pushing; don't blame\ngit for this.\n\n>>  - On the other hand, if it is to show what you did as early as\n>>    possible in a working shape, and if the updated shared\n>>    repository has changes from somebody else that conflicts you,\n>>    in a CVS/SVN style shared workflow, there is no way for you\n>>    to show what you did in isolation.  If you try to follow that\n>>    model in git and insist pushing to the same branch, then you\n>>    are forced to resolve first.\n>>\n>>    But you do not have to.  You could push out to another new\n>>    branch, and say \"Here is how you could do it, although this\n>>    is based on an older codebase and conflicts with what\n>>    recently happened to the tip\".  You could even ask other\n>>    party whose changes conflict with yours to help with the\n>>    merge by saying \"I pushed it out, you are more familiar with\n>>    that area of the code and with your changes near the tip of\n>>    the trunk, so could you merge it and push out the result?\"\n>\n> ... I know we could use git to establish a more complex workflow\n> that would give better guarantees on the published branches.\n\nDon't get me wrong.  You do not always have to use the \"push to\na side branch and ask for help from others\", but git opens the\ndoor for you to do so more conveniently, rather than strictly\nsticking to the CVS workflow.    I re-quoted the whole \"On the\nother hand\" part because I think this is something not often\ndone by people with CVS background --- with CVS you can do\nexactly the same thing but it is too cumbersome and people don't\ndo so in practice.  With git, such an interaction is not just\npossible but is a very natural thing to do.\n\nYour more advanced people can be the first ones to employ this\n\"new communication medium\" to help work better among them.  You\ndo not have to force the \"side communication\" as an official\npart of workflow to the whole group.\n\nSCM is just a tool to help developer communication.  Use it\nwisely.\n\n> We haven't figured out much more of our workflow. The first\n> milestone is to migrate from CVS to git continuing to use a\n> CVS-style workflow.\n\nI think that is an interesting admission.  As somebody else on\nthe thread already said, if you are sticking to CVS workflow,\nthere are things that can and cannot be naturally done with\ngit.  Don't break git when you hit the situation in the latter\ncategory without understanding how the world works.\n\n> error: remote 'refs/heads/master' is ahead of local 'refs/heads/\n> master'. Use --verbose for more details.\n\nI'd rather have \"Read section XXX of the user's guide\".\n"},{"id":"57936","messageId":"0C176853-8848-46C8-AD7A-97F73274DC29@wincent.com","threadId":"10503","inReplyTo":"7vlk9jgeee.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 10/10] push: teach push to be quiet if local ref is strict subset of remote ref","fromName":"Wincent Colaiuta","fromEmail":"win@wincent.com","sentAt":"2007-11-02T08:18:03Z","receivedAt":"2007-11-02T08:18:03Z","isPatch":true,"sender":{"key":"greg@hurrell.net","avatar":"https://avatars.githubusercontent.com/u/7074?v=4"},"body":"El 31/10/2007, a las 22:31, Junio C Hamano escribió:\n\n> Wrong.  push is a mirror of fetch and does not do _any_\n> integration.  It is just a safe (because it insists on\n> fast-forward) propagation mechanism.  Your integration still\n> happens with pull (actually, shared repository people seem to\n> prefer \"fetch + rebase\" over \"pull\" which is \"fetch + merge\").\n\n\nOf course, it's too late too change now, but it would be nice if the  \nmirror of \"fetch\" were \"send\". (I know it's been commented in the past  \nthat the fact that \"push\" and \"pull\" aren't mirror operations has  \nsurprised quite a few people.)\n\nCheers,\nWincent\n"},{"id":"57956","messageId":"472AF5F8.40208@op5.se","threadId":"10503","inReplyTo":"3550D197-CA8C-4B06-9A95-3C7F18EBEFA7@zib.de","subject":"Re: [PATCH 10/10] push: teach push to be quiet if local ref is strict subset of remote ref","fromName":"Andreas Ericsson","fromEmail":"ae@op5.se","sentAt":"2007-11-02T10:03:36Z","receivedAt":"2007-11-02T10:03:36Z","isPatch":true,"sender":{"key":"ae@op5.se","avatar":"https://gravatar.com/avatar/426e89595c75a8f5252dd0c989e5fabe5bcac616e68557427ad9aef6b0ca342a?d=mp&s=160"},"body":"Steffen Prohaska wrote:\n> \n> On Nov 1, 2007, at 10:11 AM, Andreas Ericsson wrote:\n> \n>>\n>> It's easier to bisect. If git bisect lands you on a merge-commit,\n>> you need to start a new bisect for each of the parents included\n>> in the merge. Hopefully the nature of the merge gives a clue so\n>> the user can make an educated guess as to which parent introduced\n>> the bogus commit, but for an \"evil octopus\" (unusual) or if the\n>> merge had conflicts which were resolved in a buggy way (not\n>> exactly uncommon), it can be quite a hassle to get things right.\n>> With a mostly linear history, this problem goes away.\n> \n> This is really an interesting point. I did not start to use\n> git bisect regularly. But I certainly plan to do so in the future.\n> \n> Couldn't bisect learn to better cope with non-linear history?\n> \n\nPerhaps it could, but it's far from trivial. I started hacking on\na wrapper for git-bisect which would do just that, but gave up\nrather quickly as the book-keeping required to remember each and\nevery parent-point tried just got out of hand, and it *still*\nwouldn't run in full automatic. It broke down because I also\nwanted merges on non-first-line parents to be delved into. If\nthat didn't happen, I wouldn't *know* the bisect would run fine\nwithout me watching it, so then it was as useless as if I'd have\nhad to sit there the entire time anyway.\n\n\n> \n> BTW, what do you thing about the proposal to add branch.$name.push [1]?\n> \n> [1] http://marc.info/?l=git&m=119384331712996&w=2\n> \n\nI'm not so sure about it. I rather liked the \"don't warn if local is\nstrict subset of remote\" thing though. I teach our devs to just\nignore that warning, but with the same leaden feeling in my stomach\nthat someone, sometime, is going to get bit by it. It's worked so\nfar though, perhaps because our update-hook contains a check meaning\nI'm the only one allowed to do \"git-push --force\".\n\n>>\n>> Except that it doesn't work unless you either detach the HEAD\n>> (which prints a big fat ugly message) or give it -D to force\n>> it, which I really, really don't recommend. We use git because\n>> I'm pretty confident in its capabilities of never ever losing\n>> anything. Using the seemingly harmless -D switch to git-branch\n>> puts us at risk of wiping history quite without noticing.\n> \n> I don't like -D either. I liked the idea mentioned recently\n> to check -d against the remotes. If a remote tracking branch\n> has the history it should be considered fully merged.\n> \n\nYes. Since remote branches are considered when prune'ing anyway,\nand the git-branch -d warning is there to make sure we don't\naccidentally lose any tip pointers, it should be safe to use\n*all* \"named\" refs when checking for git-branch -d's sake (that\nis, everything under refs/{heads,remotes,tags}/**/*).\n\n> Another idea may be to distinguish between detached head and\n> checkout of remote tracking branch. Maybe we could do some\n> useful things if get knew that the user is 'on a remote tracking\n> branch'. Committing could be forbidden.\n\nCommitting nearly *has* to be forbidden.\n\n> A suggestion would be\n> printed instead to use \"git checkout -b something\", which could act\n> as if the remote branch was mentioned on the command line.\n> \n> Something like that would be needed before I'd seriously\n> suggest to delete local branches after you finished your work.\n> \n\nYup. I'll never suggest using \"git branch -D\" to my co-workers. Sooner\nor later there'll be cries of anguish echoing throughout the office\nwhen that happens ;-)\n\n> \n> \n>>> Independently of what the best practice is, leaving the local\n>>> work branch there shouldn't do any harm because I'm sure that\n>>> some devs will forget to clean up, independently of what I tell\n>>> them.\n>>\n>> I wholeheartedly agree with this one.\n> \n> So I think we need to resolve this first.\n> \n> Do you already have post-checkout script that makes useful\n> suggestions.  I remember you mentioned something like that\n> during the 200-local-branches discussion.\n> \n\nNo. Junio suggested I'd implement it as a post-checkout hook, but it\nwould only save me one command and could cause confusion as diff\noutput would change depending on whether one has checked out the\none branch or another prior to running git diff, so I decided against\nit.\n\n-- \nAndreas Ericsson                   andreas.ericsson@op5.se\nOP5 AB                             www.op5.se\nTel: +46 8-230225                  Fax: +46 8-230231\n"},{"id":"57957","messageId":"417C801B-5DFF-4753-AB32-0FA1EB30C8E2@zib.de","threadId":"10503","inReplyTo":"7vk5p15bkv.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 10/10] push: teach push to be quiet if local ref is strict subset of remote ref","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2007-11-02T10:03:45Z","receivedAt":"2007-11-02T10:03:45Z","isPatch":true,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"\nOn Nov 2, 2007, at 8:52 AM, Junio C Hamano wrote:\n\n> ... it still holds that what the developer wants to do is not\n> just \"to push\", but \"to push after making sure what he is going\n> to push is in a good enough shape to be pushed\".  Your _workflow_\n> is forcing to integrate right away before pushing; don't blame\n> git for this.\n\nI don't blame git for forcing the developers to merge. I blame\ngit for not supporting this workflow well enough.\n\nI still believe that\n\n- in a pull-oriented workflow (Linux kernel, git) there's less\n   need to handle unexpected changes on the remote you want to\n   push to. There's maybe also less need to push to heads named\n   differently on the local and the remote (though I'm not sure\n   if this really true).\n\n- in a workflow that is base on shared branches (CVS-style),\n   the remote heads certainly will advance unexpectedly, and\n   git push should support developers to cope with this situation.\n   In addition push should push back to the remote branch a local\n   topic was originally branched off. This makes the need for\n   pushing to a branch named differently on the remote side more\n   likely than in a pull-oriented workflow, where you would\n   publish under your local branch name and ask someone else\n   to pull.\n\n[...]\n\n>\n>> We haven't figured out much more of our workflow. The first\n>> milestone is to migrate from CVS to git continuing to use a\n>> CVS-style workflow.\n>\n> I think that is an interesting admission.  As somebody else on\n> the thread already said, if you are sticking to CVS workflow,\n> there are things that can and cannot be naturally done with\n> git.  Don't break git when you hit the situation in the latter\n> category without understanding how the world works.\n\nFair enough. I absolutely agree that it will never be a design\ngoal of git to directly support a CVS workflow ;)\n\nBut I strongly believe that there is a more universal question\nbehind. It makes sense to have good support for a workflow\nthat is based on a shared repository. A shared repository\ncan be a way\n- to make it easy for the average developer to get started.\n   Only clone to a local working repository is needed, but no\n   publishing repository.\n- to facilitate that commits will be pushed to at a central\n   place. The default is to push back to the shared repository\n   (btw, it's easy to setup hooks to do some access control to\n   avoid havoc). This may increase visibility of changes. It may\n   help doing backups. It may be easy to encourage early integration.\n\nFor small projects with developers available for direct\ncommunication it may even be an option to have just this single\nshared branch.\n\nFor larger project a better infrastructure and more control\nover the changes is certainly a good idea. And git greatly\nsupports more complex workflows. That's the main reason why\nI decided to choose git in the first place.\n\nBut for me the question is how can git be efficiently used to\nsupport a workflow based on a shared repository. It should be\neasy and safe to use and only few commands should be needed\nto get started.\n\n\n>> error: remote 'refs/heads/master' is ahead of local 'refs/heads/\n>> master'. Use --verbose for more details.\n>\n> I'd rather have \"Read section XXX of the user's guide\".\n\nOk; do I need to write the section first or is there? ;)\n\n\nAnd maybe we could do two things (at least for msysgit):\n\n- Rename or link user-manual.html to git-user-manual.html,\n   which would allow saying \"git help user-manual\".\n\n- Support HTML anchors, such that\n   \"git help user-manual#section5\" would open the user manual\n   and jump to the right section.\n\t\n\tSteffen\n"},{"id":"57965","messageId":"7v7il13p1g.fsf@gitster.siamese.dyndns.org","threadId":"10503","inReplyTo":"417C801B-5DFF-4753-AB32-0FA1EB30C8E2@zib.de","subject":"Re: [PATCH 10/10] push: teach push to be quiet if local ref is strict subset of remote ref","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-11-02T10:44:11Z","receivedAt":"2007-11-02T10:44:11Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Steffen Prohaska <prohaska@zib.de> writes:\n\n> - in a pull-oriented workflow (Linux kernel, git) ...\n>   ... There's maybe also less need to push to heads named\n>   differently on the local and the remote (though I'm not sure\n>   if this really true).\n\nThat's far from true but is irrelevant to the discussion of\nsupporting shared repositories better.\n\n> - in a workflow that is base on shared branches (CVS-style),\n>   ...\n>   In addition push should push back to the remote branch a local\n>   topic was originally branched off.\n\nWhy?  If it is shared, and if you are shooting for the simplest\nset of commands, wouldn't you work this way?\n\n\t$ git clone $public my-work-dir\n        $ cd my-work-dir\n        $ git checkout -b --track foo origin/foo\n        $ hack hack hack, commit, commit, commit *on* *foo*\n        $ git push $public foo\n\nI think the recent git defaults to --track anyway so the third\nstep do not spell out --track.\n\nWith your \"remote.$public.push = HEAD\", the last step would be\n\"git push\" without any parameter.\n\nIf you do use private topics, then the story would change this\nway:\n\n        $ git checkout -b --track foo origin/foo\n        $ git checkout -b topic1 foo ;# or origin/foo\n        $ hack hack hack, commit, commit, commit on topic1\n        $ git checkout -b topic2 foo ;# or origin/foo\n        $ hack hack hack, commit, commit, commit on topic2\n        $ git checkout foo\n        $ git merge topic1\n        $ test test test; # test _your_ changes\n        $ git merge topic2\n        $ test test test; # test _your_ changes\n        $ git push ;# again push 'foo' out\n\nThis may fail to fast forward.  You may at this time want to\n\"git fetch\" first, rebase topic1 or topic2 that conflict with\nthe other side on top of updated origin/foo, rebuild foo and\npush the result out, like this:\n\n\t$ git fetch\n        $ git rebase origin/foo topic1\n        $ git branch -f foo origin/foo\n        $ git checkout foo\n        $ git merge topic1\n        $ git merge topic2\n        $ test test test\n        $ git push\n\n>   ... This makes the need for\n>   pushing to a branch named differently on the remote side more\n>   likely than in a pull-oriented workflow,\n\nSo I do not understand this remark.\n"},{"id":"57970","messageId":"DEFB6632-9D04-4CDB-8FF0-DE2214826A5B@zib.de","threadId":"10503","inReplyTo":"7v7il13p1g.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 10/10] push: teach push to be quiet if local ref is strict subset of remote ref","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2007-11-02T11:40:00Z","receivedAt":"2007-11-02T11:40:00Z","isPatch":true,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"\nOn Nov 2, 2007, at 11:44 AM, Junio C Hamano wrote:\n\n> Steffen Prohaska <prohaska@zib.de> writes:\n>\n>> - in a workflow that is base on shared branches (CVS-style),\n>>   ...\n>>   In addition push should push back to the remote branch a local\n>>   topic was originally branched off.\n>\n> Why?  If it is shared, and if you are shooting for the simplest\n> set of commands, wouldn't you work this way?\n\nYes. I would work exactly this way with current git.\n\n\n> \t$ git clone $public my-work-dir\n>         $ cd my-work-dir\n>         $ git checkout -b --track foo origin/foo\n\nSo the implicit rule here is\n\"name a branch identical in all repositories you're dealing with\"\nright?\n\nThat is foo is named foo at the remote, named foo as a tracking\nbranch (git handles this automatically) and is named foo as your\nlocal branch.\n\nI believe it is reasonable. Though I have two questions:\n\n1) If this is best practice, why doesn't save git me from typos?\n    Why do I need to type \"foo\" correctly twice?\n\n2) What shall I do if I am dealing with more than one shared\n    repository?  Andreas' group should already run into problems\n    here. They have several shared repos and if they want to\n    checkout several local branches from different repos they\n    need to somehow encode the name of the remote in the name\n    of the local branch.\n\n\n>         $ hack hack hack, commit, commit, commit *on* *foo*\n>         $ git push $public foo\n>\n> I think the recent git defaults to --track anyway so the third\n> step do not spell out --track.\n\nIt does.\n\n\n> With your \"remote.$public.push = HEAD\", the last step would be\n> \"git push\" without any parameter.\n\nIndeed. Or with my \"branch.$name.push\" it would just be \"git push\"\nas well. And I'd be probably happy then.\n\n\n> If you do use private topics, then the story would change this\n> way:\n>\n>         $ git checkout -b --track foo origin/foo\n>         $ git checkout -b topic1 foo ;# or origin/foo\n\nI'd be more happy without 'or'. I really want to give a single\nrecommendation.\n\nSo the question here is: Should I branch off the local branch or\nshould I branch off the remote branch? When should I do what?\nWhat is best practice and what is used for 'exceptional'\nsituations?\n\n\n>         $ hack hack hack, commit, commit, commit on topic1\n>         $ git checkout -b topic2 foo ;# or origin/foo\n>         $ hack hack hack, commit, commit, commit on topic2\n>         $ git checkout foo\n>         $ git merge topic1\n>         $ test test test; # test _your_ changes\n>         $ git merge topic2\n>         $ test test test; # test _your_ changes\n>         $ git push ;# again push 'foo' out\n\nThis focuses testing on the integration of topic1 with topic2.\n\nYou could as well do the following\n\n\t$ git checkout -b topic1 origin/foo\n\t$ hack ...\n\t$ git checkout -b topic2 origin/foo\n\t$ hack ..\n\n\t[ later ]\n\t$ git checkout topic1\n\t$ git pull # or git fetch; git rebase origin/foo\n\t$ test test test\n\t$ git push origin topic1:origin/foo\n\n\t[ later ]\n\t$ git checkout topic2\n\t$ git pull # or git fetch; git rebase origin/foo\n\t$ test test test\n\t$ git push origin topic2:origin/foo\n\nWith my \"branch.$name.push\" it would just be \"git push\" here.\n\nThis workflow focuses testing on the integration of each of your\ntopics with the new changes on the shared branch independently\nof your other topic.\n\nYou're done at this point. No need to merge a second time,\nno need to reset branches.\n\nIt's probably a good idea to delete your local branches\nnow. And there is one minor question related to that: Where\nto park your HEAD if you want to clean up _all_ of your local\nbranches because you have nothing left to do? Everything is\non the shared remote branch. The only thing you're interested\nnow is to checkout new changes from the shared branch if\ninteresting work was done by others.\n\n\n> This may fail to fast forward.  You may at this time want to\n> \"git fetch\" first, rebase topic1 or topic2 that conflict with\n> the other side on top of updated origin/foo, rebuild foo and\n> push the result out, like this:\n\nOr you could just pull\n\n[ this continues Junio's example from above, you are on branch foo. ]\n\n\t$ git pull\n\t$ test test; # test of your integration of topic1, topic2\n\t             # with the new changes on the shared branch\n\t$ git push\n\n\n\n> \t$ git fetch\n>         $ git rebase origin/foo topic1\n>         $ git branch -f foo origin/foo\n\nHere is another interesting point.\n\nWould you recommend \"git branch -f foo origin/foo\" over\n\"git checkout foo; git reset --hard origin/foo\"? I think the\nfirst command is safer because it doesn't throw away uncommitted\nchanges. However it fails if you are already on branch foo. Then it\nsays \"fatal: Cannot force update the current branch.\". It is not\nvery intuitive if I'd ask users to first leave the branch they\nwant to modify, only to be able to use \"git branch\". \"git reset\"\nalways lets you achieve your goal. (BTW, I don't recommend having\nlocal changes while doing integration testing ... but who knows\nmaybe someone feels comfortable with it.)\n\n\n>         $ git checkout foo\n>         $ git merge topic1\n>         $ git merge topic2\n>         $ test test test\n>         $ git push\n\nUsing rebase requires more commands than using pull, and more\nintrusive  commands like \"branch -f\" or \"reset --hard\" are involved.\n\nThat doesn't mean that you should not use rebase. But it certainly\nneeds more explanation.\n\nAnother related question is the following: After some time the\nuser decides that some help on topic1 would be appreciated and\nanother developer promises to help. So they agree to work on\na shared branch name topic1. The first developer starts with\n\n\t$ git push origin topic1\n\n From now on he _MUST NOT_ use rebase any longer! So starting\nto work on the topic with a second developer completely changed\nthe best practice. From now no rebase is forbidden, which was\nbest practice before.\n\nSo the question for me is: do I want to teach developer a pull\nor a rebase workflow first? Currently I believe pull will be\nsafer for them, better supported by git, and there will be\nsituations they must use pull. If the only nuisance are loops\nin the history when viewing them in gitk, I'm happy to accept\nthis.\n\n\n>>   ... This makes the need for\n>>   pushing to a branch named differently on the remote side more\n>>   likely than in a pull-oriented workflow,\n>\n> So I do not understand this remark.\n\nYeah, I should have added some explanation here. I had Andreas'\n200-local-branches and the topic1/topic2 example in mind that\ndoes the integration against the shared branch.\n\n\tSteffen\n"},{"id":"57972","messageId":"Pine.LNX.4.64.0711021213370.4362@racer.site","threadId":"10503","inReplyTo":"0C176853-8848-46C8-AD7A-97F73274DC29@wincent.com","subject":"Re: [PATCH 10/10] push: teach push to be quiet if local ref is strict subset of remote ref","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-11-02T12:14:04Z","receivedAt":"2007-11-02T12:14:04Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Fri, 2 Nov 2007, Wincent Colaiuta wrote:\n\n> Of course, it's too late too change now, but it would be nice if the \n> mirror of \"fetch\" were \"send\". (I know it's been commented in the past \n> that the fact that \"push\" and \"pull\" aren't mirror operations has \n> surprised quite a few people.)\n\nCould you please just do\n\n\tgit config --global alias.send push\n\nand be done with it?\n\nHth,\nDscho\n"},{"id":"57976","messageId":"A862668C-7895-489A-B13B-597084CAEE11@zib.de","threadId":"10503","inReplyTo":"Pine.LNX.4.64.0711021213370.4362@racer.site","subject":"Re: [PATCH 10/10] push: teach push to be quiet if local ref is strict subset of remote ref","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2007-11-02T12:48:47Z","receivedAt":"2007-11-02T12:48:47Z","isPatch":true,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"\nOn Nov 2, 2007, at 1:14 PM, Johannes Schindelin wrote:\n\n> Hi,\n>\n> On Fri, 2 Nov 2007, Wincent Colaiuta wrote:\n>\n>> Of course, it's too late too change now, but it would be nice if the\n>> mirror of \"fetch\" were \"send\". (I know it's been commented in the  \n>> past\n>> that the fact that \"push\" and \"pull\" aren't mirror operations has\n>> surprised quite a few people.)\n>\n> Could you please just do\n>\n> \tgit config --global alias.send push\n>\n> and be done with it?\n\nThis would certainly be the easiest. But I think the following\nis probably more in line with Wincent's comment:\n\n\tMakefile builds git-send instead of git-push\n\tgit config --global alias.push send\n\t[ wait some time ]\n\tgit config --unset alias.push\n\nThe comment was about how to avoid surprises for people that\nare new to git, not how to let long-time users have an alias\nfor push.\n\nThe _only_ real solution I see right now, is to stop the\ndiscussion and leave \"git push\" as is. I strongly believe that\nthe git community in its majority will refuse to rename push;\nthough I have no evidence for this.\n\n\tSteffen\n"},{"id":"57978","messageId":"5D2EDD64-CD98-4747-8579-25DF7FC9DAAC@wincent.com","threadId":"10503","inReplyTo":"A862668C-7895-489A-B13B-597084CAEE11@zib.de","subject":"Re: [PATCH 10/10] push: teach push to be quiet if local ref is strict subset of remote ref","fromName":"Wincent Colaiuta","fromEmail":"win@wincent.com","sentAt":"2007-11-02T13:11:35Z","receivedAt":"2007-11-02T13:11:35Z","isPatch":true,"sender":{"key":"greg@hurrell.net","avatar":"https://avatars.githubusercontent.com/u/7074?v=4"},"body":"El 2/11/2007, a las 13:48, Steffen Prohaska escribió:\n\n> On Nov 2, 2007, at 1:14 PM, Johannes Schindelin wrote:\n>\n>> On Fri, 2 Nov 2007, Wincent Colaiuta wrote:\n>>\n>>> Of course, it's too late too change now, but it would be nice if the\n>>> mirror of \"fetch\" were \"send\". (I know it's been commented in the  \n>>> past\n>>> that the fact that \"push\" and \"pull\" aren't mirror operations has\n>>> surprised quite a few people.)\n>>\n>> Could you please just do\n>>\n>> \tgit config --global alias.send push\n>>\n>> and be done with it?\n\n(snip)\n\n> The comment was about how to avoid surprises for people that\n> are new to git, not how to let long-time users have an alias\n> for push.\n\nExactly. I was talking about the *initial* surprise for new users, not  \nfor people who already know the difference between push, pull and  \nfetch (99% of people reading this list already, myself included).\n\n> The _only_ real solution I see right now, is to stop the\n> discussion and leave \"git push\" as is. I strongly believe that\n> the git community in its majority will refuse to rename push;\n> though I have no evidence for this.\n\nAs I said above, \"Of course, it's too late to change now\"... I don't  \nthink it will be renamed either.\n\nCheers,\nWincent\n"},{"id":"57979","messageId":"20071102132446.GA31758@hermes.priv","threadId":"10503","inReplyTo":"472AF5F8.40208@op5.se","subject":"Re: [PATCH 10/10] push: teach push to be quiet if local ref is strict subset of remote ref","fromName":"Tom Prince","fromEmail":"tom.prince@ualberta.net","sentAt":"2007-11-02T13:24:46Z","receivedAt":"2007-11-02T13:24:46Z","isPatch":true,"sender":{"key":"tom.prince@ualberta.net","avatar":"https://gravatar.com/avatar/a0ad19caee7618876339485106ec994f5202505eecd210ba5c0bd869feaa555a?d=mp&s=160"},"body":"On Fri, Nov 02, 2007 at 11:03:36AM +0100, Andreas Ericsson wrote:\n> Steffen Prohaska wrote:\n>> On Nov 1, 2007, at 10:11 AM, Andreas Ericsson wrote:\n>>>\n>>> It's easier to bisect. If git bisect lands you on a merge-commit,\n>>> you need to start a new bisect for each of the parents included\n>>> in the merge. Hopefully the nature of the merge gives a clue so\n>>> the user can make an educated guess as to which parent introduced\n>>> the bogus commit, but for an \"evil octopus\" (unusual) or if the\n>>> merge had conflicts which were resolved in a buggy way (not\n>>> exactly uncommon), it can be quite a hassle to get things right.\n>>> With a mostly linear history, this problem goes away.\n>> This is really an interesting point. I did not start to use\n>> git bisect regularly. But I certainly plan to do so in the future.\n>> Couldn't bisect learn to better cope with non-linear history?\n>\n> Perhaps it could, but it's far from trivial. I started hacking on\n> a wrapper for git-bisect which would do just that, but gave up\n> rather quickly as the book-keeping required to remember each and\n> every parent-point tried just got out of hand, and it *still*\n> wouldn't run in full automatic. It broke down because I also\n> wanted merges on non-first-line parents to be delved into. If\n> that didn't happen, I wouldn't *know* the bisect would run fine\n> without me watching it, so then it was as useless as if I'd have\n> had to sit there the entire time anyway.\n\nI haven't had occasion to use git-bisect much, but I was under the\nimpression that bisect could already handle merges, or any other shaped\nhistory just fine.\n\nIf you test a merge and it is bad, git (eventually) picks a commit on one of\nthe branches. If that commit is good, then the merge-base is good, so that the\nbug lies on some other branch. If that commit is bad, then the bug is on some\nancestor of the branch. Thus, no need for special book keeping.\n\n  Tom\n"},{"id":"57984","messageId":"472B2B8F.1060203@op5.se","threadId":"10503","inReplyTo":"20071102132446.GA31758@hermes.priv","subject":"Re: [PATCH 10/10] push: teach push to be quiet if local ref is strict subset of remote ref","fromName":"Andreas Ericsson","fromEmail":"ae@op5.se","sentAt":"2007-11-02T13:52:15Z","receivedAt":"2007-11-02T13:52:15Z","isPatch":true,"sender":{"key":"ae@op5.se","avatar":"https://gravatar.com/avatar/426e89595c75a8f5252dd0c989e5fabe5bcac616e68557427ad9aef6b0ca342a?d=mp&s=160"},"body":"Tom Prince wrote:\n> On Fri, Nov 02, 2007 at 11:03:36AM +0100, Andreas Ericsson wrote:\n>> Steffen Prohaska wrote:\n>>> On Nov 1, 2007, at 10:11 AM, Andreas Ericsson wrote:\n>>>> It's easier to bisect. If git bisect lands you on a merge-commit,\n>>>> you need to start a new bisect for each of the parents included\n>>>> in the merge. Hopefully the nature of the merge gives a clue so\n>>>> the user can make an educated guess as to which parent introduced\n>>>> the bogus commit, but for an \"evil octopus\" (unusual) or if the\n>>>> merge had conflicts which were resolved in a buggy way (not\n>>>> exactly uncommon), it can be quite a hassle to get things right.\n>>>> With a mostly linear history, this problem goes away.\n>>> This is really an interesting point. I did not start to use\n>>> git bisect regularly. But I certainly plan to do so in the future.\n>>> Couldn't bisect learn to better cope with non-linear history?\n>> Perhaps it could, but it's far from trivial. I started hacking on\n>> a wrapper for git-bisect which would do just that, but gave up\n>> rather quickly as the book-keeping required to remember each and\n>> every parent-point tried just got out of hand, and it *still*\n>> wouldn't run in full automatic. It broke down because I also\n>> wanted merges on non-first-line parents to be delved into. If\n>> that didn't happen, I wouldn't *know* the bisect would run fine\n>> without me watching it, so then it was as useless as if I'd have\n>> had to sit there the entire time anyway.\n> \n> I haven't had occasion to use git-bisect much, but I was under the\n> impression that bisect could already handle merges, or any other shaped\n> history just fine.\n> \n\nIt appears the code supports your statement. I started writing on my\nhack-around about a year ago, and the merge-handling code got in with\n1c4fea3a40e836dcee2f16091bf7bfba96c924d0 at Wed Mar 21 22:16:24 2007.\nPerhaps I shouldn't be so paranoid about useless merges anymore then.\nHmm. I shall have to look into it. Perhaps Junio can clarify how it\nworks? The man-page was terribly silent about how git-bisect handles\nmerges.\n\n-- \nAndreas Ericsson                   andreas.ericsson@op5.se\nOP5 AB                             www.op5.se\nTel: +46 8-230225                  Fax: +46 8-230231\n"},{"id":"57986","messageId":"8C8648EB-8434-46FC-A6F6-9DE146ACB373@zib.de","threadId":"10503","inReplyTo":"472B2B8F.1060203@op5.se","subject":"Re: [PATCH 10/10] push: teach push to be quiet if local ref is strict subset of remote ref","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2007-11-02T14:49:37Z","receivedAt":"2007-11-02T14:49:37Z","isPatch":true,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"\nOn Nov 2, 2007, at 2:52 PM, Andreas Ericsson wrote:\n\n>> I haven't had occasion to use git-bisect much, but I was under the\n>> impression that bisect could already handle merges, or any other  \n>> shaped\n>> history just fine.\n>\n> It appears the code supports your statement. I started writing on my\n> hack-around about a year ago, and the merge-handling code got in with\n> 1c4fea3a40e836dcee2f16091bf7bfba96c924d0 at Wed Mar 21 22:16:24 2007.\n> Perhaps I shouldn't be so paranoid about useless merges anymore then.\n> Hmm. I shall have to look into it. Perhaps Junio can clarify how it\n> works? The man-page was terribly silent about how git-bisect handles\n> merges.\n\nSo eventually there's coming something good out of this thread,\nwithout actually writing any code ;)\n\n\tSteffen\n"},{"id":"58025","messageId":"7vfxzo3046.fsf@gitster.siamese.dyndns.org","threadId":"10503","inReplyTo":"472B2B8F.1060203@op5.se","subject":"Re: [PATCH 10/10] push: teach push to be quiet if local ref is strict subset of remote ref","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-11-02T19:42:33Z","receivedAt":"2007-11-02T19:42:33Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Andreas Ericsson <ae@op5.se> writes:\n\n> Tom Prince wrote:\n>>\n>> I haven't had occasion to use git-bisect much, but I was under the\n>> impression that bisect could already handle merges, or any other shaped\n>> history just fine.\n>\n> It appears the code supports your statement. I started writing on my\n> hack-around about a year ago, and the merge-handling code got in with\n> 1c4fea3a40e836dcee2f16091bf7bfba96c924d0 at Wed Mar 21 22:16:24 2007.\n> Perhaps I shouldn't be so paranoid about useless merges anymore then.\n> Hmm. I shall have to look into it. Perhaps Junio can clarify how it\n> works? The man-page was terribly silent about how git-bisect handles\n> merges.\n\nBisecting through merge is not a problem.  Not at all, from the\nvery beginning of the bisect command.\n\n\tSide note.  The commit you quote does not change (let\n\talone fix) the semantics at all.  It is a pure\n\toptimization.  The theory behind how bisect works, see\n\tmy OLS presentation (reachable from the gitwiki).\n\nThe real problem is what to do when the culprit turns out to be\na merge commit.  How to spot what really is wrong, and figure\nout how to fix.  The problem is not for the tool but for the\nhuman, and it is real.\n\nImagine this history.\n\n      ---Z---o---X---...---o---A---C---D\n          \\                       /\n           o---o---Y---...---o---B\n\nSuppose that on the upper development line, the meaning of one\nof the functions existed at Z was changed at commit X.  The\ncommits from Z leading to A change both the function's\nimplementation and all calling sites that existed at Z, as well\nas new calling sites they add, to be consistent.  There is no\nbug at A.\n\nSuppose in the meantime the lower development line somebody\nadded a new calling site for that function at commit Y.  The\ncommits from Z leading to B all assume the old semantics of that\nfunction and the callers and the callee are consistent with each\nother.  There is no bug at B, either.\n\nYou merge to create C.  There is no textual conflict with this\nthree way merge, and the result merges cleanly.  You bisect\nthis, because you found D is bad and you know Z was good.  Your\nbisect will find that C (merge) is broken.  Understandably so,\nas at C, the new calling site of the function added by the lower\nbranch is not converted to the new semantics, while all the\nother calling sites that already existed at Z would have been\nconverted by the merge.  The new calling site has semantic\nadjustment needed, but you do not know that yet.  You need to\nfind out that is the cause of the breakage by looking at the\nmerge commit C and the history leading to it.\n\nHow would you do that?\n\nBoth \"git diff A C\" and \"git diff B C\" would be an enormous patch.\nEach of them essentially shows the whole change on each branch\nsince they diverged.  The developers may have well behaved to\ncreate good commits that follow the \"commit small, commit often,\ncommit well contained units\" mantra, and each individual commit\nleading from Z to A and from Z to B may be easy to review and\nunderstand, but looking at these small and easily reviewable\nsteps alone would not let you spot the breakage.  You need to\nhave a global picture of what the upper branch did (and\namong many, one of them is to change the semantics of that\nparticular function) and look first at the huge \"diff A C\"\n(which shows the change the lower branch introduces), and see if\nthat huge change is consistent with what have been done between\nZ and A.\n\nIf you linearlize the history by rebasing the lower branch on\ntop of upper, instead of merging, the bug becomes much easier to\nfind and understand.  Your history would instead be:\n\n    ---Z---o---X'--...---o---A---o---o---Y'--...---o---B'--D'\n\nand there is a single commit Y' between A and B' that introduced\nthe new calling site that still uses the new semantics of the\nfunction that was already in A.  \"git show Y'\" will be a much\nsmaller patch than \"git diff A C\" and it is much easier to deal\nwith.\n"},{"id":"58033","messageId":"7vhck41jtd.fsf@gitster.siamese.dyndns.org","threadId":"10503","inReplyTo":"7vfxzo3046.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 10/10] push: teach push to be quiet if local ref is strict subset of remote ref","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-11-02T20:19:58Z","receivedAt":"2007-11-02T20:19:58Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> If you linearlize the history by rebasing the lower branch on\n> top of upper, instead of merging, the bug becomes much easier to\n> find and understand.  Your history would instead be:\n>\n>     ---Z---o---X'--...---o---A---o---o---Y'--...---o---B'--D'\n>\n> and there is a single commit Y' between A and B' that introduced\n> the new calling site that still uses the new semantics of the\n> function that was already in A.  \"git show Y'\" will be a much\n> smaller patch than \"git diff A C\" and it is much easier to deal\n> with.\n\nTypo.  Y' uses \"the old semantics of the function, even though\nthat was already modified at X'\".\n"}]}