]>
git.ipfire.org Git - thirdparty/git.git/blob - t/helper/test-fast-rebase.c
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"
20 #include "merge-ort.h"
23 #include "sequencer.h"
27 static const char *short_commit_name(struct commit
*commit
)
29 return find_unique_abbrev(&commit
->object
.oid
, DEFAULT_ABBREV
);
32 static struct commit
*peel_committish(const char *name
)
37 if (get_oid(name
, &oid
))
39 obj
= parse_object(the_repository
, &oid
);
40 return (struct commit
*)peel_to_type(name
, 0, obj
, OBJ_COMMIT
);
43 static char *get_author(const char *message
)
48 a
= find_commit_header(message
, "author", &len
);
50 return xmemdupz(a
, len
);
55 static struct commit
*create_commit(struct tree
*tree
,
56 struct commit
*based_on
,
57 struct commit
*parent
)
61 struct commit_list
*parents
= NULL
;
63 char *sign_commit
= NULL
;
64 struct commit_extra_header
*extra
;
65 struct strbuf msg
= STRBUF_INIT
;
66 const char *out_enc
= get_commit_output_encoding();
67 const char *message
= logmsg_reencode(based_on
, NULL
, out_enc
);
68 const char *orig_message
= NULL
;
69 const char *exclude_gpgsig
[] = { "gpgsig", NULL
};
71 commit_list_insert(parent
, &parents
);
72 extra
= read_commit_extra_headers(based_on
, exclude_gpgsig
);
73 find_commit_subject(message
, &orig_message
);
74 strbuf_addstr(&msg
, orig_message
);
75 author
= get_author(message
);
77 if (commit_tree_extended(msg
.buf
, msg
.len
, &tree
->object
.oid
, parents
,
78 &ret
, author
, NULL
, sign_commit
, extra
)) {
79 error(_("failed to write commit object"));
85 obj
= parse_object(the_repository
, &ret
);
86 return (struct commit
*)obj
;
89 int cmd__fast_rebase(int argc
, const char **argv
)
92 struct commit
*last_commit
= NULL
, *last_picked_commit
= NULL
;
93 struct object_id head
;
94 struct lock_file lock
= LOCK_INIT
;
95 struct strvec rev_walk_args
= STRVEC_INIT
;
97 struct commit
*commit
;
98 struct merge_options merge_opt
;
99 struct tree
*next_tree
, *base_tree
, *head_tree
;
100 struct merge_result result
;
101 struct strbuf reflog_msg
= STRBUF_INIT
;
102 struct strbuf branch_name
= STRBUF_INIT
;
106 * test-tool stuff doesn't set up the git directory by default; need to
109 setup_git_directory();
111 if (argc
== 2 && !strcmp(argv
[1], "-h")) {
112 printf("Sorry, I am not a psychiatrist; I can not give you the help you need. Oh, you meant usage...\n");
116 if (argc
!= 5 || strcmp(argv
[1], "--onto"))
117 die("usage: read the code, figure out how to use it, then do so");
119 onto
= peel_committish(argv
[2]);
120 strbuf_addf(&branch_name
, "refs/heads/%s", argv
[4]);
123 if (get_oid("HEAD", &head
))
124 die(_("Cannot read HEAD"));
125 assert(oideq(&onto
->object
.oid
, &head
));
127 repo_hold_locked_index(the_repository
, &lock
, LOCK_DIE_ON_ERROR
);
128 if (repo_read_index(the_repository
) < 0)
129 BUG("Could not read index");
131 repo_init_revisions(the_repository
, &revs
, NULL
);
132 revs
.verbose_header
= 1;
133 revs
.max_parents
= 1;
134 revs
.cherry_mark
= 1;
138 revs
.sort_order
= REV_SORT_IN_GRAPH_ORDER
;
140 strvec_pushl(&rev_walk_args
, "", argv
[4], "--not", argv
[3], NULL
);
142 if (setup_revisions(rev_walk_args
.nr
, rev_walk_args
.v
, &revs
, NULL
) > 1) {
143 ret
= error(_("unhandled options"));
147 strvec_clear(&rev_walk_args
);
149 if (prepare_revision_walk(&revs
) < 0) {
150 ret
= error(_("error preparing revisions"));
154 init_merge_options(&merge_opt
, the_repository
);
155 memset(&result
, 0, sizeof(result
));
156 merge_opt
.show_rename_progress
= 1;
157 merge_opt
.branch1
= "HEAD";
158 head_tree
= get_commit_tree(onto
);
159 result
.tree
= head_tree
;
161 while ((commit
= get_revision(&revs
))) {
164 fprintf(stderr
, "Rebasing %s...\r",
165 oid_to_hex(&commit
->object
.oid
));
166 assert(commit
->parents
&& !commit
->parents
->next
);
167 base
= commit
->parents
->item
;
169 next_tree
= get_commit_tree(commit
);
170 base_tree
= get_commit_tree(base
);
172 merge_opt
.branch2
= short_commit_name(commit
);
173 merge_opt
.ancestor
= xstrfmt("parent of %s", merge_opt
.branch2
);
175 merge_incore_nonrecursive(&merge_opt
,
181 free((char*)merge_opt
.ancestor
);
182 merge_opt
.ancestor
= NULL
;
185 last_picked_commit
= commit
;
186 last_commit
= create_commit(result
.tree
, commit
, last_commit
);
189 merge_switch_to_result(&merge_opt
, head_tree
, &result
, 1, !result
.clean
);
191 if (result
.clean
< 0)
195 fprintf(stderr
, "\nDone.\n");
196 strbuf_addf(&reflog_msg
, "finish rebase %s onto %s",
197 oid_to_hex(&last_picked_commit
->object
.oid
),
198 oid_to_hex(&last_commit
->object
.oid
));
199 if (update_ref(reflog_msg
.buf
, branch_name
.buf
,
200 &last_commit
->object
.oid
,
201 &last_picked_commit
->object
.oid
,
202 REF_NO_DEREF
, UPDATE_REFS_MSG_ON_ERR
)) {
203 error(_("could not update %s"), argv
[4]);
204 die("Failed to update %s", argv
[4]);
206 if (create_symref("HEAD", branch_name
.buf
, reflog_msg
.buf
) < 0)
207 die(_("unable to update HEAD"));
209 prime_cache_tree(the_repository
, the_repository
->index
,
212 fprintf(stderr
, "\nAborting: Hit a conflict.\n");
213 strbuf_addf(&reflog_msg
, "rebase progress up to %s",
214 oid_to_hex(&last_picked_commit
->object
.oid
));
215 if (update_ref(reflog_msg
.buf
, "HEAD",
216 &last_commit
->object
.oid
,
218 REF_NO_DEREF
, UPDATE_REFS_MSG_ON_ERR
)) {
219 error(_("could not update %s"), argv
[4]);
220 die("Failed to update %s", argv
[4]);
223 if (write_locked_index(&the_index
, &lock
,
224 COMMIT_LOCK
| SKIP_IF_UNCHANGED
))
225 die(_("unable to write %s"), get_index_file());
227 ret
= (result
.clean
== 0);
229 strbuf_release(&reflog_msg
);
230 strbuf_release(&branch_name
);
231 release_revisions(&revs
);