-
Notifications
You must be signed in to change notification settings - Fork 137
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Avoid bad rebase amend #582
base: master
Are you sure you want to change the base?
Avoid bad rebase amend #582
Conversation
The best I can offer is https://github.com/git-for-windows/git/wiki/Debugging-Git. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is already a pretty good start!
I left a couple suggestions, and I think that the offsets used in the peek_command()
calls are too far off, and that's most likely why the test suite fails. All of my concerns will be addressed very easily, I am sure.
sequencer.c
Outdated
* has merge conflicts with the base here and we want to avoid amending | ||
* f1 onto p1 if p is skipped. | ||
*/ | ||
static GIT_PATH_FUNC(rebase_path_bad_fixup, "rebase-merge/avoid-bad-fixup") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To make this code easier to read, I think we should not skimp on the avoid
part and call the variable rebase_path_avoid_bad_fixup
.
sequencer.c
Outdated
@@ -3811,6 +3821,7 @@ static int pick_commits(struct repository *r, | |||
struct todo_item *item = todo_list->items + todo_list->current; | |||
const char *arg = todo_item_get_arg(todo_list, item); | |||
int check_todo = 0; | |||
struct object_id head; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's move this further down into the if (item->command <= TODO_SQUASH)
block, to restrict the scope further.
sequencer.c
Outdated
return error(_("cannot read HEAD")); | ||
|
||
p = oid_to_hex(&head); | ||
write_message(p, strlen(p), rebase_path_bad_fixup(), 1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea, but I would actually write this only in case of a failed TODO_PICK
, TODO_EDIT
or TODO_REWORD
, i.e. if is_pick_or_similar()
returns 1
(but make sure that we don't do it if is_fixup()
returns 1
).
Further, I think that peek_command(todo_list, 1)
is looking too far in the future. We are about to call do_pick_commit()
with item->command
, so that's the command to look at. Besides, at this point peek_command(todo_list, 0)
already looks at the next command.
So I think that the logic should go more like this:
struct strbuf buf = STRBUF_INIT;
struct object_id head, previous_head;
[...]
res = 0;
if (is_fixup(item->command)) {
if (read_oneliner(&buf, rebase_path_avoid_bad_fixup(), 1) > 0) {
if (get_oid(buf.buf, &previous_head)) {
error(_("invalid file contents '%s' of '%s'"),
buf.buf, rebase_path_avoid_bad_fixup());
strbuf_release(&buf);
}
strbuf_release(&buf);
if (get_oid("HEAD", &head))
return error(_("could not read HEAD"));
if (oideq(&head, &previous_head))
res = error(_("commit to fix up was skipped")); /* reschedule */
}
} else if (is_pick_or_similar(item->command) &&
is_fixup(peek_command(todo_list, 0)) {
char hex[GIT_MAX_HEXSZ + 1];
if (get_oid("HEAD", &head))
return error(_("cannot read HEAD"));
oid_to_hex_r(hex, &head);
write_message(hex, the_hash_algo->hexsz, rebase_path_avoid_bad_fixup(), 0);
}
if (!res)
res = do_pick_commit(r, item->command, item->commit,
opts, is_final_fixup(todo_list),
&check_todo);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still have 2 questions right now,
- Is there any particular advantage in writing to file, since we are only writing a single value ?
- What does oid_to_hex_r do differently, ie is it equivalent to writing
hex = oid_to_hex(&head);
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
struct strbuf buf = STRBUF_INIT;
And how about reducing this variable's scope even further ? Into
if (is_fixup(item->command)) { if (read_oneliner(&buf, rebase_path_avoid_bad_fixup(), 1) > 0) { if (get_oid(buf.buf, &previous_head)) { error(_("invalid file contents '%s' of '%s'"), buf.buf, rebase_path_avoid_bad_fixup()); strbuf_release(&buf); } strbuf_release(&buf); if (get_oid("HEAD", &head)) return error(_("could not read HEAD")); if (oideq(&head, &previous_head)) res = error(_("commit to fix up was skipped")); /* reschedule */ } }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The value is short all right, but remember: the most likely scenario is that the pick
failed due to merge conflicts, the user --skip
s it, and then the fixup
has no correct commit to target.
In other words: git
stopped running between writing the value and reading it. Those are two separate processes, therefore the value must be persisted to disk.
About reducing the scope even further: sure, as long indentation issues don't make the code unreadable?
Hi @ParthGala2k !
The CodingGuidelines document also has some guidance for using the system-installed GDB. If you compiled GDB yourself you will need to invoke it like this:
I you are on macOS and want to use LLDB, that would be:
Sometimes Git command spawn other Git commands under the hood, using fork+exec. You will recognize this by a call to either If the code your are trying to debug is in an instance of git spawned (fork+exec) by the main git process, you will need to use the Another option is to put a call to
Then you can control both instances independently. Addendum: there is also some interesting guidelines on the old wiki, that might still be useful for debugging tests: https://git.wiki.kernel.org/index.php/What_to_do_when_a_test_fails |
7aa3a0e
to
d1ef114
Compare
@dscho, any updates here ? |
Didn't you get excellent feedback from @phil-blain ? |
I meant to say about the pull request, not gdb here. Although the tests have passed, the the purpose is not yet solved. |
If by "run a test repository" you mean running a specifically-crafted test case in the Git test suite, then the old wiki page which I linked above mentions an approach that might work (I haven't tried it myself though):
So if
should run the test and open GDB at the right point, where you could insert breakpoints and then run the command in question. |
I think these days, you can simply prefix the |
This file stores info of the commit at a pick before a pick-fixup/squash chain eg. for this series of commands p1---p---f1---s---f.... The commit info for HEAD corresponding to pick p1 will be stored in file here. Although the name suggests bad_fixup it is actually pick p that has merge conflicts with the base here and we want to avoid applying fixup to f1 onto p1 if p is skipped. Currently if pick p results in a conflict, and is skipped f1 gets fixed up to p1. Signed-off-by: Parth Gala <[email protected]>
The condition here in the 'else if' statement verifies that the commit whose hash is written to file is actually that of pick p1 since we are writing before the call to do_pick_commit, refer f7f082c9bf p could also be an edit or reword but not fixup or squash p1---p---f1---f---f... The writing to file is done based upon the implementation of the `intend_to_amend` function in sequencer.c which similarly copies a single hash to a file. The `if` ensures that we are dealing with a fixup whose preceding pick/edit/reword had merge conflicts and was skipped. The file contents are compared with the current head position and if the two are same it means that the conflicting pick was skipped. Hence we error out without amending HEAD. Signed-off-by: Parth Gala <[email protected]>
d1ef114
to
c11ad1c
Compare
This version works as expected.
I will include it in the next PR after feedback on it. |
Given that this is all about the |
This is a draft PR regarding this[#210] issue.
I built and tested it on a test repository and it doesn't yet solve the issue.
Although I have currently done as per your recommendation of writing the pick
commit to a file and then comparing it while processing the fixup, I was wondering
what difference it would make to write the commit to a variable rather(since we are
just copying a single commit) ie is there a particular advantage in writing to file ?
Also I'm having trouble running the program on gdb, is there any reference for that?