The whole story
Let’s pretend Mary and I are collaborating by Git.
Firstly, in my office PC, I committed my local changes to my local and pushed them into the central repo(upstream), then Mary pulled them into her repo.
Then, I went home, pulled the repo onto my laptop. But I found my Email address in the commits was not correct so I rewrote all my Email addresses in commit history by filter-repo
which is a good tool to rewrite commit history. Then I pushed, it turned out that my repo and remote repo were divergent. Without further ado, I pushed with -f
. Oh, my God! What have I done? It’s late so I went to bed.
Tomorrow, when Mary pulled from the upstream, the command line complained that You have divergent branches and need to specify how to reconcile them.
git:(master) $ git status
On branch master
Your branch and 'origin/master' have diverged,
and have 26 and 27 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)
git:(master) $ git pull
hint: You have divergent branches and need to specify how to reconcile them.
hint: You can do so by running one of the following commands sometime before
hint: your next pull:
hint:
hint: git config pull.rebase false # merge
hint: git config pull.rebase true # rebase
hint: git config pull.ff only # fast-forward only
hint:
hint: You can replace "git config" with "git config --global" to set a default
hint: preference for all repositories. You can also pass --rebase, --no-rebase,
hint: or --ff-only on the command line to override the configured default per
hint: invocation.
fatal: Need to specify how to reconcile divergent branches.
Mary used git log master..origin/master
and found the huge divergence between her local repo and the remote repo!
To make this clear, we can refer to the picture as below (The left is remote repo, the right is Mary’s repo and they are all output by git log --reverse --online
):
They are almost the same but the commitID as filter-repo
will change the commitID when it rewrote the commit history.
From the tip, Mary tried to run git pull --rebase
.
warning: skipped previously applied commit fd24aaa
warning: skipped previously applied commit be753ff
warning: skipped previously applied commit 6d2604d
warning: skipped previously applied commit b5d4bad
warning: skipped previously applied commit 16ad5d3
warning: skipped previously applied commit 29e3d91
warning: skipped previously applied commit 0de1df1
warning: skipped previously applied commit 72a3391
warning: skipped previously applied commit 70641bd
warning: skipped previously applied commit 42c8214
warning: skipped previously applied commit b4d098b
warning: skipped previously applied commit ce59055
warning: skipped previously applied commit 830f3e6
warning: skipped previously applied commit 49a8f47
warning: skipped previously applied commit 0983fe6
warning: skipped previously applied commit 4f4d6cc
warning: skipped previously applied commit c2300cb
warning: skipped previously applied commit ff7f6c0
warning: skipped previously applied commit fff89ff
warning: skipped previously applied commit 41a835c
warning: skipped previously applied commit 1fd8a50
warning: skipped previously applied commit b1c2d16
warning: skipped previously applied commit 48dd927
warning: skipped previously applied commit 07ac7eb
hint: use --reapply-cherry-picks to include skipped commits
hint: Disable this message with "git config advice.skippedCherryPicks false"
Successfully rebased and updated refs/heads/master.
Done! It’s Magic!
Understand the magic under the hood
git pull --rebase
rebase the current branch on top of the upstream branch after fetching.
Note that any commits in HEAD which introduce the same textual changes as a commit in HEAD..<upstream>
(i.e., not in HEAD but in the upstream) are omitted (i.e., a patch already accepted upstream with a different commit message or timestamp will be skipped).
Because most of the commits on the upstream and local repo are the same except the commitID.
So all the commits of upstream were pulled and all original commits with the same textual contents in the local repo were skipped.
Now the local and remote repo are synced.
本作品採用《CC 協議》,轉載必須註明作者和本文連結