In git you can reorder any sequence of commits without any conflicts. Howwever, there is no nice "porcelain" for it.

The basis for it is the read-tree command.

In git, every commit is a snapshot and not a delta. (Repeat that three times.)

Any arbitrary snapshots of files can be arranged into a git history. They don't even have to be related. We could take a tarball of GCC, and make that the first commit. Then a tarball of Clang and make that the second commit.

The read-tree command will read any commit's state into the index, and from there you can make a commit out of it.

To reorder some N commits you're looking at, save all of their hashes somewhere, and then rewind the branch: git reset --hard HEAD~N. Then use git read-tree to read those hashes in whatever order you want, committing them one by one. To reuse their commit messages you have to use commit -C <hash>, though most them likely don't make any sense, because the text of commit messages usually talks about changes between a commit and its main parent.

What will happen is that your history now as N commits which represent the same states as the N you had there before, in a different order. For instance if you reverse them, then the oldest commit has all the features (is the same code baseline) as what the newest HEAD was previously. And then the subsequent child commits basically remove all the changes that were made, so the latest now looks like what the N-th looked like.

How I sometimes use this:

Suppose I made a fairly complex change that I would like to break up so that it is presented as a sequence of two or more states of the code.

There are cases when the following workflow is easy: first I make a commit out of the changes. One commit with everything. That commit is what I want the final state to look like. Then I revert some of the changes to produce the state before that state. If I have mostly been adding things, this might consist of just deleting them. Or I can do a git reset --patch HEAD^ to selectively revert. I commit this penultimate state. Then repeat the process: revert some more changes from that one, commit and so on, as many times as I see fit.

So what I end up with is the states of the code I want to present as a history, but exactly in the wrong order. Using "git rebase -i" doesn't work nicely; there are ugly conflicts, and some of them have to be encountered twice. Here is where the git read-tree trick comes into play: I simply reverse those exact states of the code to put them in the right order on the branch. After that I might do a rebase -i just to reword the commit messages to frame the code states from the POV of being changes from their parents.

You might think: why not just "git commit --patch" from the original working state to produce commits in order. The reason is that doesn't always make sense. For that you had to remember to make the commit as you were working. Because say you refactored something and then made a change. You can't easily do a "git commit --patch" which separates the refactoring from the change. Sure, if you do the refactoring and then a commit, and then make the change, you are good. But suppose you've conflated them already; now what? You can commit everything and then back out the changes that were done on top of the refactoring, and commit that. Then reorder the two states.