25
#include "sigchain.h"
26
#include "unpack-trees.h"
27
#include "worktree.h"
28
+#include "oidmap.h"
29
+#include "oidset.h"
30
31
#define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
32
3450
strbuf_release(&sob);
3451
}
3452
3453
+struct labels_entry {
3454
+ struct hashmap_entry entry;
3455
+ char label[FLEX_ARRAY];
3456
+};
3457
+
3458
+static int labels_cmp(const void *fndata, const struct labels_entry *a,
3459
+ const struct labels_entry *b, const void *key)
3460
+{
3461
+ return key ? strcmp(a->label, key) : strcmp(a->label, b->label);
3462
+}
3463
+
3464
+struct string_entry {
3465
+ struct oidmap_entry entry;
3466
+ char string[FLEX_ARRAY];
3467
+};
3468
+
3469
+struct label_state {
3470
+ struct oidmap commit2label;
3471
+ struct hashmap labels;
3472
+ struct strbuf buf;
3473
+};
3474
+
3475
+static const char *label_oid(struct object_id *oid, const char *label,
3476
+ struct label_state *state)
3477
+{
3478
+ struct labels_entry *labels_entry;
3479
+ struct string_entry *string_entry;
3480
+ struct object_id dummy;
3481
+ size_t len;
3482
+ int i;
3483
+
3484
+ string_entry = oidmap_get(&state->commit2label, oid);
3485
+ if (string_entry)
3486
+ return string_entry->string;
3487
+
3488
+ /*
3489
+ * For "uninteresting" commits, i.e. commits that are not to be
3490
+ * rebased, and which can therefore not be labeled, we use a unique
3491
+ * abbreviation of the commit name. This is slightly more complicated
3492
+ * than calling find_unique_abbrev() because we also need to make
3493
+ * sure that the abbreviation does not conflict with any other
3494
+ * label.
3495
+ *
3496
+ * We disallow "interesting" commits to be labeled by a string that
3497
+ * is a valid full-length hash, to ensure that we always can find an
3498
+ * abbreviation for any uninteresting commit's names that does not
3499
+ * clash with any other label.
3500
+ */
3501
+ if (!label) {
3502
+ char *p;
3503
+
3504
+ strbuf_reset(&state->buf);
3505
+ strbuf_grow(&state->buf, GIT_SHA1_HEXSZ);
3506
+ label = p = state->buf.buf;
3507
+
3508
+ find_unique_abbrev_r(p, oid, default_abbrev);
3509
+
3510
+ /*
3511
+ * We may need to extend the abbreviated hash so that there is
3512
+ * no conflicting label.
3513
+ */
3514
+ if (hashmap_get_from_hash(&state->labels, strihash(p), p)) {
3515
+ size_t i = strlen(p) + 1;
3516
+
3517
+ oid_to_hex_r(p, oid);
3518
+ for (; i < GIT_SHA1_HEXSZ; i++) {
3519
+ char save = p[i];
3520
+ p[i] = '\0';
3521
+ if (!hashmap_get_from_hash(&state->labels,
3522
+ strihash(p), p))
3523
+ break;
3524
+ p[i] = save;
3525
+ }
3526
+ }
3527
+ } else if (((len = strlen(label)) == GIT_SHA1_RAWSZ &&
3528
+ !get_oid_hex(label, &dummy)) ||
3529
+ (len == 1 && *label == '#') ||
3530
+ hashmap_get_from_hash(&state->labels,
3531
+ strihash(label), label)) {
3532
+ /*
3533
+ * If the label already exists, or if the label is a valid full
3534
+ * OID, or the label is a '#' (which we use as a separator
3535
+ * between merge heads and oneline), we append a dash and a
3536
+ * number to make it unique.
3537
+ */
3538
+ struct strbuf *buf = &state->buf;
3539
+
3540
+ strbuf_reset(buf);
3541
+ strbuf_add(buf, label, len);
3542
+
3543
+ for (i = 2; ; i++) {
3544
+ strbuf_setlen(buf, len);
3545
+ strbuf_addf(buf, "-%d", i);
3546
+ if (!hashmap_get_from_hash(&state->labels,
3547
+ strihash(buf->buf),
3548
+ buf->buf))
3549
+ break;
3550
+ }
3551
+
3552
+ label = buf->buf;
3553
+ }
3554
+
3555
+ FLEX_ALLOC_STR(labels_entry, label, label);
3556
+ hashmap_entry_init(labels_entry, strihash(label));
3557
+ hashmap_add(&state->labels, labels_entry);
3558
+
3559
+ FLEX_ALLOC_STR(string_entry, string, label);
3560
+ oidcpy(&string_entry->entry.oid, oid);
3561
+ oidmap_put(&state->commit2label, string_entry);
3562
+
3563
+ return string_entry->string;
3564
+}
3565
+
3566
+static int make_script_with_merges(struct pretty_print_context *pp,
3567
+ struct rev_info *revs, FILE *out,
3568
+ unsigned flags)
3569
+{
3570
+ int keep_empty = flags & TODO_LIST_KEEP_EMPTY;
3571
+ struct strbuf buf = STRBUF_INIT, oneline = STRBUF_INIT;
3572
+ struct strbuf label = STRBUF_INIT;
3573
+ struct commit_list *commits = NULL, **tail = &commits, *iter;
3574
+ struct commit_list *tips = NULL, **tips_tail = &tips;
3575
+ struct commit *commit;
3576
+ struct oidmap commit2todo = OIDMAP_INIT;
3577
+ struct string_entry *entry;
3578
+ struct oidset interesting = OIDSET_INIT, child_seen = OIDSET_INIT,
3579
+ shown = OIDSET_INIT;
3580
+ struct label_state state = { OIDMAP_INIT, { NULL }, STRBUF_INIT };
3581
+
3582
+ int abbr = flags & TODO_LIST_ABBREVIATE_CMDS;
3583
+ const char *cmd_pick = abbr ? "p" : "pick",
3584
+ *cmd_label = abbr ? "l" : "label",
3585
+ *cmd_reset = abbr ? "t" : "reset",
3586
+ *cmd_merge = abbr ? "m" : "merge";
3587
+
3588
+ oidmap_init(&commit2todo, 0);
3589
+ oidmap_init(&state.commit2label, 0);
3590
+ hashmap_init(&state.labels, (hashmap_cmp_fn) labels_cmp, NULL, 0);
3591
+ strbuf_init(&state.buf, 32);
3592
+
3593
+ if (revs->cmdline.nr && (revs->cmdline.rev[0].flags & BOTTOM)) {
3594
+ struct object_id *oid = &revs->cmdline.rev[0].item->oid;
3595
+ FLEX_ALLOC_STR(entry, string, "onto");
3596
+ oidcpy(&entry->entry.oid, oid);
3597
+ oidmap_put(&state.commit2label, entry);
3598
+ }
3599
+
3600
+ /*
3601
+ * First phase:
3602
+ * - get onelines for all commits
3603
+ * - gather all branch tips (i.e. 2nd or later parents of merges)
3604
+ * - label all branch tips
3605
+ */
3606
+ while ((commit = get_revision(revs))) {
3607
+ struct commit_list *to_merge;
3608
+ int is_octopus;
3609
+ const char *p1, *p2;
3610
+ struct object_id *oid;
3611
+ int is_empty;
3612
+
3613
+ tail = &commit_list_insert(commit, tail)->next;
3614
+ oidset_insert(&interesting, &commit->object.oid);
3615
+
3616
+ is_empty = is_original_commit_empty(commit);
3617
+ if (!is_empty && (commit->object.flags & PATCHSAME))
3618
+ continue;
3619
+
3620
+ strbuf_reset(&oneline);
3621
+ pretty_print_commit(pp, commit, &oneline);
3622
+
3623
+ to_merge = commit->parents ? commit->parents->next : NULL;
3624
+ if (!to_merge) {
3625
+ /* non-merge commit: easy case */
3626
+ strbuf_reset(&buf);
3627
+ if (!keep_empty && is_empty)
3628
+ strbuf_addf(&buf, "%c ", comment_line_char);
3629
+ strbuf_addf(&buf, "%s %s %s", cmd_pick,
3630
+ oid_to_hex(&commit->object.oid),
3631
+ oneline.buf);
3632
+
3633
+ FLEX_ALLOC_STR(entry, string, buf.buf);
3634
+ oidcpy(&entry->entry.oid, &commit->object.oid);
3635
+ oidmap_put(&commit2todo, entry);
3636
+
3637
+ continue;
3638
+ }
3639
+
3640
+ is_octopus = to_merge && to_merge->next;
3641
+
3642
+ if (is_octopus)
3643
+ BUG("Octopus merges not yet supported");
3644
+
3645
+ /* Create a label */
3646
+ strbuf_reset(&label);
3647
+ if (skip_prefix(oneline.buf, "Merge ", &p1) &&
3648
+ (p1 = strchr(p1, '\'')) &&
3649
+ (p2 = strchr(++p1, '\'')))
3650
+ strbuf_add(&label, p1, p2 - p1);
3651
+ else if (skip_prefix(oneline.buf, "Merge pull request ",
3652
+ &p1) &&
3653
+ (p1 = strstr(p1, " from ")))
3654
+ strbuf_addstr(&label, p1 + strlen(" from "));
3655
+ else
3656
+ strbuf_addbuf(&label, &oneline);
3657
+
3658
+ for (p1 = label.buf; *p1; p1++)
3659
+ if (isspace(*p1))
3660
+ *(char *)p1 = '-';
3661
+
3662
+ strbuf_reset(&buf);
3663
+ strbuf_addf(&buf, "%s -C %s",
3664
+ cmd_merge, oid_to_hex(&commit->object.oid));
3665
+
3666
+ /* label the tip of merged branch */
3667
+ oid = &to_merge->item->object.oid;
3668
+ strbuf_addch(&buf, ' ');
3669
+
3670
+ if (!oidset_contains(&interesting, oid))
3671
+ strbuf_addstr(&buf, label_oid(oid, NULL, &state));
3672
+ else {
3673
+ tips_tail = &commit_list_insert(to_merge->item,
3674
+ tips_tail)->next;
3675
+
3676
+ strbuf_addstr(&buf, label_oid(oid, label.buf, &state));
3677
+ }
3678
+ strbuf_addf(&buf, " # %s", oneline.buf);
3679
+
3680
+ FLEX_ALLOC_STR(entry, string, buf.buf);
3681
+ oidcpy(&entry->entry.oid, &commit->object.oid);
3682
+ oidmap_put(&commit2todo, entry);
3683
+ }
3684
+
3685
+ /*
3686
+ * Second phase:
3687
+ * - label branch points
3688
+ * - add HEAD to the branch tips
3689
+ */
3690
+ for (iter = commits; iter; iter = iter->next) {
3691
+ struct commit_list *parent = iter->item->parents;
3692
+ for (; parent; parent = parent->next) {
3693
+ struct object_id *oid = &parent->item->object.oid;
3694
+ if (!oidset_contains(&interesting, oid))
3695
+ continue;
3696
+ if (!oidset_contains(&child_seen, oid))
3697
+ oidset_insert(&child_seen, oid);
3698
+ else
3699
+ label_oid(oid, "branch-point", &state);
3700
+ }
3701
+
3702
+ /* Add HEAD as implict "tip of branch" */
3703
+ if (!iter->next)
3704
+ tips_tail = &commit_list_insert(iter->item,
3705
+ tips_tail)->next;
3706
+ }
3707
+
3708
+ /*
3709
+ * Third phase: output the todo list. This is a bit tricky, as we
3710
+ * want to avoid jumping back and forth between revisions. To
3711
+ * accomplish that goal, we walk backwards from the branch tips,
3712
+ * gathering commits not yet shown, reversing the list on the fly,
3713
+ * then outputting that list (labeling revisions as needed).
3714
+ */
3715
+ fprintf(out, "%s onto\n", cmd_label);
3716
+ for (iter = tips; iter; iter = iter->next) {
3717
+ struct commit_list *list = NULL, *iter2;
3718
+
3719
+ commit = iter->item;
3720
+ if (oidset_contains(&shown, &commit->object.oid))
3721
+ continue;
3722
+ entry = oidmap_get(&state.commit2label, &commit->object.oid);
3723
+
3724
+ if (entry)
3725
+ fprintf(out, "\n# Branch %s\n", entry->string);
3726
+ else
3727
+ fprintf(out, "\n");
3728
+
3729
+ while (oidset_contains(&interesting, &commit->object.oid) &&
3730
+ !oidset_contains(&shown, &commit->object.oid)) {
3731
+ commit_list_insert(commit, &list);
3732
+ if (!commit->parents) {
3733
+ commit = NULL;
3734
+ break;
3735
+ }
3736
+ commit = commit->parents->item;
3737
+ }
3738
+
3739
+ if (!commit)
3740
+ fprintf(out, "%s onto\n", cmd_reset);
3741
+ else {
3742
+ const char *to = NULL;
3743
+
3744
+ entry = oidmap_get(&state.commit2label,
3745
+ &commit->object.oid);
3746
+ if (entry)
3747
+ to = entry->string;
3748
+
3749
+ if (!to || !strcmp(to, "onto"))
3750
+ fprintf(out, "%s onto\n", cmd_reset);
3751
+ else {
3752
+ strbuf_reset(&oneline);
3753
+ pretty_print_commit(pp, commit, &oneline);
3754
+ fprintf(out, "%s %s # %s\n",
3755
+ cmd_reset, to, oneline.buf);
3756
+ }
3757
+ }
3758
+
3759
+ for (iter2 = list; iter2; iter2 = iter2->next) {
3760
+ struct object_id *oid = &iter2->item->object.oid;
3761
+ entry = oidmap_get(&commit2todo, oid);
3762
+ /* only show if not already upstream */
3763
+ if (entry)
3764
+ fprintf(out, "%s\n", entry->string);
3765
+ entry = oidmap_get(&state.commit2label, oid);
3766
+ if (entry)
3767
+ fprintf(out, "%s %s\n",
3768
+ cmd_label, entry->string);
3769
+ oidset_insert(&shown, oid);
3770
+ }
3771
+
3772
+ free_commit_list(list);
3773
+ }
3774
+
3775
+ free_commit_list(commits);
3776
+ free_commit_list(tips);
3777
+
3778
+ strbuf_release(&label);
3779
+ strbuf_release(&oneline);
3780
+ strbuf_release(&buf);
3781
+
3782
+ oidmap_free(&commit2todo, 1);
3783
+ oidmap_free(&state.commit2label, 1);
3784
+ hashmap_free(&state.labels, 1);
3785
+ strbuf_release(&state.buf);
3786
+
3787
+ return 0;
3788
+}
3789
+
3790
int sequencer_make_script(FILE *out, int argc, const char **argv,
3791
unsigned flags)
3792
{
3797
struct commit *commit;
3798
int keep_empty = flags & TODO_LIST_KEEP_EMPTY;
3799
const char *insn = flags & TODO_LIST_ABBREVIATE_CMDS ? "p" : "pick";
3800
+ int rebase_merges = flags & TODO_LIST_REBASE_MERGES;
3801
3802
init_revisions(&revs, NULL);
3803
revs.verbose_header = 1;
3464
- revs.max_parents = 1;
3804
+ if (!rebase_merges)
3805
+ revs.max_parents = 1;
3806
revs.cherry_mark = 1;
3807
revs.limited = 1;
3808
revs.reverse = 1;
3827
if (prepare_revision_walk(&revs) < 0)
3828
return error(_("make_script: error preparing revisions"));
3829
3830
+ if (rebase_merges)
3831
+ return make_script_with_merges(&pp, &revs, out, flags);
3832
+
3833
while ((commit = get_revision(&revs))) {
3834
int is_empty = is_original_commit_empty(commit);
3835