git rebase -i shows wrong commit history after a rebase and force push

非 Y 不嫁゛ 提交于 2019-12-17 20:40:48

问题


I encountered an interesting problem after rebasing a branch on another branch; git rebase -i HEAD~n shows not only the wrong commit history (the old branch) but also the incorrect amount of commits.

What I want to do

I want to be able to do a git rebase -i HEAD~n on the correct commit history in order to squash a leftover commit from the old branch I based my branch on.

What I did to cause the issue

# On another Feature branch
git branch -b NewFeautureBranch
# Develop my commit
git add editedfile.extension
git commit -m "Commit message"
# I squashed and merged the feature branch into the development branch, as well as some other feature branches
git fetch --all
git checkout DevelopmentBranch
git pull
git checkout NewFeatureBranch
git rebase DevelopmentBranch
git push -f

Running git log and gitk will show the history as it should be, which is my current commit and an older commit from the feature branch it was originally based on, as expected. However, if I then run git rebase -i HEAD~4 I get the old branch's history as well as 11 commits instead of the 4 I asked for:

# Git rebase -i HEAD~4 opens up in VIM like this:
pick f79316dc Commit on old Branch base
pick ba742f2f Commit on old Branch base
pick 7577ea7a Commit on old Branch base
pick 91c4088c Commit on old Branch base
pick 98feed6d Commit on old Branch base
pick e8a73d78 Commit on old Branch base
pick 198f79e7 Commit on old Branch base
pick 10bb699c Commit on old Branch base
pick 1d15a926 Commit on old Branch base
pick 0cf569bb Previous commit I want to squash with
pick 470de8d9 Current FeatureBranch commit

But git log prints this:

# As it should be when seeing git log and gitk
commit 470de8d92bb490dd14c31d5741b7edec82ca7597 (HEAD -> FeatureBranch, origin/FeatureBranch)
Author: evFox <evFox@fake-email.com>
Date:   Wed Jan 3 16:08:24 2018 +0100
    Feature commit message

commit 0cf569bba43b5747831a28d6cb42209dab1c2ffa
Author: evFox <evFox@fake-email.com>
Date:   Wed Jan 3 12:09:48 2018 +0100
    Feature from old branch still relevant to this; what I want to merge with the later commit.

commit 982c30d9c3b46539340fe48c241192e377d3e136 (origin/Development, Development)
Merge: ab6e7c9d 1d15a926
Author: evFox <evFox@fake-email.com>
Date:   Tue Jan 9 10:51:06 2018 +0000
    Merged PR XX: Merge OldFeatureBranch to Development

What I've tried

I've tried to delete the branch locally and pull a fresh one off of the remote repository:

git checkout DevelopmentBranch
git branch -D NewFeatureBranch
git checkout -b NewFeatureBranch origin/NewFeatureBranch

I have tried to get more history by increasing the commits in the git rebase -i and I can clearly see that the commits are old, belonging to the OldFeatureBranch as it was before it was updated and merged:

# Git rebase -i HEAD~20 opens up in VIM like this:
pick bt67f432 Commit on old version DevelopmentBranch
pick 5g67f33s Commit on old version DevelopmentBranch
pick rt53d563 Commit on old version DevelopmentBranch
pick ew5r45fg Commit on old version DevelopmentBranch
pick 9gy3f74f Commit on old version DevelopmentBranch
pick 58u5hh63 Commit on old version DevelopmentBranch
pick 34fdg5d5 Commit on old version DevelopmentBranch
pick n678hcn7 Commit on old version DevelopmentBranch
pick mh7y88dr PR merge of DevelopmentBranch where old Branch base were branched out originally, but not where DevelopmentBranch was when old Branch Base was squashed and merged.
pick f79316dc Commit on old Branch base
pick ba742f2f Commit on old Branch base
pick 7577ea7a Commit on old Branch base
pick 91c4088c Commit on old Branch base
pick 98feed6d Commit on old Branch base
pick e8a73d78 Commit on old Branch base
pick 198f79e7 Commit on old Branch base
pick 10bb699c Commit on old Branch base
pick 1d15a926 Commit on old Branch base
pick 0cf569bb Previous commit I want to squash with
pick 470de8d9 Current FeatureBranch commit

But the issue remains.

Possible work-around

I suppose I could try to do a soft reset and amend to the commit I want to squash into:

git reset --soft HEAD~1

But that doesn't fix my current issue of having the git rebase -i HEAD~n history messed up.


回答1:


However, if I then run git rebase -i HEAD~4 I get the old branch's history as well as 11 commits instead of the 4 I asked for:

One of your commits is a merge. Whenever you try to squash [interactive rebase] you will get all the commits. If there is a merge in the middle you will get all the commits form this merge.




回答2:


I just encountered this issue and it turned out I had left my editor open so whenever I ran rebase it was opening it up to the buffer I still had running from the previous rebase. To fix it just close the editor window or kill the process.




