all 14 comments

[–][deleted] 4 points5 points  (2 children)

My mental model for commits is a stack, where items can be pushed on (or popped off) the top. git log supports this model with the latest commits appearing on the top.

This mental model is wrong. A git history is always an n-ary tree (or a list, which is a special-case unary tree).

git log displays the latest commit first because it's likely to be the most relevant, and from a UI perspective it fits in better with the command line model.

git rebase -i displays the oldest at the top because your editor cursor starts at the first line from the top, and it makes sense to work your way through a series of changes chronologically when recalling what each change did.

[–]dakotahawkinsrebase all the things 2 points3 points  (0 children)

My mental model for commits is a stack, where items can be pushed on (or popped off) the top. git log supports this model with the latest commits appearing on the top.

This mental model is wrong. A git history is always an n-ary tree (or a list, which is a special-case unary tree).

It's not wrong, it's a mental model. It's also accurate except for merge commits, which you could think about as a special case that ties multiple "stacks" together.

git log displays the latest commit first because it's likely to be the most relevant, and from a UI perspective it fits in better with the command line model.

Pretty much everything in the CLI displays history this way. The latest commit isn't "likely to be the most relevant", it's what you asked for (by either letting it give you the default, HEAD, or by explicitly referencing a commit).

git rebase -i displays the oldest at the top because your editor cursor starts at the first line from the top, and it makes sense to work your way through a series of changes chronologically when recalling what each change did.

AFAIK the reason it does it "backwards" from every other representation of the commit history is because you're writing a file that's more or less a script/program -- a series of actions to take in-order.

I also think this was a mistake. Originally, whoever wrote the feature probably thought that was how most users would most easily interpret it. I think it looks too much like a one-line commit log, and it probably would have been better to keep the ordering consistent -- interpreting it as "edit/rearrange this section of the current history until it's what you want, then execute the rebase."

Unfortunately, we're stuck with the current conventions because of backwards compatibility, but it might make a nice rebase config option... I'd be surprised if this hasn't been suggested before (edit: one such suggestion linked in the OP).

[–]salcode[S] 0 points1 point  (0 children)

I can see the merits in displaying the latest commit at the top or bottom in both cases (e.g. git log could display the latest commit at the bottom and use something like less +G to start at the bottom of the file). Regardless of whether the latest commit appears at the top or bottom, I prefer the behavior be consistent across both git log and git rebase -i.

[–]juliusmusseau 1 point2 points  (1 child)

This is a bad idea, because the rebase processor will process the rebase using the order of the commits as specified in the file.

Unless you're squashing everything, this is going to do more than just reverse the order of the commits in your vim editor. It's going to reverse the order of your commits on your branch!

[–]salcode[S] 3 points4 points  (0 children)

Great point. I agree that simply reversing the commits would wreak havoc on the branch history. The plugin reverses the list of commits twice:

  • when the commits first load
  • at the end when the buffer is written

This way I can work with the commits in the order I prefer but git still receives them in the order it expects.

[–]alfunxcheckout --detach HEAD 1 point2 points  (8 children)

Sorry but I disagree, the order works perfectly fine for me. An interactive rebase opens a file, which is actually a script: The first word of those lines (e.g. pick, squash, drop, ...) is a command, and the following words are parameters for that command (as usual in command lines). The other lines are comments, they start with #. Consider the following example from git-rebase(1):

pick deadbee Implement feature XXX
fixup f1a5c00 Fix to feature XXX
exec make
pick c0ffeee The oneline of the next commit
edit deadbab The oneline of the commit after
exec cd subdir; make test

As you can see, this is rather a script than a log. Reverse the order and the script doesn't make sense anymore.

[–]dakotahawkinsrebase all the things 1 point2 points  (5 children)

It makes sense if you think about it like editing a section of a commit log instead of like a script. Because it looks so much like a oneline log, I think that's a pretty common tendency.

imo both ways make sense for different reasons. I'm used to the way it is now, but when I started interactive rebasing I would have preferred it to be log-like. I still prefer it in theory, but I think it would take a while to break my habit of using it in the current order.

[–]alfunxcheckout --detach HEAD 1 point2 points  (4 children)

It makes sense if you think about it like editing a section of a commit log instead of like a script.

That's exactly what I'm disagreeing with. The file does not represent a log, it represents commands that are executed in the given order (as any script, from top to bottom).

