THIS IS A TEST INSTANCE ONLY! REPOSITORIES CAN BE DELETED AT ANY TIME!

Git Source Code Mirror - This is a publish-only repository and all pull requests are ignored. Please follow Documentation/SubmittingPatches procedure for any of your improvements.
git
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

190 lines
6.1KB

  1. #include "cache.h"
  2. #include "commit.h"
  3. #include "sequencer.h"
  4. #include "rebase-interactive.h"
  5. #include "strbuf.h"
  6. #include "commit-slab.h"
  7. #include "config.h"
  8. enum missing_commit_check_level {
  9. MISSING_COMMIT_CHECK_IGNORE = 0,
  10. MISSING_COMMIT_CHECK_WARN,
  11. MISSING_COMMIT_CHECK_ERROR
  12. };
  13. static enum missing_commit_check_level get_missing_commit_check_level(void)
  14. {
  15. const char *value;
  16. if (git_config_get_value("rebase.missingcommitscheck", &value) ||
  17. !strcasecmp("ignore", value))
  18. return MISSING_COMMIT_CHECK_IGNORE;
  19. if (!strcasecmp("warn", value))
  20. return MISSING_COMMIT_CHECK_WARN;
  21. if (!strcasecmp("error", value))
  22. return MISSING_COMMIT_CHECK_ERROR;
  23. warning(_("unrecognized setting %s for option "
  24. "rebase.missingCommitsCheck. Ignoring."), value);
  25. return MISSING_COMMIT_CHECK_IGNORE;
  26. }
  27. void append_todo_help(unsigned keep_empty, int command_count,
  28. const char *shortrevisions, const char *shortonto,
  29. struct strbuf *buf)
  30. {
  31. const char *msg = _("\nCommands:\n"
  32. "p, pick <commit> = use commit\n"
  33. "r, reword <commit> = use commit, but edit the commit message\n"
  34. "e, edit <commit> = use commit, but stop for amending\n"
  35. "s, squash <commit> = use commit, but meld into previous commit\n"
  36. "f, fixup <commit> = like \"squash\", but discard this commit's log message\n"
  37. "x, exec <command> = run command (the rest of the line) using shell\n"
  38. "b, break = stop here (continue rebase later with 'git rebase --continue')\n"
  39. "d, drop <commit> = remove commit\n"
  40. "l, label <label> = label current HEAD with a name\n"
  41. "t, reset <label> = reset HEAD to a label\n"
  42. "m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]\n"
  43. ". create a merge commit using the original merge commit's\n"
  44. ". message (or the oneline, if no original merge commit was\n"
  45. ". specified). Use -c <commit> to reword the commit message.\n"
  46. "\n"
  47. "These lines can be re-ordered; they are executed from top to bottom.\n");
  48. unsigned edit_todo = !(shortrevisions && shortonto);
  49. if (!edit_todo) {
  50. strbuf_addch(buf, '\n');
  51. strbuf_commented_addf(buf, Q_("Rebase %s onto %s (%d command)",
  52. "Rebase %s onto %s (%d commands)",
  53. command_count),
  54. shortrevisions, shortonto, command_count);
  55. }
  56. strbuf_add_commented_lines(buf, msg, strlen(msg));
  57. if (get_missing_commit_check_level() == MISSING_COMMIT_CHECK_ERROR)
  58. msg = _("\nDo not remove any line. Use 'drop' "
  59. "explicitly to remove a commit.\n");
  60. else
  61. msg = _("\nIf you remove a line here "
  62. "THAT COMMIT WILL BE LOST.\n");
  63. strbuf_add_commented_lines(buf, msg, strlen(msg));
  64. if (edit_todo)
  65. msg = _("\nYou are editing the todo file "
  66. "of an ongoing interactive rebase.\n"
  67. "To continue rebase after editing, run:\n"
  68. " git rebase --continue\n\n");
  69. else
  70. msg = _("\nHowever, if you remove everything, "
  71. "the rebase will be aborted.\n\n");
  72. strbuf_add_commented_lines(buf, msg, strlen(msg));
  73. if (!keep_empty) {
  74. msg = _("Note that empty commits are commented out");
  75. strbuf_add_commented_lines(buf, msg, strlen(msg));
  76. }
  77. }
  78. int edit_todo_list(struct repository *r, struct todo_list *todo_list,
  79. struct todo_list *new_todo, const char *shortrevisions,
  80. const char *shortonto, unsigned flags)
  81. {
  82. const char *todo_file = rebase_path_todo();
  83. unsigned initial = shortrevisions && shortonto;
  84. /* If the user is editing the todo list, we first try to parse
  85. * it. If there is an error, we do not return, because the user
  86. * might want to fix it in the first place. */
  87. if (!initial)
  88. todo_list_parse_insn_buffer(r, todo_list->buf.buf, todo_list);
  89. if (todo_list_write_to_file(r, todo_list, todo_file, shortrevisions, shortonto,
  90. -1, flags | TODO_LIST_SHORTEN_IDS | TODO_LIST_APPEND_TODO_HELP))
  91. return error_errno(_("could not write '%s'"), todo_file);
  92. if (initial && copy_file(rebase_path_todo_backup(), todo_file, 0666))
  93. return error(_("could not copy '%s' to '%s'."), todo_file,
  94. rebase_path_todo_backup());
  95. if (launch_sequence_editor(todo_file, &new_todo->buf, NULL))
  96. return -2;
  97. strbuf_stripspace(&new_todo->buf, 1);
  98. if (initial && new_todo->buf.len == 0)
  99. return -3;
  100. /* For the initial edit, the todo list gets parsed in
  101. * complete_action(). */
  102. if (!initial)
  103. return todo_list_parse_insn_buffer(r, new_todo->buf.buf, new_todo);
  104. return 0;
  105. }
  106. define_commit_slab(commit_seen, unsigned char);
  107. /*
  108. * Check if the user dropped some commits by mistake
  109. * Behaviour determined by rebase.missingCommitsCheck.
  110. * Check if there is an unrecognized command or a
  111. * bad SHA-1 in a command.
  112. */
  113. int todo_list_check(struct todo_list *old_todo, struct todo_list *new_todo)
  114. {
  115. enum missing_commit_check_level check_level = get_missing_commit_check_level();
  116. struct strbuf missing = STRBUF_INIT;
  117. int res = 0, i;
  118. struct commit_seen commit_seen;
  119. init_commit_seen(&commit_seen);
  120. if (check_level == MISSING_COMMIT_CHECK_IGNORE)
  121. goto leave_check;
  122. /* Mark the commits in git-rebase-todo as seen */
  123. for (i = 0; i < new_todo->nr; i++) {
  124. struct commit *commit = new_todo->items[i].commit;
  125. if (commit)
  126. *commit_seen_at(&commit_seen, commit) = 1;
  127. }
  128. /* Find commits in git-rebase-todo.backup yet unseen */
  129. for (i = old_todo->nr - 1; i >= 0; i--) {
  130. struct todo_item *item = old_todo->items + i;
  131. struct commit *commit = item->commit;
  132. if (commit && !*commit_seen_at(&commit_seen, commit)) {
  133. strbuf_addf(&missing, " - %s %.*s\n",
  134. find_unique_abbrev(&commit->object.oid, DEFAULT_ABBREV),
  135. item->arg_len,
  136. todo_item_get_arg(old_todo, item));
  137. *commit_seen_at(&commit_seen, commit) = 1;
  138. }
  139. }
  140. /* Warn about missing commits */
  141. if (!missing.len)
  142. goto leave_check;
  143. if (check_level == MISSING_COMMIT_CHECK_ERROR)
  144. res = 1;
  145. fprintf(stderr,
  146. _("Warning: some commits may have been dropped accidentally.\n"
  147. "Dropped commits (newer to older):\n"));
  148. /* Make the list user-friendly and display */
  149. fputs(missing.buf, stderr);
  150. strbuf_release(&missing);
  151. fprintf(stderr, _("To avoid this message, use \"drop\" to "
  152. "explicitly remove a commit.\n\n"
  153. "Use 'git config rebase.missingCommitsCheck' to change "
  154. "the level of warnings.\n"
  155. "The possible behaviours are: ignore, warn, error.\n\n"));
  156. leave_check:
  157. clear_commit_seen(&commit_seen);
  158. return res;
  159. }