Closed drewdeponte closed 9 months ago
libgit2 doesn't currently support opening interactive rebases. So what I am thinking about doing is implementing my own light weight functionality to read the necessary data from the .git
directory in pure Rust.
From poking around a bit it looks like when you are in the middle of a rebase a .git/rebase-merge
directory exists. The insides of this directory consists of something like the following.
✔ ls -l .git/rebase-merge 33589m 939efeb+rebase
total 104
-rw-r--r--@ 1 drewdeponte staff 41 Nov 12 14:42 amend
-rw-r--r--@ 1 drewdeponte staff 107 Nov 12 14:42 author-script
-rw-r--r--@ 1 drewdeponte staff 264 Nov 12 14:42 done
-rw-r--r--@ 1 drewdeponte staff 2 Nov 12 14:42 end
-rw-r--r--@ 1 drewdeponte staff 136 Nov 12 14:42 git-rebase-todo
-rw-r--r--@ 1 drewdeponte staff 1881 Nov 12 14:42 git-rebase-todo.backup
-rw-r--r--@ 1 drewdeponte staff 3 Nov 12 14:42 gpg_sign_opt
-rw-r--r--@ 1 drewdeponte staff 16 Nov 12 14:42 head-name
-rw-r--r--@ 1 drewdeponte staff 0 Nov 12 14:42 interactive
-rw-r--r--@ 1 drewdeponte staff 77 Nov 12 14:42 message
-rw-r--r--@ 1 drewdeponte staff 2 Nov 12 14:42 msgnum
-rw-r--r--@ 1 drewdeponte staff 0 Nov 12 14:42 no-reschedule-failed-exec
-rw-r--r--@ 1 drewdeponte staff 41 Nov 12 14:42 onto
-rw-r--r--@ 1 drewdeponte staff 41 Nov 12 14:42 orig-head
-rw-r--r--@ 1 drewdeponte staff 0 Nov 12 14:42 patch
-rw-r--r--@ 1 drewdeponte staff 41 Nov 12 14:42 stopped-sha
At least that is true when I tested doing an interactive rebase where I flagged a commit in the middle for edit.
It seems that the existance or lack of existance of the interactive
file is probably used to indicate interactive vs non-interactive rebase.
The head-name
file holds the reference that is being rebased.
✔ cat .git/rebase-merge/head-name 33593m 939efeb+rebase
refs/heads/main
The done
file seems to hold the commits that have already been replayed.
✔ cat .git/rebase-merge/done 33602m 939efeb+rebase
pick 7a645dbc60057ef469b9a2bc4a82b30fa5efbb75 Free world
pick a403343e8a173dc8cc2fa27d9465b13fe2c0d627 Free new world
pick 54fd6c2a52eaf0d67eaea5adc289c0831f5f4f7e Add comment to the end
edit 939efeb6a58842e931ed0277686c9d899b2671ae Add comment to the end # empty
The end
file seems to hold an integer representing the number of commits to be replayed in total.
✔ cat .git/rebase-merge/end 33603m 939efeb+rebase
6
The git-rebase-todo
file seems to hold the commits that still need to be replayed
✔ cat .git/rebase-merge/git-rebase-todo 33604m 939efeb+rebase
pick acd3e52e0eab5c6239e5b183ca10f3f2e4ec94d6 Merge branch 'foo' # empty
pick 6346a1c22019bf1e4ca69e11816a4217cf490f48 Test gpg signing
The message
file seems to hold the commit message for the commit that is flagged for edit.
✔ cat .git/rebase-merge/message 33605m 939efeb+rebase
Add comment to the end
<!-- ps-id: e214d699-8116-4f47-a65e-ef45547e3f9b -->
The msgnum
file seems to hold in integer represnting the index of the commit it is editing, assuming it is 0 indexed.
✔ cat .git/rebase-merge/msgnum 33606m 939efeb+rebase
4
The onto
file seems to hold the sha of the commit to replay the entire series of commits onto.
✔ cat .git/rebase-merge/onto 33608m 939efeb+rebase
66862a013d670570e6038f65241f16c83282b2d5
The orig-head
file seems to hold the sha of the commit that was originally the head of the branch being rebased, prior to rebasing.
✔ cat .git/rebase-merge/orig-head 33609m 939efeb+rebase
6346a1c22019bf1e4ca69e11816a4217cf490f48
The stopped-sha
file seems to contain the sha of the commit that the intercative rebase stopped at for editing.
✔ cat .git/rebase-merge/stopped-sha 33612m 939efeb+rebase
939efeb6a58842e931ed0277686c9d899b2671ae
I am not sure what the patch
file indicates exactly, but it is empty. So maybe the existance or non existance of it indicates something.
The gpg_sign_opt
seems to contain the gpg signing option. I assume based on either the config or command line options.
✔ cat .git/rebase-merge/gpg_sign_opt 33613m 939efeb+rebase
-S
I am not sure what the amend
file is for, but it seems to contain the sha of the commit that was flagged for editing and we are currently stopped at in the rebase.
✔ cat .git/rebase-merge/amend 33614m 939efeb+rebase
939efeb6a58842e931ed0277686c9d899b2671ae
The author-script
seems to contain some sort of script to set the author name, email, and date I would assume for the replaying of the commits.
✔ cat .git/rebase-merge/author-script 33616m 939efeb+rebase
GIT_AUTHOR_NAME='Drew De Ponte'
GIT_AUTHOR_EMAIL='cyphactor@gmail.com'
GIT_AUTHOR_DATE='@1697829045 -0400'
The git-rebase-todo.backup
file seems to contain the original todo from the interactive rebase prior to me marking the commit for edit
and saving and quiting.
✔ cat .git/rebase-merge/git-rebase-todo.backup 33617m 939efeb+rebase
pick 7a645dbc60057ef469b9a2bc4a82b30fa5efbb75 Free world
pick a403343e8a173dc8cc2fa27d9465b13fe2c0d627 Free new world
pick 54fd6c2a52eaf0d67eaea5adc289c0831f5f4f7e Add comment to the end
pick 939efeb6a58842e931ed0277686c9d899b2671ae Add comment to the end # empty
pick acd3e52e0eab5c6239e5b183ca10f3f2e4ec94d6 Merge branch 'foo' # empty
pick 6346a1c22019bf1e4ca69e11816a4217cf490f48 Test gpg signing
# Rebase 66862a0..6346a1c onto 66862a0 (6 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup [-C | -c] <commit> = like "squash" but keep only the previous
# commit's log message, unless -C is used, in which case
# keep only this commit's message; -c is same as -C but
# opens the editor
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# create a merge commit using the original merge commit's
# message (or the oneline, if no original merge commit was
# specified); use -c <commit> to reword the commit message
# u, update-ref <ref> = track a placeholder for the <ref> to be updated
# to this position in the new commits. The <ref> is
# updated at the end of the rebase
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
I am not sure what the no-reschedule-failed-exec
file is for exactly. But it is empty. So maybe the existance or non existance of it means something. Not sure.
Ok, I think the functionality we basically need is as follows.
.git/rebase-merge
exists.git/rebase-merge/head-name
.git/rebase-merge/done
.git/rebase-merge/git-rebase-todo
It is worth noting that the last two seem to be the same file format. Therefore, it is probably just worth implementing a parser for that file format.
I believe with that information we should be able to modify the gps list
command to actually work in the middle of a rebase.
I have a patch locally that implements a spike of it. The todo parser currently only addresses commands that operate on individual sha.
Next up I need to expand the parser to support parsing all the different command variants in the todo files so that we don't have any edge case problems. Also it will allow us to present the various commands in different ways if we decide it makes sense.
This has been integrated into mainline. Therefore, I am closing this issue.
The idea with this is that when you are in the middle of a rebase because of either interactive or because of a conflict, or what not.
gps list
will still work and it will actually show you visually the state you are in in the current patch stack.This means it should show you the commits that have already been rebased along with their associated branch associations and statuses as normal.
But then it should have some sort of separation above it (maybe just a blank line or something) and then have the commits that are to be replayed when when you run a
git rebase --continue
. These commits should also have associated branches and state info likegps list
currently shows.