{"thread":{"id":"39170","subject":"GSoC 2015: 2 accepted proposals","startedAt":"2015-04-27T19:50:23Z","lastAt":"2015-05-06T05:43:20Z","messageCount":13,"participants":["Matthieu Moy","Paul Tan","karthik nayak","Johannes Schindelin","Stephen Robin"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"260080","messageId":"vpqoam9mjuo.fsf@anie.imag.fr","threadId":"39170","inReplyTo":null,"subject":"GSoC 2015: 2 accepted proposals","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@grenoble-inp.fr","sentAt":"2015-04-27T19:50:23Z","receivedAt":"2015-04-27T19:50:23Z","isPatch":false,"sender":{"key":"matthieu.moy@grenoble-inp.fr","avatar":"https://gravatar.com/avatar/72c8a2705971a25dfaff23cece15130d405685845d911aedd5667ace277f3fc5?d=mp&s=160"},"body":"Hi,\n\nThe results just got offical: the Git organization has 2 students\naccepted for the summer of code 2015.\n\nKarthik Nayak will work on \"Unifying git branch -l, git tag -l, and git\nfor-each-ref\" mentored by Christian Couder and yours truly.\n\nPaul Tan will work on \"Make git-pull and git-am builtins\", mentored by \nJohannes Schindelin and Stefan Beller.\n\nRegards,\n\n-- \nMatthieu Moy\nhttp://www-verimag.imag.fr/~moy/\n"},{"id":"260116","messageId":"CACRoPnQ5_r-26J4gBHc27KZt3X9KAU7eFkA3vz_GE6_dP-Uyug@mail.gmail.com","threadId":"39170","inReplyTo":"vpqoam9mjuo.fsf@anie.imag.fr","subject":"Re: GSoC 2015: 2 accepted proposals","fromName":"Paul Tan","fromEmail":"pyokagan@gmail.com","sentAt":"2015-04-28T08:58:26Z","receivedAt":"2015-04-28T08:58:26Z","isPatch":false,"sender":{"key":"pyokagan@gmail.com","avatar":"https://avatars.githubusercontent.com/u/109479?v=4"},"body":"Hi all,\n\nOn Tue, Apr 28, 2015 at 3:50 AM, Matthieu Moy\n<Matthieu.Moy@grenoble-inp.fr> wrote:\n> Hi,\n>\n> The results just got offical: the Git organization has 2 students\n> accepted for the summer of code 2015.\n>\n> Karthik Nayak will work on \"Unifying git branch -l, git tag -l, and git\n> for-each-ref\" mentored by Christian Couder and yours truly.\n>\n> Paul Tan will work on \"Make git-pull and git-am builtins\", mentored by\n> Johannes Schindelin and Stefan Beller.\n\nThanks for accepting me, and it is my pleasure to work with everyone.\nFor reference, information on the proposed project can be found at\n[1].\n\nAs stated in the proposal, I will be starting work on the project\nimmediately. The first step would be to review the test coverage of\ngit-pull and git-am in order to make sure that nothing breaks during\nthe rewriting. I am currently reviewing all related code in order to\nget a better perspective on the issues involved. I am also aware of\nthe recent issues with git-pull[2], which I will look into.\n\nAll patches that I'm working on but are not ready to be published to\nthe mailing list will be cooked in their corresponding branches in my\npersonal git repo[3], which I will push at least once a working day.\nEveryone is welcome to have a look :-).\n\nAgain, thanks all for your support and guidance, and I look forward to\nworking with everyone to make this project a success.\n\nRegards,\nPaul\n\n[1] https://gist.github.com/pyokagan/1b7b0d1f4dab6ba3cef1\n[2] http://thread.gmane.org/gmane.comp.version-control.git/267432\n[3] https://github.com/pyokagan/git\n"},{"id":"260125","messageId":"553F7A50.1080907@gmail.com","threadId":"39170","inReplyTo":"vpqoam9mjuo.fsf@anie.imag.fr","subject":"Re: GSoC 2015: 2 accepted proposals","fromName":"karthik nayak","fromEmail":"karthik.188@gmail.com","sentAt":"2015-04-28T12:17:20Z","receivedAt":"2015-04-28T12:17:20Z","isPatch":false,"sender":{"key":"karthik.188@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1786334?v=4"},"body":"Hello to Everyone,\n\nOn 04/28/2015 01:20 AM, Matthieu Moy wrote:\n> Hi,\n>\n> The results just got offical: the Git organization has 2 students\n> accepted for the summer of code 2015.\n>\n> Karthik Nayak will work on \"Unifying git branch -l, git tag -l, and git\n> for-each-ref\" mentored by Christian Couder and yours truly.\n\nThanks a lot for accepting my proposal and giving me an opportunity to \nwork with Git via GSoC. Can't express how excited I am.\n\nAs Matthieu mentioned I will be working on \"Unifying git branch -l, git \ntag -l, and git for-each-ref\". I plan to start off by going through the \nexisting implementation of each of the above commands and come up with a \ndesign for unification for now. Also to take notes from Jeff King's \nattempt at unification[1].\n\nI will be pushing all my work to my personal Git repository on Github[2].\nWhere anyone can get involved. Will also make sure to notify the mailing \nlist on a regular basis on what is going on with my project.\n\nLooking forward to work with Git and complete this project successfully.\n\nRegards,\nKarthik\n\n>\n> Paul Tan will work on \"Make git-pull and git-am builtins\", mentored by\n> Johannes Schindelin and Stefan Beller.\n\nCongrats Paul, I wish you the very best.\n\n>\n> Regards,\n>\n\n[1] https://github.com/peff/git/tree/jk/for-each-ref-contains-wip\n[2] https://github.com/KarthikNayak/git\n"},{"id":"260174","messageId":"1489cf720b659e1cb41c88cb671930c4@www.dscho.org","threadId":"39170","inReplyTo":"CACRoPnQ5_r-26J4gBHc27KZt3X9KAU7eFkA3vz_GE6_dP-Uyug@mail.gmail.com","subject":"Re: GSoC 2015: 2 accepted proposals","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2015-04-29T15:27:27Z","receivedAt":"2015-04-29T15:27:27Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Paul,\n\nOn 2015-04-28 10:58, Paul Tan wrote:\n\n> As stated in the proposal, I will be starting work on the project\n> immediately. The first step would be to review the test coverage of\n> git-pull and git-am in order to make sure that nothing breaks during\n> the rewriting. I am currently reviewing all related code in order to\n> get a better perspective on the issues involved. I am also aware of\n> the recent issues with git-pull[2], which I will look into.\n> \n> All patches that I'm working on but are not ready to be published to\n> the mailing list will be cooked in their corresponding branches in my\n> personal git repo[3], which I will push at least once a working day.\n> Everyone is welcome to have a look :-).\n> \n> Again, thanks all for your support and guidance, and I look forward to\n> working with everyone to make this project a success.\n\nSounds good! Feel free to ping me on https://gitter.im/git-for-windows/git for a more interactive chat. Email is fine with me, too, though.\n\nCiao,\nJohannes\n"},{"id":"260630","messageId":"1430870453-5408-1-git-send-email-stephen.robin@gmail.com","threadId":"39170","inReplyTo":"CACRoPnQ5_r-26J4gBHc27KZt3X9KAU7eFkA3vz_GE6_dP-Uyug@mail.gmail.com","subject":"[PATCH 0/6] Make pull a builtin","fromName":"Stephen Robin","fromEmail":"stephen.robin@gmail.com","sentAt":"2015-05-06T00:00:47Z","receivedAt":"2015-05-06T00:00:47Z","isPatch":true,"sender":{"key":"stephen.robin@gmail.com","avatar":null},"body":"Hi Paul,\n\nCongratulations on getting your project accepted for GSOC. Here's my\nattempt at implementing pull as a builtin, maybe it will be of some use\nas you look to progress your version.\n\nIt's fairly complete in the sense that all the features of git-pull.sh\nshould be implemented, the test suite passes, and I've been using it\nmyself without issue. At the same time it's some way from finished as\nI've never had time to test it fully and there are parts of the code I'm\nnot happy with.\n\nApologies for not sharing this with you earlier.  I have been too busy\nwith paid work to look at any open source projects for some months.\n\nGood luck with your project!\n\nRegards\nStephen\n\n\nStephen Robin (6):\n  merge: tidy up options\n  merge: move error message given when a merge needs committing to\n    advice.c\n  merge-base: split handle_fork_point to make reuse easier\n  pull: reimplement as a builtin in C\n  pull: allow interactive rebase\n  parse-remote: dismantle git-parse-remote.sh\n\n .gitignore                           |    2 -\n Documentation/config.txt             |    1 +\n Documentation/git-parse-remote.txt   |   23 -\n Documentation/git-pull.txt           |    4 +-\n Makefile                             |    3 +-\n advice.c                             |    9 +\n advice.h                             |    1 +\n builtin.h                            |    3 +\n builtin/merge-base.c                 |   64 ++-\n builtin/merge.c                      |   16 +-\n builtin/pull.c                       | 1006 ++++++++++++++++++++++++++++++++++\n builtin/remote.c                     |    8 +-\n command-list.txt                     |    1 -\n contrib/examples/git-parse-remote.sh |   89 +++\n contrib/examples/git-pull.sh         |  340 ++++++++++++\n git-parse-remote.sh                  |   89 ---\n git-pull.sh                          |  340 ------------\n git-rebase.sh                        |   36 +-\n git-submodule.sh                     |    8 +-\n git.c                                |    1 +\n 20 files changed, 1547 insertions(+), 497 deletions(-)\n delete mode 100644 Documentation/git-parse-remote.txt\n create mode 100644 builtin/pull.c\n create mode 100644 contrib/examples/git-parse-remote.sh\n create mode 100755 contrib/examples/git-pull.sh\n delete mode 100644 git-parse-remote.sh\n delete mode 100755 git-pull.sh\n\n-- \n2.4.0.7.gf20f26f\n"},{"id":"260632","messageId":"1430870453-5408-2-git-send-email-stephen.robin@gmail.com","threadId":"39170","inReplyTo":"1430870453-5408-1-git-send-email-stephen.robin@gmail.com","subject":"[PATCH 1/6] merge: tidy up options","fromName":"Stephen Robin","fromEmail":"stephen.robin@gmail.com","sentAt":"2015-05-06T00:00:48Z","receivedAt":"2015-05-06T00:00:48Z","isPatch":true,"sender":{"key":"stephen.robin@gmail.com","avatar":null},"body":"THIS PATCH SERIES IS NOT CODE-COMPLETE OR FULLY TESTED.\nSee code comments beginning TODO for work remaining.\n\nHide --summary (it is a deprecated synonym for --stat).\nCorrect capitalization of the description of --verify-signatures.\nCorrect indentation of code.\n\nSigned-off-by: Stephen Robin <stephen.robin@gmail.com>\n---\n builtin/merge.c | 10 +++++-----\n 1 file changed, 5 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 3b0f8f9..d6b0579 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -194,10 +194,10 @@ static struct option builtin_merge_options[] = {\n \t\tPARSE_OPT_NOARG, option_parse_n },\n \tOPT_BOOL(0, \"stat\", &show_diffstat,\n \t\tN_(\"show a diffstat at the end of the merge\")),\n-\tOPT_BOOL(0, \"summary\", &show_diffstat, N_(\"(synonym to --stat)\")),\n+\tOPT_HIDDEN_BOOL(0, \"summary\", &show_diffstat, N_(\"(synonym to --stat)\")),\n \t{ OPTION_INTEGER, 0, \"log\", &shortlog_len, N_(\"n\"),\n-\t  N_(\"add (at most <n>) entries from shortlog to merge commit message\"),\n-\t  PARSE_OPT_OPTARG, NULL, DEFAULT_MERGE_LOG_LEN },\n+\t\tN_(\"add (at most <n>) entries from shortlog to merge commit message\"),\n+\t\tPARSE_OPT_OPTARG, NULL, DEFAULT_MERGE_LOG_LEN },\n \tOPT_BOOL(0, \"squash\", &squash,\n \t\tN_(\"create a single commit instead of doing a merge\")),\n \tOPT_BOOL(0, \"commit\", &option_commit,\n@@ -210,7 +210,7 @@ static struct option builtin_merge_options[] = {\n \t\tPARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, FF_ONLY },\n \tOPT_RERERE_AUTOUPDATE(&allow_rerere_auto),\n \tOPT_BOOL(0, \"verify-signatures\", &verify_signatures,\n-\t\tN_(\"Verify that the named commit has a valid GPG signature\")),\n+\t\tN_(\"verify that the named commit has a valid GPG signature\")),\n \tOPT_CALLBACK('s', \"strategy\", &use_strategies, N_(\"strategy\"),\n \t\tN_(\"merge strategy to use\"), option_parse_strategy),\n \tOPT_CALLBACK('X', \"strategy-option\", &xopts, N_(\"option=value\"),\n@@ -223,7 +223,7 @@ static struct option builtin_merge_options[] = {\n \t\tN_(\"abort the current in-progress merge\")),\n \tOPT_SET_INT(0, \"progress\", &show_progress, N_(\"force progress reporting\"), 1),\n \t{ OPTION_STRING, 'S', \"gpg-sign\", &sign_commit, N_(\"key-id\"),\n-\t  N_(\"GPG sign commit\"), PARSE_OPT_OPTARG, NULL, (intptr_t) \"\" },\n+\t\tN_(\"GPG sign commit\"), PARSE_OPT_OPTARG, NULL, (intptr_t) \"\" },\n \tOPT_BOOL(0, \"overwrite-ignore\", &overwrite_ignore, N_(\"update ignored files (default)\")),\n \tOPT_END()\n };\n-- \n2.4.0.7.gf20f26f\n"},{"id":"260631","messageId":"1430870453-5408-3-git-send-email-stephen.robin@gmail.com","threadId":"39170","inReplyTo":"1430870453-5408-1-git-send-email-stephen.robin@gmail.com","subject":"[PATCH 2/6] merge: move error message given when a merge needs committing to advice.c","fromName":"Stephen Robin","fromEmail":"stephen.robin@gmail.com","sentAt":"2015-05-06T00:00:49Z","receivedAt":"2015-05-06T00:00:49Z","isPatch":true,"sender":{"key":"stephen.robin@gmail.com","avatar":null},"body":"THIS PATCH SERIES IS NOT CODE-COMPLETE OR FULLY TESTED.\nSee code comments beginning TODO for work remaining.\n\nThis will allow the message to be re-used in other places.\n\nSigned-off-by: Stephen Robin <stephen.robin@gmail.com>\n---\n advice.c        | 9 +++++++++\n advice.h        | 1 +\n builtin/merge.c | 6 +-----\n 3 files changed, 11 insertions(+), 5 deletions(-)\n\ndiff --git a/advice.c b/advice.c\nindex 575bec2..747792e 100644\n--- a/advice.c\n+++ b/advice.c\n@@ -96,6 +96,15 @@ void NORETURN die_resolve_conflict(const char *me)\n \tdie(\"Exiting because of an unresolved conflict.\");\n }\n \n+void NORETURN die_merge_in_progress()\n+{\n+\tif (advice_resolve_conflict)\n+\t\tdie(_(\"You have not concluded your merge (MERGE_HEAD exists).\\n\"\n+\t\t\"Please, commit your changes before you merge.\"));\n+\telse\n+\t\tdie(_(\"You have not concluded your merge (MERGE_HEAD exists).\"));\n+}\n+\n void detach_advice(const char *new_name)\n {\n \tconst char fmt[] =\ndiff --git a/advice.h b/advice.h\nindex 5ecc6c1..75c261a 100644\n--- a/advice.h\n+++ b/advice.h\n@@ -24,6 +24,7 @@ __attribute__((format (printf, 1, 2)))\n void advise(const char *advice, ...);\n int error_resolve_conflict(const char *me);\n extern void NORETURN die_resolve_conflict(const char *me);\n+extern void NORETURN die_merge_in_progress();\n void detach_advice(const char *new_name);\n \n #endif /* ADVICE_H */\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex d6b0579..45d93bb 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -1134,11 +1134,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t\t * There is no unmerged entry, don't advise 'git\n \t\t * add/rm <file>', just 'git commit'.\n \t\t */\n-\t\tif (advice_resolve_conflict)\n-\t\t\tdie(_(\"You have not concluded your merge (MERGE_HEAD exists).\\n\"\n-\t\t\t\t  \"Please, commit your changes before you merge.\"));\n-\t\telse\n-\t\t\tdie(_(\"You have not concluded your merge (MERGE_HEAD exists).\"));\n+\t\tdie_merge_in_progress();\n \t}\n \tif (file_exists(git_path(\"CHERRY_PICK_HEAD\"))) {\n \t\tif (advice_resolve_conflict)\n-- \n2.4.0.7.gf20f26f\n"},{"id":"260633","messageId":"1430870453-5408-4-git-send-email-stephen.robin@gmail.com","threadId":"39170","inReplyTo":"1430870453-5408-1-git-send-email-stephen.robin@gmail.com","subject":"[PATCH 3/6] merge-base: split handle_fork_point to make reuse easier","fromName":"Stephen Robin","fromEmail":"stephen.robin@gmail.com","sentAt":"2015-05-06T00:00:50Z","receivedAt":"2015-05-06T00:00:50Z","isPatch":true,"sender":{"key":"stephen.robin@gmail.com","avatar":null},"body":"THIS PATCH SERIES IS NOT CODE-COMPLETE OR FULLY TESTED.\nSee code comments beginning TODO for work remaining.\n\nSeparate function handle_fork_point into one part that deals with command\nline arguments, printing error messages and exiting the process, and a\nsecond part that contains only the algorithm.  The later part can be\nre-used elsewhere.\n\nSigned-off-by: Stephen Robin <stephen.robin@gmail.com>\n---\n builtin.h            |  2 ++\n builtin/merge-base.c | 64 ++++++++++++++++++++++++++++++++--------------------\n 2 files changed, 41 insertions(+), 25 deletions(-)\n\ndiff --git a/builtin.h b/builtin.h\nindex b87df70..d8e0e5a 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -27,6 +27,8 @@ extern int fmt_merge_msg(struct strbuf *in, struct strbuf *out,\n \n extern int textconv_object(const char *path, unsigned mode, const unsigned char *sha1, int sha1_valid, char **buf, unsigned long *buf_size);\n \n+extern const unsigned char *get_fork_point(const char *refname, const unsigned char *derived_sha1);\n+\n extern int is_builtin(const char *s);\n \n extern int cmd_add(int argc, const char **argv, const char *prefix);\ndiff --git a/builtin/merge-base.c b/builtin/merge-base.c\nindex 08a8217..7a22cf1 100644\n--- a/builtin/merge-base.c\n+++ b/builtin/merge-base.c\n@@ -145,30 +145,19 @@ static int collect_one_reflog_ent(unsigned char *osha1, unsigned char *nsha1,\n \treturn 0;\n }\n \n-static int handle_fork_point(int argc, const char **argv)\n+const unsigned char *get_fork_point(const char *refname, const unsigned char *derived_sha1)\n {\n-\tunsigned char sha1[20];\n-\tchar *refname;\n-\tconst char *commitname;\n+\t/*\n+\t * TODO I dislike exporting this function via builtin.h. I would prefer to\n+\t * move it to libgit if possible.\n+\t */\n+\tunsigned const char *fork_point_sha1 = null_sha1;\n \tstruct rev_collect revs;\n \tstruct commit *derived;\n \tstruct commit_list *bases;\n-\tint i, ret = 0;\n-\n-\tswitch (dwim_ref(argv[0], strlen(argv[0]), sha1, &refname)) {\n-\tcase 0:\n-\t\tdie(\"No such ref: '%s'\", argv[0]);\n-\tcase 1:\n-\t\tbreak; /* good */\n-\tdefault:\n-\t\tdie(\"Ambiguous refname: '%s'\", argv[0]);\n-\t}\n-\n-\tcommitname = (argc == 2) ? argv[1] : \"HEAD\";\n-\tif (get_sha1(commitname, sha1))\n-\t\tdie(\"Not a valid object name: '%s'\", commitname);\n+\tint i;\n \n-\tderived = lookup_commit_reference(sha1);\n+\tderived = lookup_commit_reference(derived_sha1);\n \tmemset(&revs, 0, sizeof(revs));\n \trevs.initial = 1;\n \tfor_each_reflog_ent(refname, collect_one_reflog_ent, &revs);\n@@ -182,25 +171,50 @@ static int handle_fork_point(int argc, const char **argv)\n \t * There should be one and only one merge base, when we found\n \t * a common ancestor among reflog entries.\n \t */\n-\tif (!bases || bases->next) {\n-\t\tret = 1;\n+\tif (!bases || bases->next)\n \t\tgoto cleanup_return;\n-\t}\n \n \t/* And the found one must be one of the reflog entries */\n \tfor (i = 0; i < revs.nr; i++)\n \t\tif (&bases->item->object == &revs.commit[i]->object)\n \t\t\tbreak; /* found */\n \tif (revs.nr <= i) {\n-\t\tret = 1; /* not found */\n+\t\t/* not found */\n \t\tgoto cleanup_return;\n \t}\n \n-\tprintf(\"%s\\n\", sha1_to_hex(bases->item->object.sha1));\n+\tfork_point_sha1 = bases->item->object.sha1;\n \n cleanup_return:\n \tfree_commit_list(bases);\n-\treturn ret;\n+\treturn fork_point_sha1;\n+}\n+\n+static int handle_fork_point(int argc, const char **argv)\n+{\n+\tunsigned char sha1[20];\n+\tchar *refname;\n+\tconst char *commitname;\n+\tconst unsigned char *fork_point_sha1;\n+\n+\tswitch (dwim_ref(argv[0], strlen(argv[0]), sha1, &refname)) {\n+\tcase 0:\n+\t\tdie(\"No such ref: '%s'\", argv[0]);\n+\tcase 1:\n+\t\tbreak; /* good */\n+\tdefault:\n+\t\tdie(\"Ambiguous refname: '%s'\", argv[0]);\n+\t}\n+\n+\tcommitname = (argc == 2) ? argv[1] : \"HEAD\";\n+\tif (get_sha1(commitname, sha1))\n+\t\tdie(\"Not a valid object name: '%s'\", commitname);\n+\n+\tfork_point_sha1 = get_fork_point(refname, sha1);\n+\tif (!is_null_sha1(fork_point_sha1))\n+\t\tprintf(\"%s\\n\", sha1_to_hex(fork_point_sha1));\n+\n+\treturn is_null_sha1(fork_point_sha1);\n }\n \n int cmd_merge_base(int argc, const char **argv, const char *prefix)\n-- \n2.4.0.7.gf20f26f\n"},{"id":"260636","messageId":"1430870453-5408-5-git-send-email-stephen.robin@gmail.com","threadId":"39170","inReplyTo":"1430870453-5408-1-git-send-email-stephen.robin@gmail.com","subject":"[PATCH 4/6] pull: reimplement as a builtin in C","fromName":"Stephen Robin","fromEmail":"stephen.robin@gmail.com","sentAt":"2015-05-06T00:00:51Z","receivedAt":"2015-05-06T00:00:51Z","isPatch":true,"sender":{"key":"stephen.robin@gmail.com","avatar":null},"body":"THIS PATCH SERIES IS NOT CODE-COMPLETE OR FULLY TESTED.\nSee code comments beginning TODO for work remaining.\n\nKnown differences between builtin/pull.c and git-pull.sh:\n - The output of git pull -h and git pull --help-all has changed.  It is\n   now more comprehensive and consistent with other builtins.\n - The error message given when dying due to unmerged changes in the\n   working tree has changed.  In git-pull.sh it would list all unmerged\n   files.  In builtin/pull.c it is consistent with git merge and will not\n   list file status.\n - --s and --st can no longer be used as a shorthand for --strategy.\n   They would be ambiguous with --stat.\n\nSigned-off-by: Stephen Robin <stephen.robin@gmail.com>\n---\n .gitignore                   |   1 -\n Makefile                     |   2 +-\n builtin.h                    |   1 +\n builtin/pull.c               | 993 +++++++++++++++++++++++++++++++++++++++++++\n contrib/examples/git-pull.sh | 340 +++++++++++++++\n git-pull.sh                  | 340 ---------------\n git.c                        |   1 +\n 7 files changed, 1336 insertions(+), 342 deletions(-)\n create mode 100644 builtin/pull.c\n create mode 100755 contrib/examples/git-pull.sh\n delete mode 100755 git-pull.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex a052419..6287647 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -108,7 +108,6 @@\n /git-patch-id\n /git-prune\n /git-prune-packed\n-/git-pull\n /git-push\n /git-quiltimport\n /git-read-tree\ndiff --git a/Makefile b/Makefile\nindex 5f3987f..8d8fb3a 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -472,7 +472,6 @@ SCRIPT_SH += git-merge-octopus.sh\n SCRIPT_SH += git-merge-one-file.sh\n SCRIPT_SH += git-merge-resolve.sh\n SCRIPT_SH += git-mergetool.sh\n-SCRIPT_SH += git-pull.sh\n SCRIPT_SH += git-quiltimport.sh\n SCRIPT_SH += git-rebase.sh\n SCRIPT_SH += git-remote-testgit.sh\n@@ -874,6 +873,7 @@ BUILTIN_OBJS += builtin/pack-refs.o\n BUILTIN_OBJS += builtin/patch-id.o\n BUILTIN_OBJS += builtin/prune-packed.o\n BUILTIN_OBJS += builtin/prune.o\n+BUILTIN_OBJS += builtin/pull.o\n BUILTIN_OBJS += builtin/push.o\n BUILTIN_OBJS += builtin/read-tree.o\n BUILTIN_OBJS += builtin/receive-pack.o\ndiff --git a/builtin.h b/builtin.h\nindex d8e0e5a..b2d7daa 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -100,6 +100,7 @@ extern int cmd_pack_redundant(int argc, const char **argv, const char *prefix);\n extern int cmd_patch_id(int argc, const char **argv, const char *prefix);\n extern int cmd_prune(int argc, const char **argv, const char *prefix);\n extern int cmd_prune_packed(int argc, const char **argv, const char *prefix);\n+extern int cmd_pull(int argc, const char **argv, const char *prefix);\n extern int cmd_push(int argc, const char **argv, const char *prefix);\n extern int cmd_read_tree(int argc, const char **argv, const char *prefix);\n extern int cmd_receive_pack(int argc, const char **argv, const char *prefix);\ndiff --git a/builtin/pull.c b/builtin/pull.c\nnew file mode 100644\nindex 0000000..f420b4a\n--- /dev/null\n+++ b/builtin/pull.c\n@@ -0,0 +1,993 @@\n+/*\n+ * Copyright (c) 2015 Stephen Robin <stephen.robin@gmail.com>\n+ *\n+ * Based on git-pull.sh by Junio C Hamano\n+ */\n+\n+#include \"builtin.h\"\n+#include \"parse-options.h\"\n+#include \"submodule.h\"\n+#include \"dir.h\"\n+#include \"run-command.h\"\n+#include \"argv-array.h\"\n+#include \"fmt-merge-msg.h\"\n+#include \"refs.h\"\n+#include \"revision.h\"\n+#include \"remote.h\"\n+\n+enum ff_type {\n+\tFF_NOT_SET = -1,\n+\tFF_NO,\n+\tFF_ALLOW,\n+\tFF_ONLY\n+};\n+\n+enum pull_mode {\n+\tPULL_NOT_SET = -1,\n+\tPULL_MERGE,\n+\tPULL_REBASE,\n+\tPULL_PRESERVE_MERGES_REBASE\n+};\n+\n+static const char * const builtin_pull_usage[] = {\n+\tN_(\"git pull [<options>] [<fetch-options>] [<repository> [<refspec>...]]\"),\n+\tNULL\n+};\n+\n+static enum pull_mode pull_mode_from_args = PULL_NOT_SET;\n+static enum pull_mode pull_mode_from_branch_config = PULL_NOT_SET;\n+static enum pull_mode pull_mode_from_config = PULL_NOT_SET;\n+\n+static enum ff_type ff_type_from_args = FF_NOT_SET;\n+static enum ff_type ff_type_from_config = FF_NOT_SET;\n+\n+/*\n+ * These are passed to the underlying fetch / merge / rebase commands but not\n+ * used to make decisions within pull itself.\n+ *  1  command line includes --option\n+ *  0  command line includes --no-option\n+ *  -1 neither is on command line\n+ */\n+static int progress = -1;\n+static int show_diffstat = -1;\n+static int shortlog_len = -1;\n+static int squash = -1;\n+static int option_commit = -1;\n+static int option_edit = -1;\n+static int verify_signatures = -1;\n+\n+static int dryrun;\n+static int verbosity;\n+static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;\n+\n+static const char **use_strategies;\n+static size_t use_strategies_nr, use_strategies_alloc;\n+\n+static const char **xopts;\n+static size_t xopts_nr, xopts_alloc;\n+\n+static const char *option_gpg_sign;\n+\n+static const char *curr_branch, *curr_branch_short;\n+\n+static int parse_pull_mode(const char *name, const char* arg,\n+\tenum pull_mode *option_rebase)\n+{\n+\tint arg_as_bool = git_config_maybe_bool(name, arg);\n+\n+\tif (arg_as_bool == 0) {\n+\t\t*option_rebase = PULL_MERGE;\n+\t\treturn 0;\n+\t}\n+\n+\tif (arg_as_bool == 1) {\n+\t\t*option_rebase = PULL_REBASE;\n+\t\treturn 0;\n+\t}\n+\n+\tif (!strcmp(arg, \"preserve\")) {\n+\t\t*option_rebase = PULL_PRESERVE_MERGES_REBASE;\n+\t\treturn 0;\n+\t}\n+\n+\terror(_(\"Invalid value for %s, should be 'true', 'false' or 'preserve'.\"), name);\n+\treturn -1;\n+}\n+\n+static int parse_ff_type(const char *name, const char* arg,\n+\tenum ff_type *fast_forward)\n+{\n+\tint arg_as_bool = git_config_maybe_bool(name, arg);\n+\n+\tif (arg_as_bool == 0) {\n+\t\t*fast_forward = FF_NO;\n+\t\treturn 0;\n+\t}\n+\n+\tif (arg_as_bool == 1) {\n+\t\t*fast_forward = FF_ALLOW;\n+\t\treturn 0;\n+\t}\n+\n+\tif (!strcmp(arg, \"only\")) {\n+\t\t*fast_forward = FF_ONLY;\n+\t\treturn 0;\n+\t}\n+\n+\terror(_(\"Invalid value for %s, should be 'true', 'false', or 'only'.\"), name);\n+\treturn -1;\n+}\n+\n+static int git_pull_config(const char *key, const char *value, void *cb)\n+{\n+\tif (curr_branch_short &&\n+\t\tstarts_with(key, \"branch.\") &&\n+\t\tstarts_with(key + 7, curr_branch_short) &&\n+\t\t!strcmp(key + 7 + strlen(curr_branch_short), \".rebase\"))\n+\t\treturn parse_pull_mode(key, value, &pull_mode_from_branch_config);\n+\n+\tif (!strcmp(key, \"pull.rebase\"))\n+\t\treturn parse_pull_mode(key, value, &pull_mode_from_config);\n+\n+\tif (!strcmp(key, \"pull.ff\"))\n+\t\treturn parse_ff_type(key, value, &ff_type_from_config);\n+\n+\treturn fmt_merge_msg_config(key, value, cb);\n+}\n+\n+static int option_parse_n(const struct option *opt,\n+\tconst char *arg, int unset)\n+{\n+\tshow_diffstat = unset;\n+\treturn 0;\n+}\n+\n+static int option_parse_recurse_submodules(const struct option *opt,\n+\tconst char *arg, int unset)\n+{\n+\tif (unset)\n+\t\trecurse_submodules = RECURSE_SUBMODULES_OFF;\n+\telse if (arg)\n+\t\trecurse_submodules = parse_fetch_recurse_submodules_arg(opt->long_name, arg);\n+\telse\n+\t\trecurse_submodules = RECURSE_SUBMODULES_ON;\n+\n+\treturn 0;\n+}\n+\n+static int option_parse_rebase(const struct option *opt,\n+\tconst char *arg, int unset)\n+{\n+\tif (unset) {\n+\t\tpull_mode_from_args = PULL_MERGE;\n+\t\treturn 0;\n+\t}\n+\n+\tif (!arg) {\n+\t\tpull_mode_from_args = PULL_REBASE;\n+\t\treturn 0;\n+\t}\n+\n+\tif (!parse_pull_mode(opt->long_name, arg, &pull_mode_from_args))\n+\t\treturn 0;\n+\n+\treturn -1;\n+}\n+\n+static int option_parse_strategy(const struct option *opt,\n+\tconst char *arg, int unset)\n+{\n+\tif (unset)\n+\t\treturn 0;\n+\n+\tALLOC_GROW(use_strategies, use_strategies_nr + 1, use_strategies_alloc);\n+\tuse_strategies[use_strategies_nr++] = xstrdup(arg);\n+\treturn 0;\n+}\n+\n+static int option_parse_x(const struct option *opt,\n+\tconst char *arg, int unset)\n+{\n+\tif (unset)\n+\t\treturn 0;\n+\n+\tALLOC_GROW(xopts, xopts_nr + 1, xopts_alloc);\n+\txopts[xopts_nr++] = xstrdup(arg);\n+\treturn 0;\n+}\n+\n+static struct option builtin_pull_options[] = {\n+\t{ OPTION_CALLBACK, 0, \"rebase\", NULL, N_(\"true|false|preserve\"),\n+\t\tN_(\"incorporate changes by rebasing rather than merging\"),\n+\t\tPARSE_OPT_OPTARG, option_parse_rebase },\n+\tOPT_BOOL(0, \"progress\", &progress,\n+\t\tN_(\"force progress reporting\")),\n+\tOPT__VERBOSITY(&verbosity),\n+\t{ OPTION_CALLBACK, 0, \"recurse-submodules\", NULL, N_(\"on-demand\"),\n+\t\tN_(\"control recursive fetching of submodules\"),\n+\tPARSE_OPT_OPTARG, option_parse_recurse_submodules },\n+\t/* We can't use OPT__DRY_RUN as it uses 'n' as the short form, which we use as the short form of stat. */\n+\tOPT_BOOL(0, \"dry-run\", &dryrun, N_(\"dry run\")),\n+\t{ OPTION_CALLBACK, 'n', NULL, NULL, NULL,\n+\t\tN_(\"do not show a diffstat at the end of the merge\"),\n+\t\tPARSE_OPT_NOARG, option_parse_n },\n+\tOPT_BOOL(0, \"stat\", &show_diffstat,\n+\t\tN_(\"show a diffstat at the end of the merge\")),\n+\tOPT_HIDDEN_BOOL(0, \"summary\", &show_diffstat, N_(\"(synonym to --stat)\")),\n+\t{ OPTION_INTEGER, 0, \"log\", &shortlog_len, N_(\"n\"),\n+\t\tN_(\"add (at most <n>) entries from shortlog to merge commit message\"),\n+\t\tPARSE_OPT_OPTARG, NULL, DEFAULT_MERGE_LOG_LEN },\n+\tOPT_BOOL(0, \"squash\", &squash,\n+\t\tN_(\"create a single commit instead of doing a merge\")),\n+\tOPT_BOOL(0, \"commit\", &option_commit,\n+\t\tN_(\"perform a commit if the merge succeeds (default)\")),\n+\tOPT_BOOL('e', \"edit\", &option_edit,\n+\t\tN_(\"edit message before committing\")),\n+\tOPT_SET_INT(0, \"ff\", &ff_type_from_args,\n+\t\tN_(\"allow fast-forward (default)\"), FF_ALLOW),\n+\t{ OPTION_SET_INT, 0, \"ff-only\", &ff_type_from_args, NULL,\n+\t\tN_(\"abort if fast-forward is not possible\"),\n+\t\tPARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, FF_ONLY },\n+\tOPT_BOOL(0, \"verify-signatures\", &verify_signatures,\n+\t\tN_(\"verify that the named commit has a valid GPG signature\")),\n+\tOPT_CALLBACK('s', \"strategy\", &use_strategies, N_(\"strategy\"),\n+\t\tN_(\"merge strategy to use\"), option_parse_strategy),\n+\tOPT_CALLBACK('X', \"strategy-option\", &xopts, N_(\"option=value\"),\n+\t\tN_(\"option for selected merge strategy\"), option_parse_x),\n+\t{ OPTION_STRING, 'S', \"gpg-sign\", &option_gpg_sign, N_(\"key-id\"),\n+\t\tN_(\"GPG sign commit\"), PARSE_OPT_OPTARG, NULL, (intptr_t) \"\" },\n+\tOPT_END()\n+};\n+\n+static enum pull_mode get_pull_mode()\n+{\n+\t/* use --[no-]rebase[=preserve] from the command line, if specified. */\n+\tif (pull_mode_from_args != PULL_NOT_SET)\n+\t\treturn pull_mode_from_args;\n+\n+\t/* otherwise use branch.<name>.rebase from config, if set. */\n+\tif (pull_mode_from_branch_config != PULL_NOT_SET)\n+\t\treturn pull_mode_from_branch_config;\n+\n+\t/* otherwise use pull.rebase from config, if set. */\n+\tif (pull_mode_from_config != PULL_NOT_SET)\n+\t\treturn pull_mode_from_config;\n+\n+\t/* use merge by default. */\n+\treturn PULL_MERGE;\n+}\n+\n+static enum ff_type get_ff_type()\n+{\n+\tif (ff_type_from_args != FF_NOT_SET)\n+\t\treturn ff_type_from_args;\n+\n+\tif (ff_type_from_config != FF_NOT_SET)\n+\t\treturn ff_type_from_config;\n+\n+\treturn FF_ALLOW;\n+}\n+\n+static char *get_merge_msg()\n+{\n+\tconst char *inpath = NULL;\n+\tFILE *in;\n+\tstruct strbuf input = STRBUF_INIT, output = STRBUF_INIT;\n+\tstruct fmt_merge_msg_opts opts;\n+\n+\tinpath = git_path(\"FETCH_HEAD\");\n+\tin = fopen(inpath, \"r\");\n+\tif (!in)\n+\t\tdie_errno(\"cannot open '%s'\", inpath);\n+\n+\tif (strbuf_read(&input, fileno(in), 0) < 0)\n+\t\tdie_errno(\"could not read '%s'\", inpath);\n+\n+\tfclose(in);\n+\n+\tmemset(&opts, 0, sizeof(opts));\n+\topts.add_title = 1;\n+\topts.credit_people = 1;\n+\topts.shortlog_len = shortlog_len;\n+\n+\tfmt_merge_msg(&input, &output, &opts);\n+\n+\tstrbuf_release(&input);\n+\n+\treturn strbuf_detach(&output, NULL);\n+}\n+\n+static const struct string_list get_merge_head()\n+{\n+\t/*\n+\t * Read FETCH_HEAD line by line\n+\t * ... exclude lines containing \\tnot-for-merge\\t\n+\t * ... exclude everything after the first tab in remaining lines\n+\t * ... result is a list of sha1s to be merged.\n+\t */\n+\n+\tconst char *filename;\n+\tFILE *fp;\n+\tstruct strbuf line = STRBUF_INIT;\n+\tstruct string_list merge_head = STRING_LIST_INIT_DUP;\n+\tchar *ptr;\n+\n+\tfilename = git_path(\"FETCH_HEAD\");\n+\tfp = fopen(filename, \"r\");\n+\tif (!fp)\n+\t\tdie_errno(_(\"could not open '%s' for reading\"), filename);\n+\n+\twhile (strbuf_getline(&line, fp, '\\n') != EOF) {\n+\n+\t\tptr = strstr(line.buf, \"\\tnot-for-merge\\t\");\n+\t\tif (!ptr) {\n+\t\t\tptr = strchr(line.buf, '\\t');\n+\t\t\tif (ptr) {\n+\t\t\t\tstrbuf_setlen(&line, ptr - line.buf);\n+\t\t\t\tstring_list_append(&merge_head, line.buf);\n+\t\t\t}\n+\t\t}\n+\n+\t\tstrbuf_reset(&line);\n+\t}\n+\n+\tfclose(fp);\n+\tstrbuf_release(&line);\n+\n+\treturn merge_head;\n+}\n+\n+static int run_fetch(const int additional_argc, const char **additional_argv)\n+{\n+\tint v, q, idx, result;\n+\tstruct argv_array argv = ARGV_ARRAY_INIT;\n+\n+\targv_array_push(&argv, \"fetch\");\n+\n+\tfor (v = verbosity; v > 0; v--)\n+\t\targv_array_push(&argv, \"-v\");\n+\n+\tfor (q = verbosity; q < 0; q++)\n+\t\targv_array_push(&argv, \"-q\");\n+\n+\tif (progress == 1)\n+\t\targv_array_push(&argv, \"--progress\");\n+\telse if (progress == 0)\n+\t\targv_array_push(&argv, \"--no-progress\");\n+\n+\tif (dryrun)\n+\t\targv_array_push(&argv, \"--dry-run\");\n+\n+\tif (recurse_submodules == RECURSE_SUBMODULES_ON)\n+\t\targv_array_push(&argv, \"--recurse-submodules\");\n+\telse if (recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND)\n+\t\targv_array_push(&argv, \"--recurse-submodules=on-demand\");\n+\telse if (recurse_submodules == RECURSE_SUBMODULES_OFF)\n+\t\targv_array_push(&argv, \"--no-recurse-submodules\");\n+\n+\targv_array_push(&argv, \"--update-head-ok\");\n+\n+\tfor (idx = 0; idx < additional_argc; idx++)\n+\t\targv_array_push(&argv, additional_argv[idx]);\n+\n+\tresult = run_command_v_opt(argv.argv, RUN_GIT_CMD);\n+\n+\targv_array_clear(&argv);\n+\n+\treturn result;\n+}\n+\n+static int run_merge(const struct string_list merge_head)\n+{\n+\tint v, q, idx, result;\n+\tstruct argv_array argv = ARGV_ARRAY_INIT;\n+\tconst char *merge_msg;\n+\tenum ff_type fast_forward_type;\n+\n+\tmerge_msg = get_merge_msg();\n+\tfast_forward_type = get_ff_type();\n+\n+\n+\targv_array_push(&argv, \"merge\");\n+\n+\tif (show_diffstat == 1)\n+\t\targv_array_push(&argv, \"--stat\");\n+\telse if (show_diffstat == 0)\n+\t\targv_array_push(&argv, \"--no-stat\");\n+\n+\tif (option_commit == 1)\n+\t\targv_array_push(&argv, \"--commit\");\n+\telse if (option_commit == 0)\n+\t\targv_array_push(&argv, \"--no-commit\");\n+\n+\tif (verify_signatures == 1)\n+\t\targv_array_push(&argv, \"--verify-signatures\");\n+\telse if (verify_signatures == 0)\n+\t\targv_array_push(&argv, \"--no-verify-signatures\");\n+\n+\tif (option_edit == 1)\n+\t\targv_array_push(&argv, \"--edit\");\n+\telse if (option_edit == 0)\n+\t\targv_array_push(&argv, \"--no-edit\");\n+\n+\tif (squash == 1)\n+\t\targv_array_push(&argv, \"--squash\");\n+\telse if (squash == 0)\n+\t\targv_array_push(&argv, \"--no-squash\");\n+\n+\tif (fast_forward_type == FF_ALLOW)\n+\t\targv_array_push(&argv, \"--ff\");\n+\telse if (fast_forward_type == FF_NO)\n+\t\targv_array_push(&argv, \"--no-ff\");\n+\telse if (fast_forward_type == FF_ONLY)\n+\t\targv_array_push(&argv, \"--ff-only\");\n+\n+\tif (shortlog_len >= 0)\n+\t\targv_array_pushf(&argv, \"--log=%d\", shortlog_len);\n+\n+\tfor (idx = 0; idx < use_strategies_nr; idx++)\n+\t\targv_array_pushf(&argv, \"--strategy=%s\", use_strategies[idx]);\n+\n+\tfor (idx = 0; idx < xopts_nr; idx++)\n+\t\targv_array_pushf(&argv, \"-X%s\", xopts[idx]);\n+\n+\tfor (v = verbosity; v > 0; v--)\n+\t\targv_array_push(&argv, \"-v\");\n+\n+\tfor (q = verbosity; q < 0; q++)\n+\t\targv_array_push(&argv, \"-q\");\n+\n+\tif (progress == 1)\n+\t\targv_array_push(&argv, \"--progress\");\n+\telse if (progress == 0)\n+\t\targv_array_push(&argv, \"--no-progress\");\n+\n+\tif (option_gpg_sign)\n+\t\targv_array_pushf(&argv, \"-S%s\", option_gpg_sign);\n+\n+\targv_array_pushf(&argv, \"\\\"%s\\\"\", merge_msg);\n+\n+\targv_array_push(&argv, \"HEAD\");\n+\n+\tfor (idx = 0; idx < merge_head.nr; idx++)\n+\t\targv_array_push(&argv, merge_head.items[idx].string);\n+\n+\tresult = run_command_v_opt(argv.argv, RUN_GIT_CMD);\n+\n+\targv_array_clear(&argv);\n+\n+\treturn result;\n+}\n+\n+static const char *run_show_branch(const char *merge_head,\n+\tconst char *fork_point_for_rebase)\n+{\n+\t/*\n+\t * TODO Should be able to do the same thing without needing to fork another\n+\t * git instance. It's just a simple search of the graph after all.\n+\t */\n+\n+\tint len;\n+\tstruct child_process cp;\n+\tstruct strbuf buffer = STRBUF_INIT;\n+\tstruct argv_array argv = ARGV_ARRAY_INIT;\n+\n+\targv_array_push(&argv, \"show-branch\");\n+\targv_array_push(&argv, \"--merge-base\");\n+\n+\targv_array_push(&argv, curr_branch);\n+\targv_array_push(&argv, merge_head);\n+\targv_array_push(&argv, fork_point_for_rebase);\n+\n+\tmemset(&cp, 0, sizeof(cp));\n+\tcp.argv = argv.argv;\n+\tcp.out = -1;\n+\tcp.git_cmd = 1;\n+\n+\tif (start_command(&cp))\n+\t\tdie(_(\"could not run git show-branch.\"));\n+\tlen = strbuf_read(&buffer, cp.out, 1024);\n+\tclose(cp.out);\n+\n+\tif (finish_command(&cp) || len < 0)\n+\t\tdie(_(\"show-branch failed\"));\n+\telse if (!len)\n+\t\treturn NULL;\n+\n+\treturn strbuf_detach(&buffer, NULL);\n+}\n+\n+static int run_rebase(const struct string_list merge_head, const char *fork_point,\n+\tconst enum pull_mode pull_mode)\n+{\n+\tint v, q, idx, result;\n+\tstruct argv_array argv = ARGV_ARRAY_INIT;\n+\n+\tif (merge_head.nr > 1)\n+\t\tdie(_(\"Cannot rebase onto multiple branches\"));\n+\n+\tif (fork_point) {\n+\t\tconst char *show_branch_result = run_show_branch(merge_head.items[0].string, fork_point);\n+\t\tif (!strcmp(fork_point, show_branch_result))\n+\t\t\tfork_point = NULL;\n+\t}\n+\n+\targv_array_push(&argv, \"rebase\");\n+\n+\tif (show_diffstat == 1)\n+\t\targv_array_push(&argv, \"--stat\");\n+\telse if (show_diffstat == 0)\n+\t\targv_array_push(&argv, \"--no-stat\");\n+\n+\tfor (idx = 0; idx < use_strategies_nr; idx++)\n+\t\targv_array_pushf(&argv, \"--strategy=%s\", use_strategies[idx]);\n+\n+\tfor (idx = 0; idx < xopts_nr; idx++)\n+\t\targv_array_pushf(&argv, \"-X%s\", xopts[idx]);\n+\n+\tif (pull_mode == PULL_PRESERVE_MERGES_REBASE)\n+\t\targv_array_push(&argv, \"--preserve-merges\");\n+\n+\tfor (v = verbosity; v > 0; v--)\n+\t\targv_array_push(&argv, \"-v\");\n+\n+\tfor (q = verbosity; q < 0; q++)\n+\t\targv_array_push(&argv, \"-q\");\n+\n+\tif (option_gpg_sign)\n+\t\targv_array_pushf(&argv, \"-S%s\", option_gpg_sign);\n+\n+\targv_array_push(&argv, \"--onto\");\n+\targv_array_push(&argv, merge_head.items[0].string);\n+\n+\tif (fork_point)\n+\t\targv_array_push(&argv, fork_point);\n+\telse\n+\t\targv_array_push(&argv, merge_head.items[0].string);\n+\n+\tresult = run_command_v_opt(argv.argv, RUN_GIT_CMD);\n+\n+\targv_array_clear(&argv);\n+\n+\treturn result;\n+}\n+\n+static int get_remote_name(struct remote *remote, void *priv)\n+{\n+\tstruct string_list *list = priv;\n+\tstring_list_append(list, remote->name);\n+\treturn 0;\n+}\n+\n+static void error_on_no_merge_candidates(enum pull_mode mode,\n+\tint argc, const char **argv)\n+{\n+\tconst char *op_type, *op_prep;\n+\tint idx;\n+\tstruct branch *branch;\n+\n+\t/*\n+\t * TODO Existing bug in git-pull.sh, add another patch to the series to fix:\n+\t * This function fails to take into account any arguments to be passed to\n+\t * git fetch other than the remote and the refs.\n+\t *\n+\t * Set up a pair of test repos as follows:\n+\t *   mkdir repo\n+\t *   cd repo\n+\t *   git init\n+\t *   echo test > test\n+\t *   git add test\n+\t *   git commit -m \"a commit\"\n+\t *   cd ..\n+\t *   git clone repo cloned\n+\t *   cd cloned\n+\t *   git remote add nondefaultremote \"../repo\"\n+\t *\n+\t * Now compare the output of:\n+\t *   git pull nondefaultremote\n+\t *   git pull -p nondefaultremote\n+\t *\n+\t * The messages should be identical but aren't, the second is incorrect.\n+\t */\n+\n+\tfor (idx = 0; idx < argc; idx++) {\n+\t\tif (!strcmp(\"-t\", argv[idx]) || starts_with(argv[idx], \"--t\"))\n+\t\t\tdie(_(\"It doesn't make sense to pull all tags; you probably meant:\\n\"\n+\t\t\t\"git fetch --tags\"));\n+\t}\n+\n+\tbranch = branch_get(curr_branch_short);\n+\n+\tif (mode == PULL_MERGE) {\n+\t\top_type = \"merge\";\n+\t\t/*\n+\t\t * TRANSLATORS: This is the preposition associated with the merge\n+\t\t * operation. In English it is used as \"specify the branch you want to\n+\t\t * merge _with_\"\n+\t\t */\n+\t\top_prep = _(\"with\");\n+\t} else {\n+\t\top_type = \"rebase\";\n+\t\t/*\n+\t\t* TRANSLATORS: This is the preposition associated with the rebase\n+\t\t* operation. In English it is used as \"specify the branch you want to\n+\t\t* rebase _against_\"\n+\t\t*/\n+\t\top_prep = _(\"against\");\n+\t}\n+\n+\tif (argc > 1) {\n+\t\tif (mode == PULL_MERGE)\n+\t\t\tdie(_(\"There are no candidates for merging\\n\"\n+\t\t\t\"among the refs that you just fetched.\\n\"\n+\t\t\t\"Generally this means that you provided a wildcard refspec which had no\\n\"\n+\t\t\t\"matches on the remote end.\"));\n+\t\telse\n+\t\t\tdie(_(\"There is no candidate for rebasing against\\n\"\n+\t\t\t\"among the refs that you just fetched.\\n\"\n+\t\t\t\"Generally this means that you provided a wildcard refspec which had no\\n\"\n+\t\t\t\"matches on the remote end.\\n\"));\n+\t} else if (argc > 0 && branch && branch->remote_name &&\n+\t\tstrcmp(argv[0], branch->remote_name)) {\n+\t\tdie(_(\"You asked to pull from the remote '%s', but did not specify\\n\"\n+\t\t\t\"a branch. Because this is not the default configured remote\\n\"\n+\t\t\t\"for your current branch, you must specify a branch on the command line.\"), argv[0]);\n+\t} else if (!curr_branch_short) {\n+\t\t/*\n+\t\t * TRANSLATORS: first parameter is the operation (merge or rebase),\n+\t\t * second is the preposition (with or against in English).\n+\t\t */\n+\t\tdie(_(\"You are not currently on a branch. Please specify which\\n\"\n+\t\t\t\"branch you want to %s %s. See git help pull for details.\\n\\n\"\n+\t\t\t\"  git pull <remote> <branch>\"), op_type, op_prep);\n+\t} else if (!branch || !branch->merge || !branch->merge[0] ||\n+\t\t!branch->merge[0]->dst || !branch->remote_name) {\n+\t\t/* If there's only one remote, use that in the suggestion */\n+\t\tstruct string_list list = STRING_LIST_INIT_NODUP;\n+\t\tchar *remote_name;\n+\n+\t\tfor_each_remote(get_remote_name, &list);\n+\n+\t\tif (list.nr == 1)\n+\t\t\tremote_name = list.items[0].string;\n+\t\telse\n+\t\t\tremote_name = \"<remote>\";\n+\t\t/*\n+\t\t* TRANSLATORS: first parameter is the operation (merge or rebase),\n+\t\t* second is the preposition (with or against in English).\n+\t\t*/\n+\t\tdie(_(\"There is no tracking information for the current branch.\\n\"\n+\t\t\t\"Please specify which branch you want to %s %s.\\n\"\n+\t\t\t\"See git help pull for details\\n\\n\"\n+\t\t\t\"  git pull <remote> <branch>\\n\\n\"\n+\t\t\t\"If you wish to set tracking information for this branch you can do so with:\\n\\n\"\n+\t\t\t\"  git branch --set-upstream-to=%s/<branch> %s\"),\n+\t\t\top_type, op_prep, remote_name, curr_branch_short);\n+\t} else {\n+\t\tconst char *upstream_short = strncmp(branch->merge[0]->dst, \"refs/heads/\", 11)\n+\t\t\t? branch->merge[0]->dst : branch->merge[0]->dst + 11;\n+\t\t/*\n+\t\t* TRANSLATORS: first parameter is the operation (merge or rebase),\n+\t\t* second is the preposition (with or against in English).\n+\t\t*/\n+\t\tdie(_(\"Your configuration specifies to %s %s the ref '%s'\\n\"\n+\t\t\t\"from the remote, but no such ref was fetched.\"),\n+\t\t\top_type, op_prep, upstream_short);\n+\t}\n+}\n+\n+static const char *get_remote_merge_branch(int argc, const char **argv)\n+{\n+\t/*\n+\t * TODO Existing bug in git-pull.sh, add another patch to the series to fix:\n+\t * This function fails to take into account any arguments to be passed to git\n+\t * fetch other than the remote and the refs.\n+\t *\n+\t * See also error_on_no_merge_candidates, it has the same problem.\n+\t */\n+\n+\t/*\n+\t * TODO Existing bug in git-pull.sh, add another patch to the series to fix:\n+\t * This function doesn't always take into account mapping of remote to local\n+\t * branch names.\n+\t */\n+\n+\tif (argc <= 1) {\n+\t\tstruct remote *my_remote;\n+\t\tstruct branch *branch;\n+\n+\t\tmy_remote = (argc == 1) ? remote_get(argv[0]) : remote_get(NULL);\n+\t\tif (!my_remote || !my_remote->name)\n+\t\t\treturn NULL;\n+\n+\t\tbranch = branch_get(curr_branch_short);\n+\t\tif (!branch || !branch->merge || !branch->merge[0] ||\n+\t\t\t!branch->merge[0]->dst || !branch->remote_name)\n+\t\t\treturn NULL;\n+\n+\t\tif (strcmp(branch->remote_name, my_remote->name))\n+\t\t\treturn NULL;\n+\n+\t\treturn branch->merge[0]->dst;\n+\n+\t} else {\n+\t\t/*\n+\t\t * TODO Code here is ugly but should do the same thing as\n+\t\t * git-parse-remote.sh. I haven't fully tested it as I want to rewrite\n+\t\t * the whole function in a subsequent patch anyway.\n+\t\t */\n+\n+\t\tstatic const char **refs_to_parse = NULL;\n+\t\tint refs_to_parse_nr = argc - 1;\n+\t\tint i;\n+\t\tstruct refspec *parsed_refspec;\n+\t\tchar *remote_ref;\n+\n+\t\trefs_to_parse = xcalloc(argc, sizeof(const char *));\n+\t\tfor (i = 0; i < refs_to_parse_nr; i++)\n+\t\t\trefs_to_parse[i] = argv[i + 1];\n+\t\trefs_to_parse[i] = NULL;\n+\n+\t\tparsed_refspec = parse_fetch_refspec(refs_to_parse_nr, refs_to_parse);\n+\n+\t\tremote_ref = parsed_refspec->src;\n+\n+\t\tif (!remote_ref)\n+\t\t\tremote_ref = \"HEAD\";\n+\t\telse if (starts_with(remote_ref, \"heads/\"))\n+\t\t\tremote_ref += strlen(\"heads/\");\n+\t\telse if (starts_with(remote_ref, \"refs/heads/\"))\n+\t\t\tremote_ref += strlen(\"refs/heads/\");\n+\t\telse if (starts_with(remote_ref, \"refs/\"))\n+\t\t\tremote_ref = NULL;\n+\t\telse if (starts_with(remote_ref, \"tags/\"))\n+\t\t\tremote_ref = NULL;\n+\t\telse if (starts_with(remote_ref, \"remotes/\"))\n+\t\t\tremote_ref = NULL;\n+\n+\t\tif (!remote_ref)\n+\t\t\treturn NULL;\n+\n+\t\tif (!strcmp(argv[0], \".\")) {\n+\t\t\tchar *full_ref = xmalloc(strlen(remote_ref) + 12);\n+\t\t\tstrcpy(full_ref, \"refs/heads/\");\n+\t\t\tstrcat(full_ref, remote_ref);\n+\t\t\treturn full_ref;\n+\t\t} else {\n+\t\t\tchar *full_ref = xmalloc(strlen(remote_ref) +strlen(argv[0]) + 15);\n+\t\t\tstrcpy(full_ref, \"refs/remotes/\");\n+\t\t\tstrcat(full_ref, argv[0]);\n+\t\t\tstrcat(full_ref, \"/\");\n+\t\t\tstrcat(full_ref, remote_ref);\n+\t\t\treturn full_ref;\n+\t\t}\n+\n+\t}\n+}\n+\n+static char *find_fork_point_for_rebase(int argc, const char** argv, unsigned char sha1_orig_head[20])\n+{\n+\tconst char *remote_ref;\n+\tconst unsigned char *fork_point_sha1;\n+\n+\tremote_ref = get_remote_merge_branch(argc, argv);\n+\tif (!remote_ref)\n+\t\treturn NULL;\n+\n+\tfork_point_sha1 = get_fork_point(remote_ref, sha1_orig_head);\n+\tif (is_null_sha1(fork_point_sha1))\n+\t\treturn NULL;\n+\n+\treturn sha1_to_hex(fork_point_sha1);\n+}\n+\n+static int fast_forward_unborn_branch(const struct string_list merge_head)\n+{\n+\t/*\n+\t* Pulling into an unborn branch.\n+\t* We claim the index is based on an empty tree and try to fast-forward\n+\t* to merge-head. This ensures we will not lose index / worktree\n+\t* changes that the user already made on the unborn branch.\n+\t*/\n+\tunsigned char sha1[20];\n+\n+\tif (merge_head.nr > 1)\n+\t\tdie(_(\"Cannot merge multiple branches into empty head\"));\n+\n+\tif (get_sha1_hex(merge_head.items[0].string, sha1))\n+\t\tdie(_(\"Unable to find '%s'. FETCH_HEAD may be corrupt\"), merge_head.items[0].string);\n+\n+\tif (checkout_fast_forward(EMPTY_TREE_SHA1_BIN, sha1, 0))\n+\t\treturn 1;\n+\n+\tif (update_ref(\"initial pull\", \"HEAD\", sha1, NULL, 0, UPDATE_REFS_DIE_ON_ERR))\n+\t\treturn 1;\n+\n+\treturn 0;\n+}\n+\n+static int check_for_unstaged_changes()\n+{\n+\tstruct rev_info rev;\n+\tint result;\n+\n+\t/* Check for changes in the working tree */\n+\tinit_revisions(&rev, NULL);\n+\tsetup_revisions(0, NULL, &rev, NULL);\n+\tDIFF_OPT_SET(&rev.diffopt, IGNORE_SUBMODULES);\n+\tDIFF_OPT_SET(&rev.diffopt, QUICK);\n+\tDIFF_OPT_SET(&rev.diffopt, HAS_CHANGES);\n+\tDIFF_OPT_SET(&rev.diffopt, EXIT_WITH_STATUS);\n+\tresult = run_diff_files(&rev, 0);\n+\n+\treturn diff_result_code(&rev.diffopt, result);\n+}\n+\n+static int check_for_uncommitted_changes()\n+{\n+\tstruct rev_info rev;\n+\tstruct setup_revision_opt opt;\n+\tint result;\n+\n+\t/* Check for changes in the index */\n+\tinit_revisions(&rev, NULL);\n+\tmemset(&opt, 0, sizeof(opt));\n+\topt.def = \"HEAD\";\n+\tsetup_revisions(0, NULL, &rev, &opt);\n+\tDIFF_OPT_SET(&rev.diffopt, IGNORE_SUBMODULES);\n+\tDIFF_OPT_SET(&rev.diffopt, QUICK);\n+\tDIFF_OPT_SET(&rev.diffopt, HAS_CHANGES);\n+\tDIFF_OPT_SET(&rev.diffopt, EXIT_WITH_STATUS);\n+\tresult = run_diff_index(&rev, 1);\n+\n+\treturn diff_result_code(&rev.diffopt, result);\n+}\n+\n+static void check_state_before_starting(const enum pull_mode mode, const int unborn)\n+{\n+\t/*\n+\t * TODO This function is as close to git-pull.sh as possible. We should be\n+\t * able to tidy it up and improve it now it's in c (e.g. fail early if\n+\t * cherry-pick in progress), perhaps using wt_status stuff.\n+\t */\n+\n+\tif (read_cache_unmerged())\n+\t\tdie_resolve_conflict(\"pull\");\n+\n+\tif (file_exists(git_path(\"MERGE_HEAD\")))\n+\t\tdie_merge_in_progress();\n+\n+\tif (mode != PULL_MERGE) {\n+\n+\t\t/*\n+\t\t * TODO Existing bug in git-pull.sh, add another patch to the series to fix:\n+\t\t * We'll die unnecessarily on the next line if files are added to the\n+\t\t * index then removed again, leaving the index empty, e.g.\n+\t\t *\n+\t\t *    mkdir temp\n+\t\t *    cd temp\n+\t\t *    git init\n+\t\t *    echo test > test\n+\t\t *    git add test\n+\t\t *    git reset test\n+\t\t *    rm test\n+\t\t *    git pull --rebase ../another-repo\n+\t\t * => \"updating an unborn branch with changes added to the index\"\n+\t\t */\n+\t\tif (unborn && file_exists(get_index_file()))\n+\t\t\tdie(_(\"Updating an unborn branch with changes added to the index\"));\n+\n+\t\tif (!unborn) {\n+\t\t\tint unstaged_changes = 0;\n+\t\t\tint uncommited_changes = 0;\n+\n+\t\t\tif (read_cache_preload(NULL) < 0)\n+\t\t\t\tdie(_(\"Corrupt index file\"));\n+\n+\t\t\trefresh_cache(REFRESH_QUIET | REFRESH_IGNORE_SUBMODULES);\n+\n+\t\t\tunstaged_changes = check_for_unstaged_changes();\n+\t\t\tuncommited_changes = check_for_uncommitted_changes();\n+\n+\t\t\tif (unstaged_changes && uncommited_changes)\n+\t\t\t\tdie(_(\"Cannot pull with rebase: You have unstaged changes and your index contains uncommitted changes./n\"\n+\t\t\t\t\t\"Please commit or stash them.\"));\n+\n+\t\t\tif (unstaged_changes)\n+\t\t\t\tdie(_(\"Cannot pull with rebase: You have unstaged changes./n\"\n+\t\t\t\t\t\"Please commit or stash them.\"));\n+\n+\t\t\tif (uncommited_changes)\n+\t\t\t\tdie(_(\"Cannot pull with rebase: Your index contains uncommitted changes./n\"\n+\t\t\t\t\t\"Please commit or stash them.\"));\n+\t\t}\n+\t}\n+}\n+\n+static void set_reflog_message(int argc, const char **argv)\n+{\n+\tint idx;\n+\tstruct strbuf reflog_message = STRBUF_INIT;\n+\n+\tfor (idx = 0; idx < argc; idx++) {\n+\t\tstrbuf_addstr(&reflog_message, argv[idx]);\n+\t\tstrbuf_addch(&reflog_message, ' ');\n+\t}\n+\n+\tstrbuf_trim(&reflog_message);\n+\n+\tsetenv(\"GIT_REFLOG_ACTION\", reflog_message.buf, 0);\n+\n+\tstrbuf_release(&reflog_message);\n+}\n+\n+int cmd_pull(int argc, const char **argv, const char *prefix)\n+{\n+\tunsigned char sha1_orig_head[20], sha1_curr_head[20];\n+\tenum pull_mode mode = PULL_NOT_SET;\n+\tchar *fork_point_for_rebase = NULL;\n+\n+\tset_reflog_message(argc, argv);\n+\n+\tcurr_branch = resolve_refdup(\"HEAD\", 0, sha1_orig_head, NULL);\n+\tif (curr_branch && starts_with(curr_branch, \"refs/heads/\"))\n+\t\tcurr_branch_short = curr_branch + 11;\n+\n+\tgit_config(git_pull_config, NULL);\n+\n+\targc = parse_options(argc, argv, prefix, builtin_pull_options,\n+\t\tbuiltin_pull_usage, PARSE_OPT_KEEP_UNKNOWN);\n+\n+\tmode = get_pull_mode();\n+\n+\tif (shortlog_len < 0)\n+\t\tshortlog_len = (merge_log_config > 0) ? merge_log_config : 0;\n+\n+\tcheck_state_before_starting(mode, is_null_sha1(sha1_orig_head));\n+\n+\tif (mode != PULL_MERGE && !is_null_sha1(sha1_orig_head))\n+\t\tfork_point_for_rebase = find_fork_point_for_rebase(argc, argv, sha1_orig_head);\n+\n+\tif (run_fetch(argc, argv))\n+\t\treturn 1;\n+\n+\tif (dryrun)\n+\t\treturn 0;\n+\n+\tget_sha1(\"HEAD\", sha1_curr_head);\n+\n+\tif (!is_null_sha1(sha1_orig_head) &&\n+\t\thashcmp(sha1_orig_head, sha1_curr_head)) {\n+\t\t/*\n+\t\t * The fetch involved updating the current branch.\n+\t\t * The working tree and the index file are still based on the\n+\t\t * orig_head commit, but we are merging into curr_head.\n+\t\t * First update the working tree to match curr_head.\n+\t\t */\n+\n+\t\t/* TRANSLATORS: %s is a SHA1 identifying a commit. */\n+\t\twarning(_(\"fetch updated the current branch head.\\n\"\n+\t\t\t\"fast-forwarding your working tree from\\n\"\n+\t\t\t\"commit %s.\"), sha1_to_hex(sha1_orig_head));\n+\n+\t\tif (checkout_fast_forward(sha1_orig_head, sha1_curr_head, 0))\n+\t\t\tdie(_(\"Cannot fast-forward your working tree.\\n\"\n+\t\t\t\"After making sure that you saved anything precious from\\n\\n\"\n+\t\t\t\"  git diff %s\\n\\n\"\n+\t\t\t\"output, run\\n\\n\"\n+\t\t\t\"  git reset --hard\\n\\n\"\n+\t\t\t\"to recover.\"), sha1_to_hex(sha1_orig_head));\n+\t}\n+\n+\tconst struct string_list merge_head = get_merge_head();\n+\tif (merge_head.nr == 0)\n+\t\terror_on_no_merge_candidates(mode, argc, argv);\n+\n+\tif (is_null_sha1(sha1_orig_head))\n+\t\treturn fast_forward_unborn_branch(merge_head);\n+\n+\tif (mode == PULL_MERGE)\n+\t\treturn run_merge(merge_head);\n+\n+\treturn run_rebase(merge_head, fork_point_for_rebase, mode);\n+}\ndiff --git a/contrib/examples/git-pull.sh b/contrib/examples/git-pull.sh\nnew file mode 100755\nindex 0000000..4d4fc77\n--- /dev/null\n+++ b/contrib/examples/git-pull.sh\n@@ -0,0 +1,340 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2005 Junio C Hamano\n+#\n+# Fetch one or more remote refs and merge it/them into the current HEAD.\n+\n+USAGE='[-n | --no-stat] [--[no-]commit] [--[no-]squash] [--[no-]ff|--ff-only] [--[no-]rebase|--rebase=preserve] [-s strategy]... [<fetch-options>] <repo> <head>...'\n+LONG_USAGE='Fetch one or more remote refs and integrate it/them with the current HEAD.'\n+SUBDIRECTORY_OK=Yes\n+OPTIONS_SPEC=\n+. git-sh-setup\n+. git-sh-i18n\n+set_reflog_action \"pull${1+ $*}\"\n+require_work_tree_exists\n+cd_to_toplevel\n+\n+\n+die_conflict () {\n+    git diff-index --cached --name-status -r --ignore-submodules HEAD --\n+    if [ $(git config --bool --get advice.resolveConflict || echo true) = \"true\" ]; then\n+\tdie \"$(gettext \"Pull is not possible because you have unmerged files.\n+Please, fix them up in the work tree, and then use 'git add/rm <file>'\n+as appropriate to mark resolution and make a commit.\")\"\n+    else\n+\tdie \"$(gettext \"Pull is not possible because you have unmerged files.\")\"\n+    fi\n+}\n+\n+die_merge () {\n+    if [ $(git config --bool --get advice.resolveConflict || echo true) = \"true\" ]; then\n+\tdie \"$(gettext \"You have not concluded your merge (MERGE_HEAD exists).\n+Please, commit your changes before you can merge.\")\"\n+    else\n+\tdie \"$(gettext \"You have not concluded your merge (MERGE_HEAD exists).\")\"\n+    fi\n+}\n+\n+test -z \"$(git ls-files -u)\" || die_conflict\n+test -f \"$GIT_DIR/MERGE_HEAD\" && die_merge\n+\n+bool_or_string_config () {\n+\tgit config --bool \"$1\" 2>/dev/null || git config \"$1\"\n+}\n+\n+strategy_args= diffstat= no_commit= squash= no_ff= ff_only=\n+log_arg= verbosity= progress= recurse_submodules= verify_signatures=\n+merge_args= edit= rebase_args=\n+curr_branch=$(git symbolic-ref -q HEAD)\n+curr_branch_short=\"${curr_branch#refs/heads/}\"\n+rebase=$(bool_or_string_config branch.$curr_branch_short.rebase)\n+if test -z \"$rebase\"\n+then\n+\trebase=$(bool_or_string_config pull.rebase)\n+fi\n+\n+# Setup default fast-forward options via `pull.ff`\n+pull_ff=$(git config pull.ff)\n+case \"$pull_ff\" in\n+false)\n+\tno_ff=--no-ff\n+\t;;\n+only)\n+\tff_only=--ff-only\n+\t;;\n+esac\n+\n+\n+dry_run=\n+while :\n+do\n+\tcase \"$1\" in\n+\t-q|--quiet)\n+\t\tverbosity=\"$verbosity -q\" ;;\n+\t-v|--verbose)\n+\t\tverbosity=\"$verbosity -v\" ;;\n+\t--progress)\n+\t\tprogress=--progress ;;\n+\t--no-progress)\n+\t\tprogress=--no-progress ;;\n+\t-n|--no-stat|--no-summary)\n+\t\tdiffstat=--no-stat ;;\n+\t--stat|--summary)\n+\t\tdiffstat=--stat ;;\n+\t--log|--no-log)\n+\t\tlog_arg=$1 ;;\n+\t--no-c|--no-co|--no-com|--no-comm|--no-commi|--no-commit)\n+\t\tno_commit=--no-commit ;;\n+\t--c|--co|--com|--comm|--commi|--commit)\n+\t\tno_commit=--commit ;;\n+\t-e|--edit)\n+\t\tedit=--edit ;;\n+\t--no-edit)\n+\t\tedit=--no-edit ;;\n+\t--sq|--squ|--squa|--squas|--squash)\n+\t\tsquash=--squash ;;\n+\t--no-sq|--no-squ|--no-squa|--no-squas|--no-squash)\n+\t\tsquash=--no-squash ;;\n+\t--ff)\n+\t\tno_ff=--ff ;;\n+\t--no-ff)\n+\t\tno_ff=--no-ff ;;\n+\t--ff-only)\n+\t\tff_only=--ff-only ;;\n+\t-s=*|--s=*|--st=*|--str=*|--stra=*|--strat=*|--strate=*|\\\n+\t\t--strateg=*|--strategy=*|\\\n+\t-s|--s|--st|--str|--stra|--strat|--strate|--strateg|--strategy)\n+\t\tcase \"$#,$1\" in\n+\t\t*,*=*)\n+\t\t\tstrategy=$(expr \"z$1\" : 'z-[^=]*=\\(.*\\)') ;;\n+\t\t1,*)\n+\t\t\tusage ;;\n+\t\t*)\n+\t\t\tstrategy=\"$2\"\n+\t\t\tshift ;;\n+\t\tesac\n+\t\tstrategy_args=\"${strategy_args}-s $strategy \"\n+\t\t;;\n+\t-X*)\n+\t\tcase \"$#,$1\" in\n+\t\t1,-X)\n+\t\t\tusage ;;\n+\t\t*,-X)\n+\t\t\txx=\"-X $(git rev-parse --sq-quote \"$2\")\"\n+\t\t\tshift ;;\n+\t\t*,*)\n+\t\t\txx=$(git rev-parse --sq-quote \"$1\") ;;\n+\t\tesac\n+\t\tmerge_args=\"$merge_args$xx \"\n+\t\t;;\n+\t-r=*|--r=*|--re=*|--reb=*|--reba=*|--rebas=*|--rebase=*)\n+\t\trebase=\"${1#*=}\"\n+\t\t;;\n+\t-r|--r|--re|--reb|--reba|--rebas|--rebase)\n+\t\trebase=true\n+\t\t;;\n+\t--no-r|--no-re|--no-reb|--no-reba|--no-rebas|--no-rebase)\n+\t\trebase=false\n+\t\t;;\n+\t--recurse-submodules)\n+\t\trecurse_submodules=--recurse-submodules\n+\t\t;;\n+\t--recurse-submodules=*)\n+\t\trecurse_submodules=\"$1\"\n+\t\t;;\n+\t--no-recurse-submodules)\n+\t\trecurse_submodules=--no-recurse-submodules\n+\t\t;;\n+\t--verify-signatures)\n+\t\tverify_signatures=--verify-signatures\n+\t\t;;\n+\t--no-verify-signatures)\n+\t\tverify_signatures=--no-verify-signatures\n+\t\t;;\n+\t--gpg-sign|-S)\n+\t\tgpg_sign_args=-S\n+\t\t;;\n+\t--gpg-sign=*)\n+\t\tgpg_sign_args=$(git rev-parse --sq-quote \"-S${1#--gpg-sign=}\")\n+\t\t;;\n+\t-S*)\n+\t\tgpg_sign_args=$(git rev-parse --sq-quote \"$1\")\n+\t\t;;\n+\t--d|--dr|--dry|--dry-|--dry-r|--dry-ru|--dry-run)\n+\t\tdry_run=--dry-run\n+\t\t;;\n+\t-h|--help-all)\n+\t\tusage\n+\t\t;;\n+\t*)\n+\t\t# Pass thru anything that may be meant for fetch.\n+\t\tbreak\n+\t\t;;\n+\tesac\n+\tshift\n+done\n+\n+case \"$rebase\" in\n+preserve)\n+\trebase=true\n+\trebase_args=--preserve-merges\n+\t;;\n+true|false|'')\n+\t;;\n+*)\n+\techo \"Invalid value for --rebase, should be true, false, or preserve\"\n+\tusage\n+\texit 1\n+\t;;\n+esac\n+\n+error_on_no_merge_candidates () {\n+\texec >&2\n+\tfor opt\n+\tdo\n+\t\tcase \"$opt\" in\n+\t\t-t|--t|--ta|--tag|--tags)\n+\t\t\techo \"It doesn't make sense to pull all tags; you probably meant:\"\n+\t\t\techo \"  git fetch --tags\"\n+\t\t\texit 1\n+\t\tesac\n+\tdone\n+\n+\tif test true = \"$rebase\"\n+\tthen\n+\t\top_type=rebase\n+\t\top_prep=against\n+\telse\n+\t\top_type=merge\n+\t\top_prep=with\n+\tfi\n+\n+\tupstream=$(git config \"branch.$curr_branch_short.merge\")\n+\tremote=$(git config \"branch.$curr_branch_short.remote\")\n+\n+\tif [ $# -gt 1 ]; then\n+\t\tif [ \"$rebase\" = true ]; then\n+\t\t\tprintf \"There is no candidate for rebasing against \"\n+\t\telse\n+\t\t\tprintf \"There are no candidates for merging \"\n+\t\tfi\n+\t\techo \"among the refs that you just fetched.\"\n+\t\techo \"Generally this means that you provided a wildcard refspec which had no\"\n+\t\techo \"matches on the remote end.\"\n+\telif [ $# -gt 0 ] && [ \"$1\" != \"$remote\" ]; then\n+\t\techo \"You asked to pull from the remote '$1', but did not specify\"\n+\t\techo \"a branch. Because this is not the default configured remote\"\n+\t\techo \"for your current branch, you must specify a branch on the command line.\"\n+\telif [ -z \"$curr_branch\" -o -z \"$upstream\" ]; then\n+\t\t. git-parse-remote\n+\t\terror_on_missing_default_upstream \"pull\" $op_type $op_prep \\\n+\t\t\t\"git pull <remote> <branch>\"\n+\telse\n+\t\techo \"Your configuration specifies to $op_type $op_prep the ref '${upstream#refs/heads/}'\"\n+\t\techo \"from the remote, but no such ref was fetched.\"\n+\tfi\n+\texit 1\n+}\n+\n+test true = \"$rebase\" && {\n+\tif ! git rev-parse -q --verify HEAD >/dev/null\n+\tthen\n+\t\t# On an unborn branch\n+\t\tif test -f \"$GIT_DIR/index\"\n+\t\tthen\n+\t\t\tdie \"$(gettext \"updating an unborn branch with changes added to the index\")\"\n+\t\tfi\n+\telse\n+\t\trequire_clean_work_tree \"pull with rebase\" \"Please commit or stash them.\"\n+\tfi\n+\toldremoteref= &&\n+\ttest -n \"$curr_branch\" &&\n+\t. git-parse-remote &&\n+\tremoteref=\"$(get_remote_merge_branch \"$@\" 2>/dev/null)\" &&\n+\toldremoteref=$(git merge-base --fork-point \"$remoteref\" $curr_branch 2>/dev/null)\n+}\n+orig_head=$(git rev-parse -q --verify HEAD)\n+git fetch $verbosity $progress $dry_run $recurse_submodules --update-head-ok \"$@\" || exit 1\n+test -z \"$dry_run\" || exit 0\n+\n+curr_head=$(git rev-parse -q --verify HEAD)\n+if test -n \"$orig_head\" && test \"$curr_head\" != \"$orig_head\"\n+then\n+\t# The fetch involved updating the current branch.\n+\n+\t# The working tree and the index file is still based on the\n+\t# $orig_head commit, but we are merging into $curr_head.\n+\t# First update the working tree to match $curr_head.\n+\n+\teval_gettextln \"Warning: fetch updated the current branch head.\n+Warning: fast-forwarding your working tree from\n+Warning: commit \\$orig_head.\" >&2\n+\tgit update-index -q --refresh\n+\tgit read-tree -u -m \"$orig_head\" \"$curr_head\" ||\n+\t\tdie \"$(eval_gettext \"Cannot fast-forward your working tree.\n+After making sure that you saved anything precious from\n+$ git diff \\$orig_head\n+output, run\n+$ git reset --hard\n+to recover.\")\"\n+\n+fi\n+\n+merge_head=$(sed -e '/\tnot-for-merge\t/d' \\\n+\t-e 's/\t.*//' \"$GIT_DIR\"/FETCH_HEAD | \\\n+\ttr '\\012' ' ')\n+\n+case \"$merge_head\" in\n+'')\n+\terror_on_no_merge_candidates \"$@\"\n+\t;;\n+?*' '?*)\n+\tif test -z \"$orig_head\"\n+\tthen\n+\t\tdie \"$(gettext \"Cannot merge multiple branches into empty head\")\"\n+\tfi\n+\tif test true = \"$rebase\"\n+\tthen\n+\t\tdie \"$(gettext \"Cannot rebase onto multiple branches\")\"\n+\tfi\n+\t;;\n+esac\n+\n+# Pulling into unborn branch: a shorthand for branching off\n+# FETCH_HEAD, for lazy typers.\n+if test -z \"$orig_head\"\n+then\n+\t# Two-way merge: we claim the index is based on an empty tree,\n+\t# and try to fast-forward to HEAD.  This ensures we will not\n+\t# lose index/worktree changes that the user already made on\n+\t# the unborn branch.\n+\tempty_tree=4b825dc642cb6eb9a060e54bf8d69288fbee4904\n+\tgit read-tree -m -u $empty_tree $merge_head &&\n+\tgit update-ref -m \"initial pull\" HEAD $merge_head \"$curr_head\"\n+\texit\n+fi\n+\n+if test true = \"$rebase\"\n+then\n+\to=$(git show-branch --merge-base $curr_branch $merge_head $oldremoteref)\n+\tif test \"$oldremoteref\" = \"$o\"\n+\tthen\n+\t\tunset oldremoteref\n+\tfi\n+fi\n+\n+merge_name=$(git fmt-merge-msg $log_arg <\"$GIT_DIR/FETCH_HEAD\") || exit\n+case \"$rebase\" in\n+true)\n+\teval=\"git-rebase $diffstat $strategy_args $merge_args $rebase_args $verbosity\"\n+\teval=\"$eval $gpg_sign_args\"\n+\teval=\"$eval --onto $merge_head ${oldremoteref:-$merge_head}\"\n+\t;;\n+*)\n+\teval=\"git-merge $diffstat $no_commit $verify_signatures $edit $squash $no_ff $ff_only\"\n+\teval=\"$eval $log_arg $strategy_args $merge_args $verbosity $progress\"\n+\teval=\"$eval $gpg_sign_args\"\n+\teval=\"$eval \\\"\\$merge_name\\\" HEAD $merge_head\"\n+\t;;\n+esac\n+eval \"exec $eval\"\ndiff --git a/git-pull.sh b/git-pull.sh\ndeleted file mode 100755\nindex 4d4fc77..0000000\n--- a/git-pull.sh\n+++ /dev/null\n@@ -1,340 +0,0 @@\n-#!/bin/sh\n-#\n-# Copyright (c) 2005 Junio C Hamano\n-#\n-# Fetch one or more remote refs and merge it/them into the current HEAD.\n-\n-USAGE='[-n | --no-stat] [--[no-]commit] [--[no-]squash] [--[no-]ff|--ff-only] [--[no-]rebase|--rebase=preserve] [-s strategy]... [<fetch-options>] <repo> <head>...'\n-LONG_USAGE='Fetch one or more remote refs and integrate it/them with the current HEAD.'\n-SUBDIRECTORY_OK=Yes\n-OPTIONS_SPEC=\n-. git-sh-setup\n-. git-sh-i18n\n-set_reflog_action \"pull${1+ $*}\"\n-require_work_tree_exists\n-cd_to_toplevel\n-\n-\n-die_conflict () {\n-    git diff-index --cached --name-status -r --ignore-submodules HEAD --\n-    if [ $(git config --bool --get advice.resolveConflict || echo true) = \"true\" ]; then\n-\tdie \"$(gettext \"Pull is not possible because you have unmerged files.\n-Please, fix them up in the work tree, and then use 'git add/rm <file>'\n-as appropriate to mark resolution and make a commit.\")\"\n-    else\n-\tdie \"$(gettext \"Pull is not possible because you have unmerged files.\")\"\n-    fi\n-}\n-\n-die_merge () {\n-    if [ $(git config --bool --get advice.resolveConflict || echo true) = \"true\" ]; then\n-\tdie \"$(gettext \"You have not concluded your merge (MERGE_HEAD exists).\n-Please, commit your changes before you can merge.\")\"\n-    else\n-\tdie \"$(gettext \"You have not concluded your merge (MERGE_HEAD exists).\")\"\n-    fi\n-}\n-\n-test -z \"$(git ls-files -u)\" || die_conflict\n-test -f \"$GIT_DIR/MERGE_HEAD\" && die_merge\n-\n-bool_or_string_config () {\n-\tgit config --bool \"$1\" 2>/dev/null || git config \"$1\"\n-}\n-\n-strategy_args= diffstat= no_commit= squash= no_ff= ff_only=\n-log_arg= verbosity= progress= recurse_submodules= verify_signatures=\n-merge_args= edit= rebase_args=\n-curr_branch=$(git symbolic-ref -q HEAD)\n-curr_branch_short=\"${curr_branch#refs/heads/}\"\n-rebase=$(bool_or_string_config branch.$curr_branch_short.rebase)\n-if test -z \"$rebase\"\n-then\n-\trebase=$(bool_or_string_config pull.rebase)\n-fi\n-\n-# Setup default fast-forward options via `pull.ff`\n-pull_ff=$(git config pull.ff)\n-case \"$pull_ff\" in\n-false)\n-\tno_ff=--no-ff\n-\t;;\n-only)\n-\tff_only=--ff-only\n-\t;;\n-esac\n-\n-\n-dry_run=\n-while :\n-do\n-\tcase \"$1\" in\n-\t-q|--quiet)\n-\t\tverbosity=\"$verbosity -q\" ;;\n-\t-v|--verbose)\n-\t\tverbosity=\"$verbosity -v\" ;;\n-\t--progress)\n-\t\tprogress=--progress ;;\n-\t--no-progress)\n-\t\tprogress=--no-progress ;;\n-\t-n|--no-stat|--no-summary)\n-\t\tdiffstat=--no-stat ;;\n-\t--stat|--summary)\n-\t\tdiffstat=--stat ;;\n-\t--log|--no-log)\n-\t\tlog_arg=$1 ;;\n-\t--no-c|--no-co|--no-com|--no-comm|--no-commi|--no-commit)\n-\t\tno_commit=--no-commit ;;\n-\t--c|--co|--com|--comm|--commi|--commit)\n-\t\tno_commit=--commit ;;\n-\t-e|--edit)\n-\t\tedit=--edit ;;\n-\t--no-edit)\n-\t\tedit=--no-edit ;;\n-\t--sq|--squ|--squa|--squas|--squash)\n-\t\tsquash=--squash ;;\n-\t--no-sq|--no-squ|--no-squa|--no-squas|--no-squash)\n-\t\tsquash=--no-squash ;;\n-\t--ff)\n-\t\tno_ff=--ff ;;\n-\t--no-ff)\n-\t\tno_ff=--no-ff ;;\n-\t--ff-only)\n-\t\tff_only=--ff-only ;;\n-\t-s=*|--s=*|--st=*|--str=*|--stra=*|--strat=*|--strate=*|\\\n-\t\t--strateg=*|--strategy=*|\\\n-\t-s|--s|--st|--str|--stra|--strat|--strate|--strateg|--strategy)\n-\t\tcase \"$#,$1\" in\n-\t\t*,*=*)\n-\t\t\tstrategy=$(expr \"z$1\" : 'z-[^=]*=\\(.*\\)') ;;\n-\t\t1,*)\n-\t\t\tusage ;;\n-\t\t*)\n-\t\t\tstrategy=\"$2\"\n-\t\t\tshift ;;\n-\t\tesac\n-\t\tstrategy_args=\"${strategy_args}-s $strategy \"\n-\t\t;;\n-\t-X*)\n-\t\tcase \"$#,$1\" in\n-\t\t1,-X)\n-\t\t\tusage ;;\n-\t\t*,-X)\n-\t\t\txx=\"-X $(git rev-parse --sq-quote \"$2\")\"\n-\t\t\tshift ;;\n-\t\t*,*)\n-\t\t\txx=$(git rev-parse --sq-quote \"$1\") ;;\n-\t\tesac\n-\t\tmerge_args=\"$merge_args$xx \"\n-\t\t;;\n-\t-r=*|--r=*|--re=*|--reb=*|--reba=*|--rebas=*|--rebase=*)\n-\t\trebase=\"${1#*=}\"\n-\t\t;;\n-\t-r|--r|--re|--reb|--reba|--rebas|--rebase)\n-\t\trebase=true\n-\t\t;;\n-\t--no-r|--no-re|--no-reb|--no-reba|--no-rebas|--no-rebase)\n-\t\trebase=false\n-\t\t;;\n-\t--recurse-submodules)\n-\t\trecurse_submodules=--recurse-submodules\n-\t\t;;\n-\t--recurse-submodules=*)\n-\t\trecurse_submodules=\"$1\"\n-\t\t;;\n-\t--no-recurse-submodules)\n-\t\trecurse_submodules=--no-recurse-submodules\n-\t\t;;\n-\t--verify-signatures)\n-\t\tverify_signatures=--verify-signatures\n-\t\t;;\n-\t--no-verify-signatures)\n-\t\tverify_signatures=--no-verify-signatures\n-\t\t;;\n-\t--gpg-sign|-S)\n-\t\tgpg_sign_args=-S\n-\t\t;;\n-\t--gpg-sign=*)\n-\t\tgpg_sign_args=$(git rev-parse --sq-quote \"-S${1#--gpg-sign=}\")\n-\t\t;;\n-\t-S*)\n-\t\tgpg_sign_args=$(git rev-parse --sq-quote \"$1\")\n-\t\t;;\n-\t--d|--dr|--dry|--dry-|--dry-r|--dry-ru|--dry-run)\n-\t\tdry_run=--dry-run\n-\t\t;;\n-\t-h|--help-all)\n-\t\tusage\n-\t\t;;\n-\t*)\n-\t\t# Pass thru anything that may be meant for fetch.\n-\t\tbreak\n-\t\t;;\n-\tesac\n-\tshift\n-done\n-\n-case \"$rebase\" in\n-preserve)\n-\trebase=true\n-\trebase_args=--preserve-merges\n-\t;;\n-true|false|'')\n-\t;;\n-*)\n-\techo \"Invalid value for --rebase, should be true, false, or preserve\"\n-\tusage\n-\texit 1\n-\t;;\n-esac\n-\n-error_on_no_merge_candidates () {\n-\texec >&2\n-\tfor opt\n-\tdo\n-\t\tcase \"$opt\" in\n-\t\t-t|--t|--ta|--tag|--tags)\n-\t\t\techo \"It doesn't make sense to pull all tags; you probably meant:\"\n-\t\t\techo \"  git fetch --tags\"\n-\t\t\texit 1\n-\t\tesac\n-\tdone\n-\n-\tif test true = \"$rebase\"\n-\tthen\n-\t\top_type=rebase\n-\t\top_prep=against\n-\telse\n-\t\top_type=merge\n-\t\top_prep=with\n-\tfi\n-\n-\tupstream=$(git config \"branch.$curr_branch_short.merge\")\n-\tremote=$(git config \"branch.$curr_branch_short.remote\")\n-\n-\tif [ $# -gt 1 ]; then\n-\t\tif [ \"$rebase\" = true ]; then\n-\t\t\tprintf \"There is no candidate for rebasing against \"\n-\t\telse\n-\t\t\tprintf \"There are no candidates for merging \"\n-\t\tfi\n-\t\techo \"among the refs that you just fetched.\"\n-\t\techo \"Generally this means that you provided a wildcard refspec which had no\"\n-\t\techo \"matches on the remote end.\"\n-\telif [ $# -gt 0 ] && [ \"$1\" != \"$remote\" ]; then\n-\t\techo \"You asked to pull from the remote '$1', but did not specify\"\n-\t\techo \"a branch. Because this is not the default configured remote\"\n-\t\techo \"for your current branch, you must specify a branch on the command line.\"\n-\telif [ -z \"$curr_branch\" -o -z \"$upstream\" ]; then\n-\t\t. git-parse-remote\n-\t\terror_on_missing_default_upstream \"pull\" $op_type $op_prep \\\n-\t\t\t\"git pull <remote> <branch>\"\n-\telse\n-\t\techo \"Your configuration specifies to $op_type $op_prep the ref '${upstream#refs/heads/}'\"\n-\t\techo \"from the remote, but no such ref was fetched.\"\n-\tfi\n-\texit 1\n-}\n-\n-test true = \"$rebase\" && {\n-\tif ! git rev-parse -q --verify HEAD >/dev/null\n-\tthen\n-\t\t# On an unborn branch\n-\t\tif test -f \"$GIT_DIR/index\"\n-\t\tthen\n-\t\t\tdie \"$(gettext \"updating an unborn branch with changes added to the index\")\"\n-\t\tfi\n-\telse\n-\t\trequire_clean_work_tree \"pull with rebase\" \"Please commit or stash them.\"\n-\tfi\n-\toldremoteref= &&\n-\ttest -n \"$curr_branch\" &&\n-\t. git-parse-remote &&\n-\tremoteref=\"$(get_remote_merge_branch \"$@\" 2>/dev/null)\" &&\n-\toldremoteref=$(git merge-base --fork-point \"$remoteref\" $curr_branch 2>/dev/null)\n-}\n-orig_head=$(git rev-parse -q --verify HEAD)\n-git fetch $verbosity $progress $dry_run $recurse_submodules --update-head-ok \"$@\" || exit 1\n-test -z \"$dry_run\" || exit 0\n-\n-curr_head=$(git rev-parse -q --verify HEAD)\n-if test -n \"$orig_head\" && test \"$curr_head\" != \"$orig_head\"\n-then\n-\t# The fetch involved updating the current branch.\n-\n-\t# The working tree and the index file is still based on the\n-\t# $orig_head commit, but we are merging into $curr_head.\n-\t# First update the working tree to match $curr_head.\n-\n-\teval_gettextln \"Warning: fetch updated the current branch head.\n-Warning: fast-forwarding your working tree from\n-Warning: commit \\$orig_head.\" >&2\n-\tgit update-index -q --refresh\n-\tgit read-tree -u -m \"$orig_head\" \"$curr_head\" ||\n-\t\tdie \"$(eval_gettext \"Cannot fast-forward your working tree.\n-After making sure that you saved anything precious from\n-$ git diff \\$orig_head\n-output, run\n-$ git reset --hard\n-to recover.\")\"\n-\n-fi\n-\n-merge_head=$(sed -e '/\tnot-for-merge\t/d' \\\n-\t-e 's/\t.*//' \"$GIT_DIR\"/FETCH_HEAD | \\\n-\ttr '\\012' ' ')\n-\n-case \"$merge_head\" in\n-'')\n-\terror_on_no_merge_candidates \"$@\"\n-\t;;\n-?*' '?*)\n-\tif test -z \"$orig_head\"\n-\tthen\n-\t\tdie \"$(gettext \"Cannot merge multiple branches into empty head\")\"\n-\tfi\n-\tif test true = \"$rebase\"\n-\tthen\n-\t\tdie \"$(gettext \"Cannot rebase onto multiple branches\")\"\n-\tfi\n-\t;;\n-esac\n-\n-# Pulling into unborn branch: a shorthand for branching off\n-# FETCH_HEAD, for lazy typers.\n-if test -z \"$orig_head\"\n-then\n-\t# Two-way merge: we claim the index is based on an empty tree,\n-\t# and try to fast-forward to HEAD.  This ensures we will not\n-\t# lose index/worktree changes that the user already made on\n-\t# the unborn branch.\n-\tempty_tree=4b825dc642cb6eb9a060e54bf8d69288fbee4904\n-\tgit read-tree -m -u $empty_tree $merge_head &&\n-\tgit update-ref -m \"initial pull\" HEAD $merge_head \"$curr_head\"\n-\texit\n-fi\n-\n-if test true = \"$rebase\"\n-then\n-\to=$(git show-branch --merge-base $curr_branch $merge_head $oldremoteref)\n-\tif test \"$oldremoteref\" = \"$o\"\n-\tthen\n-\t\tunset oldremoteref\n-\tfi\n-fi\n-\n-merge_name=$(git fmt-merge-msg $log_arg <\"$GIT_DIR/FETCH_HEAD\") || exit\n-case \"$rebase\" in\n-true)\n-\teval=\"git-rebase $diffstat $strategy_args $merge_args $rebase_args $verbosity\"\n-\teval=\"$eval $gpg_sign_args\"\n-\teval=\"$eval --onto $merge_head ${oldremoteref:-$merge_head}\"\n-\t;;\n-*)\n-\teval=\"git-merge $diffstat $no_commit $verify_signatures $edit $squash $no_ff $ff_only\"\n-\teval=\"$eval $log_arg $strategy_args $merge_args $verbosity $progress\"\n-\teval=\"$eval $gpg_sign_args\"\n-\teval=\"$eval \\\"\\$merge_name\\\" HEAD $merge_head\"\n-\t;;\n-esac\n-eval \"exec $eval\"\ndiff --git a/git.c b/git.c\nindex 42a4ee5..cd824b6 100644\n--- a/git.c\n+++ b/git.c\n@@ -445,6 +445,7 @@ static struct cmd_struct commands[] = {\n \t{ \"pickaxe\", cmd_blame, RUN_SETUP },\n \t{ \"prune\", cmd_prune, RUN_SETUP },\n \t{ \"prune-packed\", cmd_prune_packed, RUN_SETUP },\n+\t{ \"pull\", cmd_pull, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"push\", cmd_push, RUN_SETUP },\n \t{ \"read-tree\", cmd_read_tree, RUN_SETUP },\n \t{ \"receive-pack\", cmd_receive_pack },\n-- \n2.4.0.7.gf20f26f\n"},{"id":"260634","messageId":"1430870453-5408-6-git-send-email-stephen.robin@gmail.com","threadId":"39170","inReplyTo":"1430870453-5408-1-git-send-email-stephen.robin@gmail.com","subject":"[PATCH 5/6] pull: allow interactive rebase","fromName":"Stephen Robin","fromEmail":"stephen.robin@gmail.com","sentAt":"2015-05-06T00:00:52Z","receivedAt":"2015-05-06T00:00:52Z","isPatch":true,"sender":{"key":"stephen.robin@gmail.com","avatar":null},"body":"THIS PATCH SERIES IS NOT CODE-COMPLETE OR FULLY TESTED.\nSee code comments beginning TODO for work remaining.\n\nTeach 'git pull' the option --rebase=interactive\nTeach 'git remote' that the value for config variable branch.<name>.rebase\ncan be 'interactive'\n\nBased-on-patch-by: Johannes Schindelin <johannes.schindelin@gmx.de>\nSigned-off-by: Stephen Robin <stephen.robin@gmail.com>\n---\n\nNotes:\n    This feature is already present in msysgit.  This patch can be used\n    either to bring the feature into standard git, or to resolve the\n    conflict that will occur in the next rebase of msysgit.\n\n Documentation/config.txt   |  1 +\n Documentation/git-pull.txt |  4 +++-\n builtin/pull.c             | 19 ++++++++++++++++---\n builtin/remote.c           |  8 ++++++--\n 4 files changed, 26 insertions(+), 6 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 2e5ceaf..91314ef 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -849,6 +849,7 @@ branch.<name>.rebase::\n \tinstead of merging the default branch from the default remote when\n \t\"git pull\" is run. See \"pull.rebase\" for doing this in a non\n \tbranch-specific manner.\n+\tWhen the value is `interactive`, the rebase is run in interactive mode.\n +\n \tWhen preserve, also pass `--preserve-merges` along to 'git rebase'\n \tso that locally committed merge commits will not be flattened\ndiff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt\nindex 712ab4b..8014908 100644\n--- a/Documentation/git-pull.txt\n+++ b/Documentation/git-pull.txt\n@@ -104,7 +104,7 @@ Options related to merging\n include::merge-options.txt[]\n \n -r::\n---rebase[=false|true|preserve]::\n+--rebase[=false|true|preserve|interactive]::\n \tWhen true, rebase the current branch on top of the upstream\n \tbranch after fetching. If there is a remote-tracking branch\n \tcorresponding to the upstream branch and the upstream branch\n@@ -116,6 +116,8 @@ to `git rebase` so that locally created merge commits will not be flattened.\n +\n When false, merge the current branch into the upstream branch.\n +\n+When `interactive`, enable the interactive mode of rebase.\n++\n See `pull.rebase`, `branch.<name>.rebase` and `branch.autoSetupRebase` in\n linkgit:git-config[1] if you want to make `git pull` always use\n `--rebase` instead of merging.\ndiff --git a/builtin/pull.c b/builtin/pull.c\nindex f420b4a..76c2f72 100644\n--- a/builtin/pull.c\n+++ b/builtin/pull.c\n@@ -26,7 +26,8 @@ enum pull_mode {\n \tPULL_NOT_SET = -1,\n \tPULL_MERGE,\n \tPULL_REBASE,\n-\tPULL_PRESERVE_MERGES_REBASE\n+\tPULL_PRESERVE_MERGES_REBASE,\n+\tPULL_INTERACTIVE_REBASE\n };\n \n static const char * const builtin_pull_usage[] = {\n@@ -85,12 +86,22 @@ static int parse_pull_mode(const char *name, const char* arg,\n \t\treturn 0;\n \t}\n \n+\tif (!strcmp(arg, \"interactive\")) {\n+\t\t*option_rebase = PULL_INTERACTIVE_REBASE;\n+\t\treturn 0;\n+\t}\n+\n+\tif (!strcmp(arg, \"i\")) {\n+\t\t*option_rebase = PULL_INTERACTIVE_REBASE;\n+\t\treturn 0;\n+\t}\n+\n \tif (!strcmp(arg, \"preserve\")) {\n \t\t*option_rebase = PULL_PRESERVE_MERGES_REBASE;\n \t\treturn 0;\n \t}\n \n-\terror(_(\"Invalid value for %s, should be 'true', 'false' or 'preserve'.\"), name);\n+\terror(_(\"Invalid value for %s, should be 'true', 'false', 'interactive' or 'preserve'.\"), name);\n \treturn -1;\n }\n \n@@ -197,7 +208,7 @@ static int option_parse_x(const struct option *opt,\n }\n \n static struct option builtin_pull_options[] = {\n-\t{ OPTION_CALLBACK, 0, \"rebase\", NULL, N_(\"true|false|preserve\"),\n+\t{ OPTION_CALLBACK, 0, \"rebase\", NULL, N_(\"true|false|interactive|preserve\"),\n \t\tN_(\"incorporate changes by rebasing rather than merging\"),\n \t\tPARSE_OPT_OPTARG, option_parse_rebase },\n \tOPT_BOOL(0, \"progress\", &progress,\n@@ -527,6 +538,8 @@ static int run_rebase(const struct string_list merge_head, const char *fork_poin\n \n \tif (pull_mode == PULL_PRESERVE_MERGES_REBASE)\n \t\targv_array_push(&argv, \"--preserve-merges\");\n+\telse if (pull_mode == PULL_INTERACTIVE_REBASE)\n+\t\targv_array_push(&argv, \"-i\");\n \n \tfor (v = verbosity; v > 0; v--)\n \t\targv_array_push(&argv, \"-v\");\ndiff --git a/builtin/remote.c b/builtin/remote.c\nindex 5d3ab90..af6b21d 100644\n--- a/builtin/remote.c\n+++ b/builtin/remote.c\n@@ -245,7 +245,7 @@ static int add(int argc, const char **argv)\n struct branch_info {\n \tchar *remote_name;\n \tstruct string_list merge;\n-\tint rebase;\n+\tenum { NO_REBASE, NORMAL_REBASE, INTERACTIVE_REBASE } rebase;\n };\n \n static struct string_list branch_list;\n@@ -306,6 +306,8 @@ static int config_read_branches(const char *key, const char *value, void *cb)\n \t\t\t\tinfo->rebase = v;\n \t\t\telse if (!strcmp(value, \"preserve\"))\n \t\t\t\tinfo->rebase = 1;\n+\t\t\telse if (!strcmp(value, \"interactive\"))\n+\t\t\t\tinfo->rebase = INTERACTIVE_REBASE;\n \t\t}\n \t}\n \treturn 0;\n@@ -1000,7 +1002,9 @@ static int show_local_info_item(struct string_list_item *item, void *cb_data)\n \n \tprintf(\"    %-*s \", show_info->width, item->string);\n \tif (branch_info->rebase) {\n-\t\tprintf_ln(_(\"rebases onto remote %s\"), merge->items[0].string);\n+\t\tprintf_ln(_(branch_info->rebase == INTERACTIVE_REBASE ?\n+\t\t\t\"rebases interactively onto remote %s\" :\n+\t\t\t\"rebases onto remote %s\"), merge->items[0].string);\n \t\treturn 0;\n \t} else if (show_info->any_rebase) {\n \t\tprintf_ln(_(\" merges with remote %s\"), merge->items[0].string);\n-- \n2.4.0.7.gf20f26f\n"},{"id":"260635","messageId":"1430870453-5408-7-git-send-email-stephen.robin@gmail.com","threadId":"39170","inReplyTo":"1430870453-5408-1-git-send-email-stephen.robin@gmail.com","subject":"[PATCH 6/6] parse-remote: dismantle git-parse-remote.sh","fromName":"Stephen Robin","fromEmail":"stephen.robin@gmail.com","sentAt":"2015-05-06T00:00:53Z","receivedAt":"2015-05-06T00:00:53Z","isPatch":true,"sender":{"key":"stephen.robin@gmail.com","avatar":null},"body":"THIS PATCH SERIES IS NOT CODE-COMPLETE OR FULLY TESTED.\nSee code comments beginning TODO for work remaining.\n\nFollowing the conversion of git-pull.sh to a builtin, git-parse-remote.sh\nis only used from two places:\nfunction error_on_missing_default_upstream is used within git-rebase.sh\nonly.\nfunction get_default_remote is used within git-submodule.sh only.\n\nMove these two functions into the scripts within which they're used, and\ndelete git-parse-remote.sh itself.\n\nSigned-off-by: Stephen Robin <stephen.robin@gmail.com>\n---\n .gitignore                           |  1 -\n Documentation/git-parse-remote.txt   | 23 ----------\n Makefile                             |  1 -\n command-list.txt                     |  1 -\n contrib/examples/git-parse-remote.sh | 89 ++++++++++++++++++++++++++++++++++++\n git-parse-remote.sh                  | 89 ------------------------------------\n git-rebase.sh                        | 36 ++++++++++++++-\n git-submodule.sh                     |  8 +++-\n 8 files changed, 131 insertions(+), 117 deletions(-)\n delete mode 100644 Documentation/git-parse-remote.txt\n create mode 100644 contrib/examples/git-parse-remote.sh\n delete mode 100644 git-parse-remote.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex 6287647..dd25b33 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -104,7 +104,6 @@\n /git-pack-redundant\n /git-pack-objects\n /git-pack-refs\n-/git-parse-remote\n /git-patch-id\n /git-prune\n /git-prune-packed\ndiff --git a/Documentation/git-parse-remote.txt b/Documentation/git-parse-remote.txt\ndeleted file mode 100644\nindex a45ea1e..0000000\n--- a/Documentation/git-parse-remote.txt\n+++ /dev/null\n@@ -1,23 +0,0 @@\n-git-parse-remote(1)\n-===================\n-\n-NAME\n-----\n-git-parse-remote - Routines to help parsing remote repository access parameters\n-\n-\n-SYNOPSIS\n---------\n-[verse]\n-'. \"$(git --exec-path)/git-parse-remote\"'\n-\n-DESCRIPTION\n------------\n-This script is included in various scripts to supply\n-routines to parse files under $GIT_DIR/remotes/ and\n-$GIT_DIR/branches/ and configuration variables that are related\n-to fetching, pulling and pushing.\n-\n-GIT\n----\n-Part of the linkgit:git[1] suite\ndiff --git a/Makefile b/Makefile\nindex 8d8fb3a..d41224c 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -481,7 +481,6 @@ SCRIPT_SH += git-submodule.sh\n SCRIPT_SH += git-web--browse.sh\n \n SCRIPT_LIB += git-mergetool--lib\n-SCRIPT_LIB += git-parse-remote\n SCRIPT_LIB += git-rebase--am\n SCRIPT_LIB += git-rebase--interactive\n SCRIPT_LIB += git-rebase--merge\ndiff --git a/command-list.txt b/command-list.txt\nindex f1eae08..273f69e 100644\n--- a/command-list.txt\n+++ b/command-list.txt\n@@ -86,7 +86,6 @@ git-p4                                  foreignscminterface\n git-pack-objects                        plumbingmanipulators\n git-pack-redundant                      plumbinginterrogators\n git-pack-refs                           ancillarymanipulators\n-git-parse-remote                        synchelpers\n git-patch-id                            purehelpers\n git-prune                               ancillarymanipulators\n git-prune-packed                        plumbingmanipulators\ndiff --git a/contrib/examples/git-parse-remote.sh b/contrib/examples/git-parse-remote.sh\nnew file mode 100644\nindex 0000000..55fe8d5\n--- /dev/null\n+++ b/contrib/examples/git-parse-remote.sh\n@@ -0,0 +1,89 @@\n+# This is a shell library to calculate the remote repository and\n+# upstream branch that should be pulled by \"git pull\" from the current\n+# branch.\n+\n+# git-ls-remote could be called from outside a git managed repository;\n+# this would fail in that case and would issue an error message.\n+GIT_DIR=$(git rev-parse -q --git-dir) || :;\n+\n+get_default_remote () {\n+\tcurr_branch=$(git symbolic-ref -q HEAD)\n+\tcurr_branch=\"${curr_branch#refs/heads/}\"\n+\torigin=$(git config --get \"branch.$curr_branch.remote\")\n+\techo ${origin:-origin}\n+}\n+\n+get_remote_merge_branch () {\n+\tcase \"$#\" in\n+\t0|1)\n+\t    origin=\"$1\"\n+\t    default=$(get_default_remote)\n+\t    test -z \"$origin\" && origin=$default\n+\t    curr_branch=$(git symbolic-ref -q HEAD) &&\n+\t    [ \"$origin\" = \"$default\" ] &&\n+\t    echo $(git for-each-ref --format='%(upstream)' $curr_branch)\n+\t    ;;\n+\t*)\n+\t    repo=$1\n+\t    shift\n+\t    ref=$1\n+\t    # FIXME: It should return the tracking branch\n+\t    #        Currently only works with the default mapping\n+\t    case \"$ref\" in\n+\t    +*)\n+\t\tref=$(expr \"z$ref\" : 'z+\\(.*\\)')\n+\t\t;;\n+\t    esac\n+\t    expr \"z$ref\" : 'z.*:' >/dev/null || ref=\"${ref}:\"\n+\t    remote=$(expr \"z$ref\" : 'z\\([^:]*\\):')\n+\t    case \"$remote\" in\n+\t    '' | HEAD ) remote=HEAD ;;\n+\t    heads/*) remote=${remote#heads/} ;;\n+\t    refs/heads/*) remote=${remote#refs/heads/} ;;\n+\t    refs/* | tags/* | remotes/* ) remote=\n+\t    esac\n+\t    [ -n \"$remote\" ] && case \"$repo\" in\n+\t\t.)\n+\t\t    echo \"refs/heads/$remote\"\n+\t\t    ;;\n+\t\t*)\n+\t\t    echo \"refs/remotes/$repo/$remote\"\n+\t\t    ;;\n+\t    esac\n+\tesac\n+}\n+\n+error_on_missing_default_upstream () {\n+\tcmd=\"$1\"\n+\top_type=\"$2\"\n+\top_prep=\"$3\"\n+\texample=\"$4\"\n+\tbranch_name=$(git symbolic-ref -q HEAD)\n+\t# If there's only one remote, use that in the suggestion\n+\tremote=\"<remote>\"\n+\tif test $(git remote | wc -l) = 1\n+\tthen\n+\t\tremote=$(git remote)\n+\tfi\n+\n+\tif test -z \"$branch_name\"\n+\tthen\n+\t\techo \"You are not currently on a branch. Please specify which\n+branch you want to $op_type $op_prep. See git-${cmd}(1) for details.\n+\n+    $example\n+\"\n+\telse\n+\t\techo \"There is no tracking information for the current branch.\n+Please specify which branch you want to $op_type $op_prep.\n+See git-${cmd}(1) for details\n+\n+    $example\n+\n+If you wish to set tracking information for this branch you can do so with:\n+\n+    git branch --set-upstream-to=$remote/<branch> ${branch_name#refs/heads/}\n+\"\n+\tfi\n+\texit 1\n+}\ndiff --git a/git-parse-remote.sh b/git-parse-remote.sh\ndeleted file mode 100644\nindex 55fe8d5..0000000\n--- a/git-parse-remote.sh\n+++ /dev/null\n@@ -1,89 +0,0 @@\n-# This is a shell library to calculate the remote repository and\n-# upstream branch that should be pulled by \"git pull\" from the current\n-# branch.\n-\n-# git-ls-remote could be called from outside a git managed repository;\n-# this would fail in that case and would issue an error message.\n-GIT_DIR=$(git rev-parse -q --git-dir) || :;\n-\n-get_default_remote () {\n-\tcurr_branch=$(git symbolic-ref -q HEAD)\n-\tcurr_branch=\"${curr_branch#refs/heads/}\"\n-\torigin=$(git config --get \"branch.$curr_branch.remote\")\n-\techo ${origin:-origin}\n-}\n-\n-get_remote_merge_branch () {\n-\tcase \"$#\" in\n-\t0|1)\n-\t    origin=\"$1\"\n-\t    default=$(get_default_remote)\n-\t    test -z \"$origin\" && origin=$default\n-\t    curr_branch=$(git symbolic-ref -q HEAD) &&\n-\t    [ \"$origin\" = \"$default\" ] &&\n-\t    echo $(git for-each-ref --format='%(upstream)' $curr_branch)\n-\t    ;;\n-\t*)\n-\t    repo=$1\n-\t    shift\n-\t    ref=$1\n-\t    # FIXME: It should return the tracking branch\n-\t    #        Currently only works with the default mapping\n-\t    case \"$ref\" in\n-\t    +*)\n-\t\tref=$(expr \"z$ref\" : 'z+\\(.*\\)')\n-\t\t;;\n-\t    esac\n-\t    expr \"z$ref\" : 'z.*:' >/dev/null || ref=\"${ref}:\"\n-\t    remote=$(expr \"z$ref\" : 'z\\([^:]*\\):')\n-\t    case \"$remote\" in\n-\t    '' | HEAD ) remote=HEAD ;;\n-\t    heads/*) remote=${remote#heads/} ;;\n-\t    refs/heads/*) remote=${remote#refs/heads/} ;;\n-\t    refs/* | tags/* | remotes/* ) remote=\n-\t    esac\n-\t    [ -n \"$remote\" ] && case \"$repo\" in\n-\t\t.)\n-\t\t    echo \"refs/heads/$remote\"\n-\t\t    ;;\n-\t\t*)\n-\t\t    echo \"refs/remotes/$repo/$remote\"\n-\t\t    ;;\n-\t    esac\n-\tesac\n-}\n-\n-error_on_missing_default_upstream () {\n-\tcmd=\"$1\"\n-\top_type=\"$2\"\n-\top_prep=\"$3\"\n-\texample=\"$4\"\n-\tbranch_name=$(git symbolic-ref -q HEAD)\n-\t# If there's only one remote, use that in the suggestion\n-\tremote=\"<remote>\"\n-\tif test $(git remote | wc -l) = 1\n-\tthen\n-\t\tremote=$(git remote)\n-\tfi\n-\n-\tif test -z \"$branch_name\"\n-\tthen\n-\t\techo \"You are not currently on a branch. Please specify which\n-branch you want to $op_type $op_prep. See git-${cmd}(1) for details.\n-\n-    $example\n-\"\n-\telse\n-\t\techo \"There is no tracking information for the current branch.\n-Please specify which branch you want to $op_type $op_prep.\n-See git-${cmd}(1) for details\n-\n-    $example\n-\n-If you wish to set tracking information for this branch you can do so with:\n-\n-    git branch --set-upstream-to=$remote/<branch> ${branch_name#refs/heads/}\n-\"\n-\tfi\n-\texit 1\n-}\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 55da9db..7b157ec 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -209,6 +209,41 @@ run_pre_rebase_hook () {\n \tfi\n }\n \n+error_on_missing_default_upstream () {\n+\tcmd=\"$1\"\n+\top_type=\"$2\"\n+\top_prep=\"$3\"\n+\texample=\"$4\"\n+\tbranch_name=$(git symbolic-ref -q HEAD)\n+\t# If there's only one remote, use that in the suggestion\n+\tremote=\"<remote>\"\n+\tif test $(git remote | wc -l) = 1\n+\tthen\n+\t\tremote=$(git remote)\n+\tfi\n+\n+\tif test -z \"$branch_name\"\n+\tthen\n+\t\techo \"You are not currently on a branch. Please specify which\n+branch you want to $op_type $op_prep. See git-${cmd}(1) for details.\n+\n+    $example\n+\"\n+\telse\n+\t\techo \"There is no tracking information for the current branch.\n+Please specify which branch you want to $op_type $op_prep.\n+See git-${cmd}(1) for details\n+\n+    $example\n+\n+If you wish to set tracking information for this branch you can do so with:\n+\n+    git branch --set-upstream-to=$remote/<branch> ${branch_name#refs/heads/}\n+\"\n+\tfi\n+\texit 1\n+}\n+\n test -f \"$apply_dir\"/applying &&\n \tdie \"$(gettext \"It looks like git-am is in progress. Cannot rebase.\")\"\n \n@@ -446,7 +481,6 @@ then\n \t\tif ! upstream_name=$(git rev-parse --symbolic-full-name \\\n \t\t\t--verify -q @{upstream} 2>/dev/null)\n \t\tthen\n-\t\t\t. git-parse-remote\n \t\t\terror_on_missing_default_upstream \"rebase\" \"rebase\" \\\n \t\t\t\t\"against\" \"git rebase <branch>\"\n \t\tfi\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex 36797c3..08c31eb 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -17,7 +17,6 @@ OPTIONS_SPEC=\n SUBDIRECTORY_OK=Yes\n . git-sh-setup\n . git-sh-i18n\n-. git-parse-remote\n require_work_tree\n wt_prefix=$(git rev-parse --show-prefix)\n cd_to_toplevel\n@@ -37,6 +36,13 @@ prefix=\n custom_name=\n depth=\n \n+get_default_remote () {\n+\tcurr_branch=$(git symbolic-ref -q HEAD)\n+\tcurr_branch=\"${curr_branch#refs/heads/}\"\n+\torigin=$(git config --get \"branch.$curr_branch.remote\")\n+\techo ${origin:-origin}\n+}\n+\n # The function takes at most 2 arguments. The first argument is the\n # URL that navigates to the submodule origin repo. When relative, this URL\n # is relative to the superproject origin URL repo. The second up_path\n-- \n2.4.0.7.gf20f26f\n"},{"id":"260641","messageId":"CACRoPnR0+Ovnnz=HzRA7ZsHHUQ54JrPfih5E8wsRaKY-ajf-gA@mail.gmail.com","threadId":"39170","inReplyTo":"1430870453-5408-1-git-send-email-stephen.robin@gmail.com","subject":"Re: [PATCH 0/6] Make pull a builtin","fromName":"Paul Tan","fromEmail":"pyokagan@gmail.com","sentAt":"2015-05-06T04:27:15Z","receivedAt":"2015-05-06T04:27:15Z","isPatch":true,"sender":{"key":"pyokagan@gmail.com","avatar":"https://avatars.githubusercontent.com/u/109479?v=4"},"body":"Hi Stephen,\n\nOn Wed, May 6, 2015 at 8:00 AM, Stephen Robin <stephen.robin@gmail.com> wrote:\n> Hi Paul,\n>\n> Congratulations on getting your project accepted for GSOC. Here's my\n> attempt at implementing pull as a builtin, maybe it will be of some use\n> as you look to progress your version.\n>\n> It's fairly complete in the sense that all the features of git-pull.sh\n> should be implemented, the test suite passes, and I've been using it\n> myself without issue. At the same time it's some way from finished as\n> I've never had time to test it fully and there are parts of the code I'm\n> not happy with.\n>\n> Apologies for not sharing this with you earlier.  I have been too busy\n> with paid work to look at any open source projects for some months.\n>\n> Good luck with your project!\n>\n> Regards\n> Stephen\n\nThank you so much for sharing your work. I'll be referencing this.\n\nRegards,\nPaul\n"},{"id":"260644","messageId":"b186a33e222c4b4cc5759cfd58531b13@www.dscho.org","threadId":"39170","inReplyTo":"1430870453-5408-6-git-send-email-stephen.robin@gmail.com","subject":"Re: [PATCH 5/6] pull: allow interactive rebase","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2015-05-06T05:43:20Z","receivedAt":"2015-05-06T05:43:20Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Stephen,\n\nOn 2015-05-06 02:00, Stephen Robin wrote:\n\n> Notes:\n>     This feature is already present in msysgit.\n\nPlease note that it is \"Git for Windows\". The term \"msysgit\" just refers to the development environment required to compile Git for Windows 1.x and build its installer.\n\nAnd yeah, I should contribute my changes already. Having said that, the --rebase=interactive support should not be a part of the initial conversion to a builtin because git-pull.sh as of git.git does not support it.\n\nBTW Thanks for contributing the patch series, even if it is incomplete as you noted. I am sure that Paul (and for that matter, Stefan and I) will find it useful to see how you implemented the builtin `git pull`.\n\nCiao,\nJohannes\n"}]}