Repository: mystor/git-revise

Issue:
Fixup of fixup not detected correctly
Hi, 
I often tend to do a lot of patches and then "squash" them at once. This also often means doing fixup commits to fixup commits. This seems to be completely fine with git rebase as it orders the commits correctly when using `--autosquash`. Revise on the other hand only moves the fist fixup commit, but not the subsequent one. I've done a minimal example in new repo, hope it helps with understanding the issue.

The git log after fixups
``` 
b87da89 (HEAD -> master) fixup! fixup! commit file
b6f2725 commit foo
30ef468 fixup! commit file
66129ee commit bar
8c62b80 commit file
```
What `git rebase -i --autosquash HEAD~5` shows:
```
pick 8c62b80 commit file
fixup 30ef468 fixup! commit file
fixup b87da89 fixup! fixup! commit file
pick 66129ee commit bar
pick b6f2725 commit foo
```
What `git revise -i --autosquash HEAD~5` shows:
```
pick 8c62b80f0846 commit file
fixup 30ef468dcb74 fixup! commit file
pick 66129ee8750d commit bar
fixup b87da89b57b3 fixup! fixup! commit file
pick b6f27254b70f commit foo
```

The revise command only reorders the first fixup, not the subsequent one.
My git version and git-revise version:
```
> git --version
git version 2.25.2
> git-revise --version
0.5.1
```

Discussion:

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 466f4d6..ccdf42e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,7 @@
 
 ## vNEXT
 
+* Fixed handling of fixup-of-fixup commits (#58)
 * Added support for `git add`'s `--patch` flag (#61)
 * Manpage is now installed in `share/man/man1` instead of `man/man1` (#62)
 * Which patch failed to apply is now included in the conflict editor (#53)
diff --git a/gitrevise/todo.py b/gitrevise/todo.py
index b2f262d..0c72394 100644
--- a/gitrevise/todo.py
+++ b/gitrevise/todo.py
@@ -107,7 +107,7 @@ def validate_todos(old: List[Step], new: List[Step]):
 def autosquash_todos(todos: List[Step]) -> List[Step]:
     new_todos = todos[:]
 
-    for step in reversed(todos):
+    for step in todos:
         # Check if this is a fixup! or squash! commit, and ignore it otherwise.
         summary = step.commit.summary()
         if summary.startswith("fixup! "):


Test patch:
diff --git a/tests/test_fixup.py b/tests/test_fixup.py
index 406d311..c98c744 100644
--- a/tests/test_fixup.py
+++ b/tests/test_fixup.py
@@ -181,3 +181,56 @@ def test_autosquash_nonhead(repo):
     assert new.persisted, "commit persisted to disk"
     assert new.author == old.author, "author is unchanged"
     assert new.committer == repo.default_committer, "committer is updated"
+
+    file1 = new.tree().entries[b"file1"].blob().body
+    assert file1 == b"hello, world\n"
+    file2 = new.tree().entries[b"file2"].blob().body
+    assert file2 == b"second file\nextra line\n"
+
+
+def test_fixup_of_fixup(repo):
+    bash(
+        """
+        echo "hello, world" > file1
+        git add file1
+        git commit -m "commit one"
+
+        echo "second file" > file2
+        git add file2
+        git commit -m "commit two"
+
+        echo "new line!" >> file1
+        git add file1
+        git commit -m "commit three"
+
+        echo "extra line" >> file2
+        git add file2
+        git commit --fixup=HEAD~
+
+        echo "even more" >> file2
+        git add file2
+        git commit --fixup=HEAD
+        """
+    )
+
+    old = repo.get_commit("HEAD~~~")
+    assert old.persisted
+
+    main(["--autosquash", str(old.parent().oid)])
+
+    new = repo.get_commit("HEAD~")
+    assert old != new, "commit was modified"
+    assert old.parents() == new.parents(), "parents are unchanged"
+
+    assert old.tree() != new.tree(), "tree is changed"
+
+    assert new.message == old.message, "message should not be changed"
+
+    assert new.persisted, "commit persisted to disk"
+    assert new.author == old.author, "author is unchanged"
+    assert new.committer == repo.default_committer, "committer is updated"
+
+    file1 = new.tree().entries[b"file1"].blob().body
+    assert file1 == b"hello, world\n"
+    file2 = new.tree().entries[b"file2"].blob().body
+    assert file2 == b"second file\nextra line\neven more\n"