回答3:


I just encountered this issue and it turned out I had left my editor open so whenever I ran rebase it was opening it up to the buffer I still had running from the previous rebase.

This has been fixed with Git 2.24 (Q4 2019).
Before, "git rebase -i" showed a wrong HEAD while "reword" open the editor, as discussed here.

See commit b0a3186, commit a47ba3c, commit 450efe2 (19 Aug 2019) by Phillip Wood (phillipwood).
(Merged by Junio C Hamano -- gitster -- in commit 4608a02, 11 Oct 2019)

rebase -i: always update HEAD before rewording

If the user runs git log while rewording a commit, it is confusing if sometimes we're amending the commit that's being reworded and at other times we're creating a new commit depending on whether we could fast-forward or not.
Fix this inconsistency by always committing the picked commit and then running 'git commit --amend' to do the reword.

The first commit is performed by the sequencer without forking git commit and does not impact on the speed of rebase.
In a test rewording 100 commits with

GIT_EDITOR=true GIT_SEQUENCE_EDITOR='sed -i s/pick/reword/' \
../bin-wrappers/git rebase -i --root

and taking the best of three runs the current master took 957ms and with this patch it took 961ms.

This change fixes rewording the new root commit when rearranging commits with --root.

Note that the new code no longer updates CHERRY_PICK_HEAD after creating a root commit - I'm not sure why the old code was that creating that ref after a successful commit, everywhere else it is removed after a successful commit.


It also improves the C version of git rebase:

rebase -i: check for updated todo after squash and reword

While a rebase is stopped for the user to edit a commit message it can be convenient for them to also edit the todo list.
The scripted version of rebase supported this but the C version does not.

We already check to see if the todo list has been updated by an exec command so extend this to rewords and squashes.
It only costs a single stat call to do this so it should not affect the speed of the rebase (especially as it has just stopped for the user to edit a message)

Note that for squashes the editor may be opened on a different pick to the squash itself as we edit the message at the end of a chain fixups and squashes.


But that recent fix also included a regression: While running "revert" or "cherry-pick --edit" for multiple commits, a recent regression incorrectly detected "nothing to commit, working tree clean", instead of replaying the commits, which has been corrected with Git 2.25 (Q1 2020).

See commit befd4f6 (23 Nov 2019) by SZEDER Gábor (szeder).
(Merged by Junio C Hamano -- gitster -- in commit f233c9f, 06 Dec 2019)

sequencer: don't re-read todo for revert and cherry-pick

Reported-by: Brian Norris
Signed-off-by: SZEDER Gábor

When 'git revert' or 'git cherry-pick --edit' is invoked with multiple commits, then after editing the first commit message is finished both these commands should continue with processing the second commit and launch another editor for its commit message, assuming there are no conflicts, of course.

Alas, this inadvertently changed with commit a47ba3c777 ("rebase -i: check for updated todo after squash and reword", 2019-08-19, Git v2.24.0-rc0 -- merge listed in batch #8): after editing the first commit message is finished, both 'git revert' and 'git cherry-pick --edit' exit with error, claiming that "nothing to commit, working tree clean".

The reason for the changed behaviour is twofold:

  • Prior to commit a47ba3c777, the up-to-dateness of the todo list file was only checked after 'exec' instructions, and that commit moved those checks to the common code path.
    The intention was that this check should be performed after instructions spawning an editor ('squash' and 'reword') as well, so the ongoing 'rebase -i' notices when the user runs a 'git rebase --edit-todo' while squashing/rewording a commit message.

However, as it happened that check is now performed even after 'revert' and 'pick' instructions when they involved editing the commit message.
And 'revert' by default while 'pick' optionally (with 'git cherry-pick --edit') involves editing the commit message.

  • When invoking 'git revert' or 'git cherry-pick --edit' with multiple commits they don't read a todo list file but assemble the todo list in memory, thus the associated stat data used to check whether the file has been updated is all zeroed out initially.

Then the sequencer writes all instructions (including the very first) to the todo file, executes the first 'revert/pick' instruction, and after the user finished editing the commit message the changes of a47ba3c777 kick in, and it checks whether the todo file has been modified.
The initial all-zero stat data obviously differs from the todo file's current stat data, so the sequencer concludes that the file has been modified.
Technically it is not wrong, of course, because the file just has been written indeed by the sequencer itself, though the file's contents still match what the sequencer was invoked with in the beginning.

Consequently, after re-reading the todo file the sequencer executes the same first instruction again, thus ending up in that "nothing to commit" situation.

The todo list was never meant to be edited during multi-commit 'git revert' or 'cherry-pick' operations, so perform that "has the todo file been modified" check only when the sequencer was invoked as part of an interactive rebase.



来源:https://stackoverflow.com/questions/48183264/git-rebase-i-shows-wrong-commit-history-after-a-rebase-and-force-push

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!