同步上游的提交时,如何在 Git 中清理提交历史?

Posted

技术标签:

【中文标题】同步上游的提交时,如何在 Git 中清理提交历史?【英文标题】:How Can I Make The Commit History Clean In Git When Sync Upstream's Commit? 【发布时间】:2017-11-22 02:39:47 【问题描述】:

我已经从 GitHub 分叉了一个 repo,并在我的 master 分支上做了一些提交。上游仓库的主分支在我之前有一些提交。所以我需要同步这些提交。

$ git remote -v
origin  git@github.com:johnwatsondev/react-navigation.git (fetch)
origin  git@github.com:johnwatsondev/react-navigation.git (push)
upstream    https://github.com/react-community/react-navigation.git (fetch)
upstream    https://github.com/react-community/react-navigation.git (push)


$ git pull --rebase upstream master
From https://github.com/react-community/react-navigation
 * branch            master     -> FETCH_HEAD
First, rewinding head to replay your work on top of it...
Applying: Update: add logic for invoking back key pressed listener in CardStack.js and remove default process logic
Applying: Update: only android platform need process physical back key pressed event


$ git status
On branch master
Your branch and 'origin/master' have diverged,
and have 6 and 2 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)

nothing to commit, working tree clean


$ git pull
Merge made by the 'recursive' strategy.


$ git status
On branch master
Your branch is ahead of 'origin/master' by 7 commits.
(use "git push" to publish your local commits)

nothing to commit, working tree clean

我在下面的原始仓库的主分支中得到了这个丑陋的提交历史:

如何制作一个优雅的 OP 以将我的原始仓库的主分支同步到上游的主分支没有丑陋的重复提交Merge branch *** 提交? (PS:我在我的原始仓库的主分支中做了一些更改)

【问题讨论】:

你想从远程移除提交? 你应该可以git reset 到第四次提交。 @NanduKalidindi 是的。我想要一种有效的方式来同步上游的提前提交并保持我的原始提交。我在上面附上了我的 OP 命令日志。你能给我一些提示吗? 我不确定我是否完全理解,但如果你想从远程删除提交,AFAIK 你需要通过重置最后三个提交来强制推送。 您可以使用git rebase HEAD~n -i 将之前的n 提交压缩成一个提交,然后选择要压缩的提交和选择的提交。不知道是不是你要找的 【参考方案1】:

正如Squash my last X commits together using Git 中的回答,您可以使用

将之前的 n 提交压缩为单个提交
git rebase HEAD~n -i

当您运行此命令时,将打开一个文本编辑器,您必须将要压缩的所有 n-1 提交前面的 pick 替换为 s。请注意,您必须在挤压后进行强制推动。这样您就可以将多个提交合并为一个。

【讨论】:

就我而言,我使用git rebase HEAD~3 -i。我只是使用 drop 删除两个重复的提交 1a773717827f1c 。我使用pick 保留1359c388ae63e5【参考方案2】:

SO 上已经有很多关于如何重置远程和本地历史记录的答案,但我想你的问题更多是关于如何在拉取期间避免这些丑陋的合并提交。

一般来说,当您想要保持线性历史记录时,您不希望使用默认的拉取行为,否则当同时存在本地和远程更改时,您会得到这种丑陋的合并提交。您应该养成使用git pull -r 在拉取期间使用rebase 而不是合并策略的习惯。

当然,如果您想以特定于分支的方式进行设置,您也可以通过pull.rebase=truebranch.master.rebase=true 为其创建别名或更改默认拉取行为。但是git pull -r 有时会做一些非常神奇的事情,所以我总是对更改默认行为保持警惕。

我喜欢这样做的方式是先通过git fetch 进行显式提取,然后再进行git merge(如果它是快进合并),或者在查看远程更改后进行git rebase。这提供了更多的控制权。事实上git pull(在它的默认行为中)基本上是一个git fetch && git merge,这解释了为什么当有新的本地和远程提交时你会得到一个合并提交。

当然,您也可以在本地非远程跟踪分支上工作,并在主分支上进行显式合并和变基。

【讨论】:

非常感谢,伙计。你有我的问题。您指出了为什么要制作丑陋的提交历史的正确原因。我只是愚蠢地执行了git pull origin master 命令。这才是真正的原因。 如果发生这种情况并且您立即注意到您收到了不需要的合并提交,那也没什么大不了的。只需做一个git reset --merge ORIG_HEAD。只有在推动之后,它才会变得更加复杂。 ORIG_HEAD 引用对于检查 git log ORIG_HEAD.. 等带来的新内容也很有用。【参考方案3】:

如果你想摆脱远程的前三个提交,你需要强制推送来压缩提交。

git reset HEAD~3 git stash save '保存提交更改以防万一' git push origin -f master

也可以查看这篇文章https://ncona.com/2011/07/how-to-delete-a-commit-in-git-local-and-remote/

免责声明:这可能会导致数据丢失。强制推送根本不安全,但这是我知道从远程删除提交的唯一方法。请随时提出可靠的解决方案或编辑更安全的答案。

【讨论】:

非常感谢。我现在已经明确说明了我的问题。 数据丢失在这里不是问题。默认情况下,您可以从 refllog 中恢复旧的提交 90 天。问题是你强迫每个在错误推送和重置期间从这个分支中拉出的开发人员也重置他们的远程参考(如果它是一个大项目,你甚至可能不是每个人,所以你必须在某个地方发布公告) . 我认为他正在尝试在自己的分叉存储库中执行此操作。因为我无法在主存储库中看到任何此类提交。

以上是关于同步上游的提交时,如何在 Git 中清理提交历史?的主要内容,如果未能解决你的问题,请参考以下文章

git-如何同步上游服务的分支

git-如何同步上游服务的分支

git-如何同步上游服务的分支

Git之清除历史记录操作

# Git 大文件清理

Git在rebase时如何保留merge commit(实用!)