[原創] How to pull code when shared repo commit history has been changed

hustnzj發表於2022-09-01

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):

在本地修改了提交歷史,再強制push到上游hou,其他開發者應該如何拉取程式碼

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.
在本地修改了提交歷史,再強制push到上游hou,其他開發者應該如何拉取程式碼

本作品採用《CC 協議》,轉載必須註明作者和本文連結
日拱一卒

相關文章