34

What non-interactive git command(s) achieve the change from Before to After?

Before:

A---B---C---D

After:

A---C'---B'---D'
John Vandenberg
  • 474
  • 6
  • 16
James Tauber
  • 3,386
  • 6
  • 27
  • 37

4 Answers4

30

In your case, you can rebase interactive: git rebase -i HEAD~4 Then you can just reorder your picks

For example lets add three more files to our branch:

git add A
git commit -m "A"

git add B
git commit -m "B"

git add C
git commit -m "C"

Your shortlog will be:

$ git shortlog
 (3):
      A
      B
      C

If you want to reorder B with C:

$ git rebase -i HEAD~2
pick 1f9133d B
pick 33f41be C

You just re-order them to be:

pick 33f41be C
pick 1f9133d B

After you're done writing, see the shortlog:

$ git shortlog
 (3):
      A
      C
      B

You can do the same thing with all the commits by re-ordering. It is like what you see is what you get, which is pretty cool :)

steampowered
  • 11,809
  • 12
  • 78
  • 98
Mohamed Mansour
  • 39,445
  • 10
  • 116
  • 90
  • 30
    How come this answer gets up votes when it clearly does not answer the question? OP asks for a way of doing this NON-INTERACTIVELY and this answer is all about how to do it INTERACTIVELY. – Andreas Wederbrand Mar 05 '14 at 13:47
  • 8
    @AndreasWederbrand probably because that's what most people (including me) were looking for, when they came here, though you're absolutely right. – hugo der hungrige May 02 '15 at 23:17
  • @AndreasWederbrand People searched for "How to reorder commits in git" and this on helped them :v. – Larry N Jan 02 '20 at 05:46
  • Let's imagine there is a thousand commits (or a million, if you don't think a thousand lines isn't much in your code editor) between `B` and `C`. How do you do this in a manageable way with an interactive rebase? – Olsgaard Feb 14 '22 at 07:11
26

Try this:

git reset --hard A
git cherry-pick C
git cherry-pick B
git cherry-pick D

There may be a way with git rebase, but I didn't really understand it.

Paŭlo Ebermann
  • 73,284
  • 20
  • 146
  • 210
  • 1
    git rebase -i will certainly let you do it; but wasn't sure how you'd achieve the same thing non-interactively – James Tauber Feb 12 '11 at 23:00
  • 2
    All `git rebase` does is use `git format-patch` and then `git am` to reapply them (possibly in a different order). It's a fundamentally interactive process, though, since re-applying the patches out of order can fail and require user intervention. – Ben Jackson Feb 13 '11 at 02:24
  • 1
    I think this really answers the question without rebase -i, except you ordered the cherry-picks B, C, D instead of C, B, D so it doesn't actually solve the problem :) – Thomson Comer Oct 23 '14 at 23:54
  • 1
    @ThomsonComer oops, seems nobody noted this for almost 4 years. Thanks. – Paŭlo Ebermann Oct 24 '14 at 20:23
  • 1
    This solution is to the point. Besides, for interactive, it works perfectly for TortoiseGit: tortoisegit show log, reset to "A" (HARD), tortoisegit show *reflog*, right click on the entry *before* the reset, "Show Log...", and then start the cherry picking to reorder your commits. If necessary, start by stashing your uncommitted local changes. – Antonio Oct 12 '16 at 15:31
6

See How do I run git rebase --interactive in non-interactive manner? for using git rebase --interactive in non-interactive manner.

Then, if you have formal criteria for reordering commits, you can script that, see for example Really flatten a git merge to reorder commits by the original commit date.

Community
  • 1
  • 1
pfalcon
  • 6,724
  • 4
  • 35
  • 43
0

If you want to reorder commits in a script and don't want to deal with the commit hashes, then this seems to work as a general solution (based on Paŭlo Ebermann 's answer):

git reset --hard @~3
git cherry-pick ORIG_HEAD~1
git cherry-pick ORIG_HEAD~2
git cherry-pick ORIG_HEAD

I assume that running this sequence of commands twice in a row will restore the commit tree to what it was before, except for changing the changed commit hashes.

Johannes Riecken
  • 2,301
  • 16
  • 17