我目前有一个本地 Git 存储库,我将其推送到 Github 存储库。
本地存储库有大约 10 个提交,Github 存储库是它的同步副本。
我想做的是从本地 Git 存储库中删除所有版本历史记录,因此存储库的当前内容显示为唯一的提交(因此不会存储存储库中旧版本的文件)。
然后我想将这些更改推送到 Github。
我调查了 Git rebase,但这似乎更适合删除特定版本。另一个可能的解决方案是删除本地 repo,然后创建一个新的——尽管这可能会产生很多工作!
ETA:有特定的目录/文件未跟踪 - 如果可能的话,我想保持这些文件的未跟踪。
这是蛮力方法。它还删除了存储库的配置。
注意:如果存储库有子模块,这将不起作用!如果您正在使用子模块,则应使用例如 interactive rebase
第 1 步:删除所有历史记录(确保您有备份,这无法恢复)
cat .git/config # note <github-uri>
rm -rf .git
第 2 步:仅使用当前内容重建 Git 存储库
git init
git add .
git commit -m "Initial commit"
第三步:推送到 GitHub。
git remote add origin <github-uri>
git push -u --force origin main
唯一适合我的解决方案(并使子模块保持工作)是
git checkout --orphan newBranch
git add -A # Add all files and commit them
git commit
git branch -D master # Deletes the master branch
git branch -m master # Rename the current branch to master
git push -f origin master # Force push master branch to github
git gc --aggressive --prune=all # remove the old files
当我有子模块时,删除 .git/
总是会导致巨大的问题。使用 git rebase --root
会以某种方式对我造成冲突(并且需要很长时间,因为我有很多历史记录)。
git push -f origin master
作为最后一个操作,阳光就会再次照耀您的新回购! :)
git gc --aggressive --prune=all
。此外,git 将继续存储使用分支或标签引用的任何提交的历史记录。要检查,请运行 git tag -l
和 git branch -v
,然后删除您找到的任何内容。还要使用 git ls-remote
仔细检查您的遥控器,您可能还需要删除远程标签/分支,或者当您获取时,您将再次获得所有链接的文件。
git gc --aggressive --prune all
,就会错过失去历史的全部意义。
这是我最喜欢的方法:
git branch new_branch_name $(echo "commit message" | git commit-tree HEAD^{tree})
这将使用一个提交创建一个新分支,该提交会在 HEAD 中添加所有内容。它不会改变其他任何东西,所以它是完全安全的。
git-rev-parse
文档中。这里发生的是 git-commit-tree
需要引用树(repo 的快照),但 HEAD
是修订版。要查找与提交关联的树,我们使用 <rev>^{<type>}
表单。
git push --force <remote> new_branch_name:<remote-branch>
git branch newbranch $(echo "commit message" | git commit-tree HEAD^{tree}) | git push --force origin newbranch:master
如果您有很多提交,另一个选项可能会产生大量工作,它是交互式 rebase(假设您的 git 版本是 >=1.7.12):git rebase --root -i
当在编辑器中显示提交列表时:
将第一次提交的“pick”更改为“reword”
每隔一次提交将“pick”更改为“fixup”
保存并关闭。 Git 将开始变基。
最后,您将获得一个新的根提交,它是其后所有提交的组合。
优点是您不必删除存储库,并且如果您有第二个想法,您总是有一个后备。
如果你真的想删除你的历史记录,请将 master 重置为此提交并删除所有其他分支。
error: failed to push some refs to
git push --force-with-lease
。使用 force-with-lease 是因为它的破坏性低于 --force。
larsmans 提出的方法的变体:
保存您的 untrackfiles 列表:
git ls-files --others --exclude-standard > /tmp/my_untracked_files
保存你的 git 配置:
mv .git/config /tmp/
然后执行 larsmans 的第一步:
rm -rf .git
git init
git add .
恢复你的配置:
mv /tmp/config .git/
取消跟踪您未跟踪的文件:
cat /tmp/my_untracked_files | xargs -0 git rm --cached
然后提交:
git commit -m "Initial commit"
最后推送到您的存储库:
git push -u --force origin master
以下是改编自@Zeelot 答案的脚本。它应该从所有分支中删除历史记录,而不仅仅是主分支:
for BR in $(git branch); do
git checkout $BR
git checkout --orphan ${BR}_temp
git commit -m "Initial commit"
git branch -D $BR
git branch -m $BR
done;
git gc --aggressive --prune=all
它适用于我的目的(我没有使用子模块)。
git branch
将在您签出的分支旁边包含一个星号,然后将其通配,使其解析为所有文件或文件夹,就好像它们也是分支名称一样。相反,我使用了 git branch --format="%(refname:lstrip=2)"
,它只给了我分支名称。
git push --force origin master
还是 git push --force-with-lease
?显然后者更安全(参见stackoverflow.com/questions/5509543/…)
您可以使用浅 clones (git > 1.9):
git clone --depth depth remote-url
进一步阅读:http://blogs.atlassian.com/2014/05/handle-big-repositories-git/
我想做的是从本地 Git 存储库中删除所有版本历史记录,因此存储库的当前内容显示为唯一的提交(因此不会存储存储库中旧版本的文件)。
一个更具概念性的答案:
如果没有标签/分支/引用指向它们,git 会自动垃圾收集旧提交。因此,您只需删除所有标签/分支并创建一个与任何分支关联的新孤儿提交 - 按照惯例,您应该让分支 master
指向该提交。
除非他们使用低级 git 命令进行挖掘,否则任何人都不会再看到旧的、无法访问的提交。如果这对你来说已经足够了,我就停在那里,让自动 GC 随时完成它的工作。如果您想立即摆脱它们,可以使用 git gc
(可能与 --aggressive --prune=all
一起使用)。对于远程 git 存储库,您无法强制执行此操作,除非您具有对其文件系统的 shell 访问权限。
只需删除 Github 存储库并创建一个新存储库。迄今为止最快、最简单、最安全的方法。毕竟,当您想要的只是带有单个提交的主分支时,您必须在公认的解决方案中执行所有这些命令吗?
git filter-branch
是大手术工具。
git filter-branch --parent-filter true -- @^!
--parent-filter
在标准输入上获取父母,并应在标准输出上打印重写的父母; unix true
成功退出并且什么也不打印,所以:没有父母。 @^!
是 Git shorthand for “头部提交,但不是它的任何父母”。然后删除所有其他 refs 并在闲暇时推送。
下面的方法是完全可以重现的,所以如果双方一致就不需要再次运行clone,只需在另一边运行脚本即可。
git log -n1 --format=%H >.git/info/grafts
git filter-branch -f
rm .git/info/grafts
如果你想清理它,试试这个脚本:
http://sam.nipl.net/b/git-gc-all-ferocious
我为存储库中的每个分支编写了一个“杀死历史”的脚本:
http://sam.nipl.net/b/git-kill-history
另见:http://sam.nipl.net/b/confirm
git-hash: not found
和 Support for <GIT_DIR>/info/grafts is deprecated
git log HEAD~${1:-0} -n1 --format=%H
,在这里,sam.aiki.info/b/git-hash 最好将它们全部放在一个脚本中供公众使用。如果我再次使用它,我可能会想出如何使用替换“grafts”的新功能来做到这一点。
干得好:
#!/bin/bash
#
# By Zibri (2019)
#
# Usage: gitclean username password giturl
#
gitclean ()
{
odir=$PWD;
if [ "$#" -ne 3 ]; then
echo "Usage: gitclean username password giturl";
return 1;
fi;
temp=$(mktemp -d 2>/dev/null /dev/shm/git.XXX || mktemp -d 2>/dev/null /tmp/git.XXX);
cd "$temp";
url=$(echo "$3" |sed -e "s/[^/]*\/\/\([^@]*@\)\?\.*/\1/");
git clone "https://$1:$2@$url" && {
cd *;
for BR in "$(git branch|tr " " "\n"|grep -v '*')";
do
echo working on branch $BR;
git checkout $BR;
git checkout --orphan $(basename "$temp"|tr -d .);
git add -A;
git commit -m "Initial Commit" && {
git branch -D $BR;
git branch -m $BR;
git push -f origin $BR;
git gc --aggressive --prune=all
};
done
};
cd $odir;
rm -rf "$temp"
}
也在此处托管:https://gist.github.com/Zibri/76614988478a076bbe105545a16ee743
这将删除 master
分支上的历史记录(您可能需要在运行命令之前进行备份):
git branch tmp_branch $(echo "commit message" | git commit-tree HEAD^{tree})
git checkout tmp_branch
git branch -D master
git branch -m master
git push -f --set-upstream origin master
这是基于@dan_waterworth 的回答。
以下是清除 Github 存储库历史记录的步骤
首先,从 .git 中删除历史记录
rm -rf .git
现在,仅从当前内容重新创建 git repos
git init
git add .
git commit -m "Initial commit"
推送到 Github 远程仓库,确保您覆盖历史记录
git remote add origin git@github.com:<YOUR ACCOUNT>/<YOUR REPOS>.git
git push -u --force origin master
community wiki
答案有何不同,或者以其他方式增加价值?
我通过从我的项目中删除 .git
文件夹并通过 IntelliJ 重新集成版本控制解决了类似的问题。注意:.git
文件夹是隐藏的。您可以使用 ls -a
在终端中查看它,然后使用 rm -rf .git
将其删除。
为此,使用 Shallow Clone 命令 git clone --depth 1 URL - 它只会克隆存储库的当前 HEAD
要从 git 中删除最后一次提交,您可以简单地运行
git reset --hard HEAD^
如果要从顶部删除多个提交,则可以运行
git reset --hard HEAD~2
删除最后两个提交。您可以增加数量以删除更多提交。
Git tutoturial here 提供有关如何清除存储库的帮助:
您想从历史记录中删除该文件并将其添加到 .gitignore 以确保它不会意外重新提交。对于我们的示例,我们将从 GitHub gem 存储库中删除 Rakefile。
git clone https://github.com/defunkt/github-gem.git
cd github-gem
git filter-branch --force --index-filter \
'git rm --cached --ignore-unmatch Rakefile' \
--prune-empty --tag-name-filter cat -- --all
现在我们已经从历史记录中删除了该文件,让我们确保我们不会再次意外提交它。
echo "Rakefile" >> .gitignore
git add .gitignore
git commit -m "Add Rakefile to .gitignore"
如果您对存储库的状态感到满意,则需要强制推送更改以覆盖远程存储库。
git push origin master --force
.gitignore
应该处理这些,对吗?