2 * "git fast-rebase" builtin command
4 * FAST: Forking Any Subprocesses (is) Taboo
6 * This is meant SOLELY as a demo of what is possible. sequencer.c and
7 * rebase.c should be refactored to use the ideas here, rather than attempting
8 * to extend this file to replace those (unless Phillip or Dscho say that
9 * refactoring is too hard and we need a clean slate, but I'm guessing that
10 * refactoring is the better route).
13 #define USE_THE_INDEX_VARIABLE
14 #include "test-tool.h"
16 #include "cache-tree.h"
18 #include "environment.h"
22 #include "merge-ort.h"
23 #include "object-name.h"
26 #include "sequencer.h"
31 static const char *short_commit_name(struct commit
*commit
)
33 return repo_find_unique_abbrev(the_repository
, &commit
->object
.oid
,
37 static struct commit
*peel_committish(const char *name
)
42 if (repo_get_oid(the_repository
, name
, &oid
))
44 obj
= parse_object(the_repository
, &oid
);
45 return (struct commit
*)repo_peel_to_type(the_repository
, name
, 0, obj
,
49 static char *get_author(const char *message
)
54 a
= find_commit_header(message
, "author", &len
);
56 return xmemdupz(a
, len
);
61 static struct commit
*create_commit(struct tree
*tree
,
62 struct commit
*based_on
,
63 struct commit
*parent
)
67 struct commit_list
*parents
= NULL
;
69 char *sign_commit
= NULL
;
70 struct commit_extra_header
*extra
;
71 struct strbuf msg
= STRBUF_INIT
;
72 const char *out_enc
= get_commit_output_encoding();
73 const char *message
= repo_logmsg_reencode(the_repository
, based_on
,
75 const char *orig_message
= NULL
;
76 const char *exclude_gpgsig
[] = { "gpgsig", NULL
};
78 commit_list_insert(parent
, &parents
);
79 extra
= read_commit_extra_headers(based_on
, exclude_gpgsig
);
80 find_commit_subject(message
, &orig_message
);
81 strbuf_addstr(&msg
, orig_message
);
82 author
= get_author(message
);
84 if (commit_tree_extended(msg
.buf
, msg
.len
, &tree
->object
.oid
, parents
,
85 &ret
, author
, NULL
, sign_commit
, extra
)) {
86 error(_("failed to write commit object"));
92 obj
= parse_object(the_repository
, &ret
);
93 return (struct commit
*)obj
;
96 int cmd__fast_rebase(int argc
, const char **argv
)
99 struct commit
*last_commit
= NULL
, *last_picked_commit
= NULL
;
100 struct object_id head
;
101 struct lock_file lock
= LOCK_INIT
;
102 struct strvec rev_walk_args
= STRVEC_INIT
;
103 struct rev_info revs
;
104 struct commit
*commit
;
105 struct merge_options merge_opt
;
106 struct tree
*next_tree
, *base_tree
, *head_tree
;
107 struct merge_result result
;
108 struct strbuf reflog_msg
= STRBUF_INIT
;
109 struct strbuf branch_name
= STRBUF_INIT
;
113 * test-tool stuff doesn't set up the git directory by default; need to
116 setup_git_directory();
118 if (argc
== 2 && !strcmp(argv
[1], "-h")) {
119 printf("Sorry, I am not a psychiatrist; I can not give you the help you need. Oh, you meant usage...\n");
123 if (argc
!= 5 || strcmp(argv
[1], "--onto"))
124 die("usage: read the code, figure out how to use it, then do so");
126 onto
= peel_committish(argv
[2]);
127 strbuf_addf(&branch_name
, "refs/heads/%s", argv
[4]);
130 if (repo_get_oid(the_repository
, "HEAD", &head
))
131 die(_("Cannot read HEAD"));
132 assert(oideq(&onto
->object
.oid
, &head
));
134 repo_hold_locked_index(the_repository
, &lock
, LOCK_DIE_ON_ERROR
);
135 if (repo_read_index(the_repository
) < 0)
136 BUG("Could not read index");
138 repo_init_revisions(the_repository
, &revs
, NULL
);
139 revs
.verbose_header
= 1;
140 revs
.max_parents
= 1;
141 revs
.cherry_mark
= 1;
145 revs
.sort_order
= REV_SORT_IN_GRAPH_ORDER
;
147 strvec_pushl(&rev_walk_args
, "", argv
[4], "--not", argv
[3], NULL
);
149 if (setup_revisions(rev_walk_args
.nr
, rev_walk_args
.v
, &revs
, NULL
) > 1) {
150 ret
= error(_("unhandled options"));
154 strvec_clear(&rev_walk_args
);
156 if (prepare_revision_walk(&revs
) < 0) {
157 ret
= error(_("error preparing revisions"));
161 init_merge_options(&merge_opt
, the_repository
);
162 memset(&result
, 0, sizeof(result
));
163 merge_opt
.show_rename_progress
= 1;
164 merge_opt
.branch1
= "HEAD";
165 head_tree
= repo_get_commit_tree(the_repository
, onto
);
166 result
.tree
= head_tree
;
168 while ((commit
= get_revision(&revs
))) {
171 fprintf(stderr
, "Rebasing %s...\r",
172 oid_to_hex(&commit
->object
.oid
));
173 assert(commit
->parents
&& !commit
->parents
->next
);
174 base
= commit
->parents
->item
;
176 next_tree
= repo_get_commit_tree(the_repository
, commit
);
177 base_tree
= repo_get_commit_tree(the_repository
, base
);
179 merge_opt
.branch2
= short_commit_name(commit
);
180 merge_opt
.ancestor
= xstrfmt("parent of %s", merge_opt
.branch2
);
182 merge_incore_nonrecursive(&merge_opt
,
188 free((char*)merge_opt
.ancestor
);
189 merge_opt
.ancestor
= NULL
;
192 last_picked_commit
= commit
;
193 last_commit
= create_commit(result
.tree
, commit
, last_commit
);
196 merge_switch_to_result(&merge_opt
, head_tree
, &result
, 1, !result
.clean
);
198 if (result
.clean
< 0)
202 fprintf(stderr
, "\nDone.\n");
203 strbuf_addf(&reflog_msg
, "finish rebase %s onto %s",
204 oid_to_hex(&last_picked_commit
->object
.oid
),
205 oid_to_hex(&last_commit
->object
.oid
));
206 if (update_ref(reflog_msg
.buf
, branch_name
.buf
,
207 &last_commit
->object
.oid
,
208 &last_picked_commit
->object
.oid
,
209 REF_NO_DEREF
, UPDATE_REFS_MSG_ON_ERR
)) {
210 error(_("could not update %s"), argv
[4]);
211 die("Failed to update %s", argv
[4]);
213 if (create_symref("HEAD", branch_name
.buf
, reflog_msg
.buf
) < 0)
214 die(_("unable to update HEAD"));
216 prime_cache_tree(the_repository
, the_repository
->index
,
219 fprintf(stderr
, "\nAborting: Hit a conflict.\n");
220 strbuf_addf(&reflog_msg
, "rebase progress up to %s",
221 oid_to_hex(&last_picked_commit
->object
.oid
));
222 if (update_ref(reflog_msg
.buf
, "HEAD",
223 &last_commit
->object
.oid
,
225 REF_NO_DEREF
, UPDATE_REFS_MSG_ON_ERR
)) {
226 error(_("could not update %s"), argv
[4]);
227 die("Failed to update %s", argv
[4]);
230 if (write_locked_index(&the_index
, &lock
,
231 COMMIT_LOCK
| SKIP_IF_UNCHANGED
))
232 die(_("unable to write %s"), get_index_file());
234 ret
= (result
.clean
== 0);
236 strbuf_release(&reflog_msg
);
237 strbuf_release(&branch_name
);
238 release_revisions(&revs
);