]> git.ipfire.org Git - thirdparty/git.git/blobdiff - add-patch.c
submodules: fix of regression on fetching of non-init subsub-repo
[thirdparty/git.git] / add-patch.c
index 457b8c550eb1b9711a67ceda65c27841ee7e3150..bd94bd3a7c9e86f4af6d9b887c824ff5be2db9a5 100644 (file)
@@ -266,6 +266,20 @@ struct add_p_state {
        const char *revision;
 };
 
+static void add_p_state_clear(struct add_p_state *s)
+{
+       size_t i;
+
+       strbuf_release(&s->answer);
+       strbuf_release(&s->buf);
+       strbuf_release(&s->plain);
+       strbuf_release(&s->colored);
+       for (i = 0; i < s->file_diff_nr; i++)
+               free(s->file_diff[i].hunk);
+       free(s->file_diff);
+       clear_add_i_state(&s->s);
+}
+
 static void err(struct add_p_state *s, const char *fmt, ...)
 {
        va_list args;
@@ -451,7 +465,7 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
        pend = p + plain->len;
        while (p != pend) {
                char *eol = memchr(p, '\n', pend - p);
-               const char *deleted = NULL, *added = NULL, *mode_change = NULL;
+               const char *deleted = NULL, *mode_change = NULL;
 
                if (!eol)
                        eol = pend;
@@ -468,12 +482,11 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
                } else if (p == plain->buf)
                        BUG("diff starts with unexpected line:\n"
                            "%.*s\n", (int)(eol - p), p);
-               else if (file_diff->deleted || file_diff->added)
+               else if (file_diff->deleted)
                        ; /* keep the rest of the file in a single "hunk" */
                else if (starts_with(p, "@@ ") ||
                         (hunk == &file_diff->head &&
-                         (skip_prefix(p, "deleted file", &deleted) ||
-                          skip_prefix(p, "new file", &added)))) {
+                         (skip_prefix(p, "deleted file", &deleted)))) {
                        if (marker == '-' || marker == '+')
                                /*
                                 * Should not happen; previous hunk did not end
@@ -491,8 +504,6 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
 
                        if (deleted)
                                file_diff->deleted = 1;
-                       else if (added)
-                               file_diff->added = 1;
                        else if (parse_hunk_header(s, hunk) < 0)
                                return -1;
 
@@ -501,6 +512,9 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
                         * split
                         */
                        marker = *p;
+               } else if (hunk == &file_diff->head &&
+                          starts_with(p, "new file")) {
+                       file_diff->added = 1;
                } else if (hunk == &file_diff->head &&
                           skip_prefix(p, "old mode ", &mode_change) &&
                           is_octal(mode_change, eol - mode_change)) {
@@ -1362,7 +1376,8 @@ static int patch_update_file(struct add_p_state *s,
                ALLOW_EDIT = 1 << 6
        } permitted = 0;
 
-       if (!file_diff->hunk_nr)
+       /* Empty added files have no hunks */
+       if (!file_diff->hunk_nr && !file_diff->added)
                return 0;
 
        strbuf_reset(&s->buf);
@@ -1371,21 +1386,25 @@ static int patch_update_file(struct add_p_state *s,
        for (;;) {
                if (hunk_index >= file_diff->hunk_nr)
                        hunk_index = 0;
-               hunk = file_diff->hunk + hunk_index;
-
+               hunk = file_diff->hunk_nr
+                               ? file_diff->hunk + hunk_index
+                               : &file_diff->head;
                undecided_previous = -1;
-               for (i = hunk_index - 1; i >= 0; i--)
-                       if (file_diff->hunk[i].use == UNDECIDED_HUNK) {
-                               undecided_previous = i;
-                               break;
-                       }
-
                undecided_next = -1;
-               for (i = hunk_index + 1; i < file_diff->hunk_nr; i++)
-                       if (file_diff->hunk[i].use == UNDECIDED_HUNK) {
-                               undecided_next = i;
-                               break;
-                       }
+
+               if (file_diff->hunk_nr) {
+                       for (i = hunk_index - 1; i >= 0; i--)
+                               if (file_diff->hunk[i].use == UNDECIDED_HUNK) {
+                                       undecided_previous = i;
+                                       break;
+                               }
+
+                       for (i = hunk_index + 1; i < file_diff->hunk_nr; i++)
+                               if (file_diff->hunk[i].use == UNDECIDED_HUNK) {
+                                       undecided_next = i;
+                                       break;
+                               }
+               }
 
                /* Everything decided? */
                if (undecided_previous < 0 && undecided_next < 0 &&
@@ -1393,38 +1412,40 @@ static int patch_update_file(struct add_p_state *s,
                        break;
 
                strbuf_reset(&s->buf);
-               render_hunk(s, hunk, 0, colored, &s->buf);
-               fputs(s->buf.buf, stdout);
+               if (file_diff->hunk_nr) {
+                       render_hunk(s, hunk, 0, colored, &s->buf);
+                       fputs(s->buf.buf, stdout);
 
-               strbuf_reset(&s->buf);
-               if (undecided_previous >= 0) {
-                       permitted |= ALLOW_GOTO_PREVIOUS_UNDECIDED_HUNK;
-                       strbuf_addstr(&s->buf, ",k");
-               }
-               if (hunk_index) {
-                       permitted |= ALLOW_GOTO_PREVIOUS_HUNK;
-                       strbuf_addstr(&s->buf, ",K");
-               }
-               if (undecided_next >= 0) {
-                       permitted |= ALLOW_GOTO_NEXT_UNDECIDED_HUNK;
-                       strbuf_addstr(&s->buf, ",j");
-               }
-               if (hunk_index + 1 < file_diff->hunk_nr) {
-                       permitted |= ALLOW_GOTO_NEXT_HUNK;
-                       strbuf_addstr(&s->buf, ",J");
-               }
-               if (file_diff->hunk_nr > 1) {
-                       permitted |= ALLOW_SEARCH_AND_GOTO;
-                       strbuf_addstr(&s->buf, ",g,/");
-               }
-               if (hunk->splittable_into > 1) {
-                       permitted |= ALLOW_SPLIT;
-                       strbuf_addstr(&s->buf, ",s");
-               }
-               if (hunk_index + 1 > file_diff->mode_change &&
-                   !file_diff->deleted) {
-                       permitted |= ALLOW_EDIT;
-                       strbuf_addstr(&s->buf, ",e");
+                       strbuf_reset(&s->buf);
+                       if (undecided_previous >= 0) {
+                               permitted |= ALLOW_GOTO_PREVIOUS_UNDECIDED_HUNK;
+                               strbuf_addstr(&s->buf, ",k");
+                       }
+                       if (hunk_index) {
+                               permitted |= ALLOW_GOTO_PREVIOUS_HUNK;
+                               strbuf_addstr(&s->buf, ",K");
+                       }
+                       if (undecided_next >= 0) {
+                               permitted |= ALLOW_GOTO_NEXT_UNDECIDED_HUNK;
+                               strbuf_addstr(&s->buf, ",j");
+                       }
+                       if (hunk_index + 1 < file_diff->hunk_nr) {
+                               permitted |= ALLOW_GOTO_NEXT_HUNK;
+                               strbuf_addstr(&s->buf, ",J");
+                       }
+                       if (file_diff->hunk_nr > 1) {
+                               permitted |= ALLOW_SEARCH_AND_GOTO;
+                               strbuf_addstr(&s->buf, ",g,/");
+                       }
+                       if (hunk->splittable_into > 1) {
+                               permitted |= ALLOW_SPLIT;
+                               strbuf_addstr(&s->buf, ",s");
+                       }
+                       if (hunk_index + 1 > file_diff->mode_change &&
+                           !file_diff->deleted) {
+                               permitted |= ALLOW_EDIT;
+                               strbuf_addstr(&s->buf, ",e");
+                       }
                }
                if (file_diff->deleted)
                        prompt_mode_type = PROMPT_DELETION;
@@ -1438,7 +1459,9 @@ static int patch_update_file(struct add_p_state *s,
                color_fprintf(stdout, s->s.prompt_color,
                              "(%"PRIuMAX"/%"PRIuMAX") ",
                              (uintmax_t)hunk_index + 1,
-                             (uintmax_t)file_diff->hunk_nr);
+                             (uintmax_t)(file_diff->hunk_nr
+                                               ? file_diff->hunk_nr
+                                               : 1));
                color_fprintf(stdout, s->s.prompt_color,
                              _(s->mode->prompt_mode[prompt_mode_type]),
                              s->buf.buf);
@@ -1458,16 +1481,24 @@ soft_increment:
                        hunk->use = SKIP_HUNK;
                        goto soft_increment;
                } else if (ch == 'a') {
-                       for (; hunk_index < file_diff->hunk_nr; hunk_index++) {
-                               hunk = file_diff->hunk + hunk_index;
-                               if (hunk->use == UNDECIDED_HUNK)
-                                       hunk->use = USE_HUNK;
+                       if (file_diff->hunk_nr) {
+                               for (; hunk_index < file_diff->hunk_nr; hunk_index++) {
+                                       hunk = file_diff->hunk + hunk_index;
+                                       if (hunk->use == UNDECIDED_HUNK)
+                                               hunk->use = USE_HUNK;
+                               }
+                       } else if (hunk->use == UNDECIDED_HUNK) {
+                               hunk->use = USE_HUNK;
                        }
                } else if (ch == 'd' || ch == 'q') {
-                       for (; hunk_index < file_diff->hunk_nr; hunk_index++) {
-                               hunk = file_diff->hunk + hunk_index;
-                               if (hunk->use == UNDECIDED_HUNK)
-                                       hunk->use = SKIP_HUNK;
+                       if (file_diff->hunk_nr) {
+                               for (; hunk_index < file_diff->hunk_nr; hunk_index++) {
+                                       hunk = file_diff->hunk + hunk_index;
+                                       if (hunk->use == UNDECIDED_HUNK)
+                                               hunk->use = SKIP_HUNK;
+                               }
+                       } else if (hunk->use == UNDECIDED_HUNK) {
+                               hunk->use = SKIP_HUNK;
                        }
                        if (ch == 'q') {
                                quit = 1;
@@ -1625,7 +1656,8 @@ soft_increment:
                if (file_diff->hunk[i].use == USE_HUNK)
                        break;
 
-       if (i < file_diff->hunk_nr) {
+       if (i < file_diff->hunk_nr ||
+           (!file_diff->hunk_nr && file_diff->head.use == USE_HUNK)) {
                /* At least one hunk selected: apply */
                strbuf_reset(&s->buf);
                reassemble_patch(s, file_diff, 0, &s->buf);
@@ -1641,7 +1673,7 @@ soft_increment:
                                         NULL, 0, NULL, 0))
                                error(_("'git apply' failed"));
                }
-               if (!repo_read_index(s->s.r))
+               if (repo_read_index(s->s.r) >= 0)
                        repo_refresh_and_write_index(s->s.r, REFRESH_QUIET, 0,
                                                     1, NULL, NULL, NULL);
        }
@@ -1690,9 +1722,7 @@ int run_add_p(struct repository *r, enum add_p_mode mode,
             repo_refresh_and_write_index(r, REFRESH_QUIET, 0, 1,
                                          NULL, NULL, NULL) < 0) ||
            parse_diff(&s, ps) < 0) {
-               strbuf_release(&s.plain);
-               strbuf_release(&s.colored);
-               clear_add_i_state(&s.s);
+               add_p_state_clear(&s);
                return -1;
        }
 
@@ -1707,10 +1737,6 @@ int run_add_p(struct repository *r, enum add_p_mode mode,
        else if (binary_count == s.file_diff_nr)
                fprintf(stderr, _("Only binary files changed.\n"));
 
-       strbuf_release(&s.answer);
-       strbuf_release(&s.buf);
-       strbuf_release(&s.plain);
-       strbuf_release(&s.colored);
-       clear_add_i_state(&s.s);
+       add_p_state_clear(&s);
        return 0;
 }