【问题标题】:How to push a shallow clone to a new repo?如何将浅克隆推送到新的仓库?
【发布时间】:2018-12-02 04:22:47
【问题描述】:

我希望摆脱很多我的 repo 的旧历史,所以我做了一个浅克隆来只获取最后 50 次提交:

git clone --depth=50 https://my.repo

这很好,但是当我创建一个新的 Gitlab 存储库并尝试推送它时,我收到了一个错误:

git remote remove origin
git remote add origin https://my.repo
git push -u origin --all
[...]
 ! [remote rejected] master -> master (shallow update not allowed)

但我只希望这 50 个提交出现在我的新仓库的历史记录中。我如何告诉 git 它应该将这 50 个提交视为新仓库中的唯一提交?

【问题讨论】:

标签: git


【解决方案1】:

您不能将浅层克隆推送到新的遥控器中。你必须先unshallow你的克隆。使用 --unshallow 参数从旧遥控器获取:

git fetch --unshallow old

您应该能够推送到您的新遥控器。请注意,您需要先添加回旧遥控器才能从中获取。

但是...

这不是你想要的。要从完整克隆中删除历史记录,您需要使用 git rebase 来有效删除旧历史记录。还有其他方法,但由于您只需要最后 50 次提交,这将是最简单的解决方案。假设master 分支:

git rebase --onto master~y master~x master

其中x 是要保留的第一个提交的编号,y 是您要删除的第一个提交的编号。此时,您可以只使用您想要保留的历史记录推送到您的新遥控器。请注意,您需要自己枚举git log 中的提交编号,因为它需要一个索引(从 1 开始)而不是提交哈希。


请小心,因为在 Git 中重写历史可能是一件危险的事情,并且您需要考虑其他影响。还要确保不要将更改推送到旧遥控器,除非您也想删除那里的旧历史记录。

来源:https://www.clock.co.uk/insight/deleting-a-git-commit

【讨论】:

  • 对于我的浅回购,我可以使用git checkout --orphan new_master,然后是START_COMMIT=$(git rev-list master|tail -n 1),然后是git checkout $START_COMMIT -- .git commit -m "Initial commit" 使new_master 初始提交与开始时的回购状态相同浅master,然后将master 变基为new_master?这行得通吗?
  • 我不确定是否诚实,但看起来您已经在回答中确认了。我很少重写 repo 历史记录,但在某些情况下,我想做与你相同的事情,保留 X 个最近的提交并删除任何较旧的内容。就我个人而言,我喜欢运行一个命令,但正如我所指出的,你发现,这个问题的解决方案不止一种 :)
【解决方案2】:

这就是我最终做的事情 - 效果很好。请注意,我正在从旧主机(Bitbucket)转移到新主机(Gitlab)。我的 cmets 在命令之上:

# First, shallow-clone the old repo to the depth we want to keep
git clone --depth=50 https://...@bitbucket.org/....git

# Go into the directory of the clone
cd clonedrepo

# Once in the clone's repo directory, remove the old origin
git remote remove origin

# Store the hash of the oldest commit (ie. in this case, the 50th) in a var
START_COMMIT=$(git rev-list master|tail -n 1)

# Checkout the oldest commit; detached HEAD
git checkout $START_COMMIT

# Create a new orphaned branch, which will be temporary
git checkout --orphan temp_branch

# Commit the initial commit for our new truncated history; it will be the state of the tree at the time of the oldest commit (the 50th)
git commit -m "Initial commit"

# Now that we have that initial commit, we're ready to replay all the other commits on top of it, in order, so rebase master onto it, except for the oldest commit whose parents don't exist in the shallow clone... it has been replaced by our 'initial commit'
git rebase --onto temp_branch $START_COMMIT master

# We're now ready to push this to the new remote repo... add the remote...
git remote add origin https://gitlab.com/....git

# ... and push.  We don't need to push the temp branch, only master, the beginning of whose commit chain will be our 'initial commit'
git push -u origin master

在那之后,我对新的 repo 做了一个全新的克隆,我得到了包含 50 个最近提交的 master 分支——这正是我想要的! :-) 提交历史从 250MB 变为 50MB。呜呜呜。

【讨论】:

  • 优秀的解决方案。对于您创建的新“初始提交”,您可能希望覆盖 GIT_AUTHOR_NAMEGIT_AUTHOR_EMAILGIT_AUTHOR_DATE,并将它们设置为您将要替换的提交的原始值。
  • 效果很好,但是似乎这些重新提交的所有现有标签都丢失了 - 知道如何解决这个问题吗?
猜你喜欢
  • 2012-07-07
  • 2015-02-21
  • 1970-01-01
  • 1970-01-01
  • 2020-07-04
  • 2019-08-03
  • 2021-05-31
  • 1970-01-01
  • 2022-09-25
相关资源
最近更新 更多