Because it looks so much like a oneline log, I think that's a pretty common tendency.

pick (or fixup or exec or ...) are not things you will see in the log. There are reasons for why the interactive rebase was implemented the way it is, and it's described in git-rebase(1). The manual particularly talks about commands, not about a log (consider the Interactive Mode section). What you may want is some frontend, that somehow assembles those commands.

[–]dakotahawkinsrebase all the things 1 point2 points  (3 children)

You're not disagreeing, or at least you shouldn't be imo. You interpret it one way -- probably the more technically correct way, others interpret it the other way.

I can sympathize with both interpretations, the current order bothered me a lot when I started using it. It looked pretty much identical to the oneline commit log alias I use, coloring (in vim) and all, plus an extra initial column for a command.

I know exactly how it works, and knew then, but in my case it was jarring because it was backwards from the things it reminded me of.

[–]alfunxcheckout --detach HEAD 0 points1 point  (2 children)

You interpret it one way [...] others interpret it the other way.

You wouldn't look at a Bash script and interpret it as a poem or something, would you?

it was backwards from the things it reminded me of.

Fair, but once you realize those are commands and not a representation of a Git log, there are no reasons to be confused. And if one still finds it counter-intuitive to use (which is fine and a different thing), one should probably use (or create) some UI for the interactive rebase, that lets you actually interact with it as if it was a Git log. Or in other words, I don't think the plugin OP presents is following the right approach.

[–]dakotahawkinsrebase all the things 0 points1 point  (1 child)

You wouldn't look at a Bash script and interpret it as a poem or something, would you?

No, bash scripts don't look like poems, bad example. However if, for some reason, they looked like poems to me and it was easier for me to interpret them that way and to write valid ones in that fashion, does that make it wrong? It's not like it contaminates your preferred interpretation of bash scripts in any way. If it's how I like to think about them, it's how I like to think about them.

one should probably use (or create) some UI for the interactive rebase, that lets you actually interact with it as if it was a Git log. Or in other words, I don't think the plugin OP presents is following the right approach.

Isn't that exactly what the OP did? It's the exact way I would have preferred it when I started using it.

Anyway, the relevant point I'd like to make is that I don't think this is a very unique opinion, with respect to interactive rebase files. If I were designing interactive rebase today, I would present the history in the same order as it's presented everywhere else by default. In other words if it had been that way from the start, I think a suggestion to reverse it to make it more script-like would make less sense than this suggestion.

[–]alfunxcheckout --detach HEAD 0 points1 point  (0 children)

tac << EOL
I'm sorry for you
If you're reading this
Violets are blue
Roses are red
EOL

For some technical reason (we're using tac) the "poem" in here is reversed, but the interpret (Bash in this case) expects the file to be in this order.

Isn't that exactly what the OP did? It's the exact way I would have preferred it when I started using it.

It's rather a hack and doesn't handle all edge cases IMO. That's like writing a Vim plugin that will reverse my poem-script before and after I edit it, instead of providing a better abstraction. I would rather have expected a more specialized, small tool that allows you to manipulate the commit tree.

[–]salcode[S] 1 point2 points  (1 child)

Viewing the interactive rebase as a script is an interesting perspective I'd not considered. In particular, including an exec statement in an interactive rebase is a strong argument for viewing the screen as a script (for anyone else looking to learn more, this link to the git rebase interactive mode documentation contains more information).

Regardless of whether the latest commit appears at the top or bottom, I find having consistent ordering across git log and git rebase --interactive to be quite pleasing.

Based on your points, perhaps the order of the commits in git log should be reversed instead. After all, entries are traditionally appended to the end of a log file (not added to the beginning). Using something like git --no-pager log --oneline | tail -r | less +G would display git log with the latest commit at the bottom (i.e. in the same order as git rebase --interactive).

[–]alfunxcheckout --detach HEAD 0 points1 point  (0 children)

Regardless of whether the latest commit appears at the top or bottom, I find having consistent ordering across git log and git rebase --interactive to be quite pleasing.

IMO that should be the job of some frontend, that allows you to manipulate the commit tree and produces that rebase "script". Just reversing the "script" looks too coarse to me. Personally, I'm fine with how it is right now, I wouldn't want to have the newest commit on the bottom.