]>
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"
15 #include "cache-tree.h"
17 #include "environment.h"
22 #include "merge-ort.h"
23 #include "object-name.h"
24 #include "read-cache-ll.h"
27 #include "sequencer.h"
32 static const char *short_commit_name(struct commit
*commit
)
34 return repo_find_unique_abbrev(the_repository
, &commit
->object
.oid
,
38 static struct commit
*peel_committish(const char *name
)
43 if (repo_get_oid(the_repository
, name
, &oid
))
45 obj
= parse_object(the_repository
, &oid
);
46 return (struct commit
*)repo_peel_to_type(the_repository
, name
, 0, obj
,
50 static char *get_author(const char *message
)
55 a
= find_commit_header(message
, "author", &len
);
57 return xmemdupz(a
, len
);
62 static struct commit
*create_commit(struct tree
*tree
,
63 struct commit
*based_on
,
64 struct commit
*parent
)
68 struct commit_list
*parents
= NULL
;
70 char *sign_commit
= NULL
;
71 struct commit_extra_header
*extra
;
72 struct strbuf msg
= STRBUF_INIT
;
73 const char *out_enc
= get_commit_output_encoding();
74 const char *message
= repo_logmsg_reencode(the_repository
, based_on
,
76 const char *orig_message
= NULL
;
77 const char *exclude_gpgsig
[] = { "gpgsig", NULL
};
79 commit_list_insert(parent
, &parents
);
80 extra
= read_commit_extra_headers(based_on
, exclude_gpgsig
);
81 find_commit_subject(message
, &orig_message
);
82 strbuf_addstr(&msg
, orig_message
);
83 author
= get_author(message
);
85 if (commit_tree_extended(msg
.buf
, msg
.len
, &tree
->object
.oid
, parents
,
86 &ret
, author
, NULL
, sign_commit
, extra
)) {
87 error(_("failed to write commit object"));
93 obj
= parse_object(the_repository
, &ret
);
94 return (struct commit
*)obj
;
97 int cmd__fast_rebase(int argc
, const char **argv
)
100 struct commit
*last_commit
= NULL
, *last_picked_commit
= NULL
;
101 struct object_id head
;
102 struct lock_file lock
= LOCK_INIT
;
103 struct strvec rev_walk_args
= STRVEC_INIT
;
104 struct rev_info revs
;
105 struct commit
*commit
;
106 struct merge_options merge_opt
;
107 struct tree
*next_tree
, *base_tree
, *head_tree
;
108 struct merge_result result
;
109 struct strbuf reflog_msg
= STRBUF_INIT
;
110 struct strbuf branch_name
= STRBUF_INIT
;
114 * test-tool stuff doesn't set up the git directory by default; need to
117 setup_git_directory();
119 if (argc
== 2 && !strcmp(argv
[1], "-h")) {
120 printf("Sorry, I am not a psychiatrist; I can not give you the help you need. Oh, you meant usage...\n");
124 if (argc
!= 5 || strcmp(argv
[1], "--onto"))
125 die("usage: read the code, figure out how to use it, then do so");
127 onto
= peel_committish(argv
[2]);
128 strbuf_addf(&branch_name
, "refs/heads/%s", argv
[4]);
131 if (repo_get_oid(the_repository
, "HEAD", &head
))
132 die(_("Cannot read HEAD"));
133 assert(oideq(&onto
->object
.oid
, &head
));
135 repo_hold_locked_index(the_repository
, &lock
, LOCK_DIE_ON_ERROR
);
136 if (repo_read_index(the_repository
) < 0)
137 BUG("Could not read index");
139 repo_init_revisions(the_repository
, &revs
, NULL
);
140 revs
.verbose_header
= 1;
141 revs
.max_parents
= 1;
142 revs
.cherry_mark
= 1;
146 revs
.sort_order
= REV_SORT_IN_GRAPH_ORDER
;
148 strvec_pushl(&rev_walk_args
, "", argv
[4], "--not", argv
[3], NULL
);
150 if (setup_revisions(rev_walk_args
.nr
, rev_walk_args
.v
, &revs
, NULL
) > 1) {
151 ret
= error(_("unhandled options"));
155 strvec_clear(&rev_walk_args
);
157 if (prepare_revision_walk(&revs
) < 0) {
158 ret
= error(_("error preparing revisions"));
162 init_merge_options(&merge_opt
, the_repository
);
163 memset(&result
, 0, sizeof(result
));
164 merge_opt
.show_rename_progress
= 1;
165 merge_opt
.branch1
= "HEAD";
166 head_tree
= repo_get_commit_tree(the_repository
, onto
);
167 result
.tree
= head_tree
;
169 while ((commit
= get_revision(&revs
))) {
172 fprintf(stderr
, "Rebasing %s...\r",
173 oid_to_hex(&commit
->object
.oid
));
174 assert(commit
->parents
&& !commit
->parents
->next
);
175 base
= commit
->parents
->item
;
177 next_tree
= repo_get_commit_tree(the_repository
, commit
);
178 base_tree
= repo_get_commit_tree(the_repository
, base
);
180 merge_opt
.branch2
= short_commit_name(commit
);
181 merge_opt
.ancestor
= xstrfmt("parent of %s", merge_opt
.branch2
);
183 merge_incore_nonrecursive(&merge_opt
,
189 free((char*)merge_opt
.ancestor
);
190 merge_opt
.ancestor
= NULL
;
193 last_picked_commit
= commit
;
194 last_commit
= create_commit(result
.tree
, commit
, last_commit
);
197 merge_switch_to_result(&merge_opt
, head_tree
, &result
, 1, !result
.clean
);
199 if (result
.clean
< 0)
203 fprintf(stderr
, "\nDone.\n");
204 strbuf_addf(&reflog_msg
, "finish rebase %s onto %s",
205 oid_to_hex(&last_picked_commit
->object
.oid
),
206 oid_to_hex(&last_commit
->object
.oid
));
207 if (update_ref(reflog_msg
.buf
, branch_name
.buf
,
208 &last_commit
->object
.oid
,
209 &last_picked_commit
->object
.oid
,
210 REF_NO_DEREF
, UPDATE_REFS_MSG_ON_ERR
)) {
211 error(_("could not update %s"), argv
[4]);
212 die("Failed to update %s", argv
[4]);
214 if (create_symref("HEAD", branch_name
.buf
, reflog_msg
.buf
) < 0)
215 die(_("unable to update HEAD"));
217 prime_cache_tree(the_repository
, the_repository
->index
,
220 fprintf(stderr
, "\nAborting: Hit a conflict.\n");
221 strbuf_addf(&reflog_msg
, "rebase progress up to %s",
222 oid_to_hex(&last_picked_commit
->object
.oid
));
223 if (update_ref(reflog_msg
.buf
, "HEAD",
224 &last_commit
->object
.oid
,
226 REF_NO_DEREF
, UPDATE_REFS_MSG_ON_ERR
)) {
227 error(_("could not update %s"), argv
[4]);
228 die("Failed to update %s", argv
[4]);
231 if (write_locked_index(&the_index
, &lock
,
232 COMMIT_LOCK
| SKIP_IF_UNCHANGED
))
233 die(_("unable to write %s"), get_index_file());
235 ret
= (result
.clean
== 0);
237 strbuf_release(&reflog_msg
);
238 strbuf_release(&branch_name
);
239 release_revisions(&revs
);