ChatGPT解决这个技术问题 Extra ChatGPT

使当前提交成为 Git 存储库中的唯一(初始)提交?

我目前有一个本地 Git 存储库,我将其推送到 Github 存储库。

本地存储库有大约 10 个提交,Github 存储库是它的同步副本。

我想做的是从本地 Git 存储库中删除所有版本历史记录,因此存储库的当前内容显示为唯一的提交(因此不会存储存储库中旧版本的文件)。

然后我想将这些更改推送到 Github。

我调查了 Git rebase,但这似乎更适合删除特定版本。另一个可能的解决方案是删除本地 repo,然后创建一个新的——尽管这可能会产生很多工作!

ETA:有特定的目录/文件未跟踪 - 如果可能的话,我想保持这些文件的未跟踪。


8
8 revs, 5 users 51%

这是蛮力方法。它还删除了存储库的配置。

注意:如果存储库有子模块,这将不起作用!如果您正在使用子模块,则应使用例如 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

谢谢 larsmans - 我选择使用它作为我的解决方案。尽管初始化 Git 存储库会丢失旧存储库中未跟踪文件的记录,但这对于我的问题可能是一个更简单的解决方案。
@kaese:我认为您的 .gitignore 应该处理这些,对吗?
之前保存你的 .git/config,然后恢复它。
如果您尝试删除敏感数据,请注意这一点:新推送的主分支中仅存在一个提交是误导性的 - 历史仍然存在,只是无法从该分支访问。例如,如果您有指向旧提交的标签,则可以访问这些提交。事实上,对于任何有点 git foo 的人来说,我确信在这次 git push 之后,他们仍然能够从 GitHub 存储库中恢复所有历史记录——如果你有其他分支或标签,那么他们就没有甚至需要很多 git foo。
世界上有这么多不好的答案,一个小时后,我终于得到了这个来做我的竞标!
M
MatthewG

唯一适合我的解决方案(并使子模块保持工作)是

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 作为最后一个操作,阳光就会再次照耀您的新回购! :)
@JonePolvora git fetch; git reset --hard origin/master stackoverflow.com/questions/4785107/…
这样做之后,回购会释放空间吗?
Git 将保留旧文件一段时间,以摆脱它们运行 git gc --aggressive --prune=all。此外,git 将继续存储使用分支或标签引用的任何提交的历史记录。要检查,请运行 git tag -lgit branch -v,然后删除您找到的任何内容。还要使用 git ls-remote 仔细检查您的遥控器,您可能还需要删除远程标签/分支,或者当您获取时,您将再次获得所有链接的文件。
我相信您应该将@JasonGoemaat 的建议作为答案的最后一行添加。如果没有 git gc --aggressive --prune all,就会错过失去历史的全部意义。
d
dan_waterworth

这是我最喜欢的方法:

git branch new_branch_name $(echo "commit message" | git commit-tree HEAD^{tree})

这将使用一个提交创建一个新分支,该提交会在 HEAD 中添加所有内容。它不会改变其他任何东西,所以它是完全安全的。


最好的方法!清除,并做工作。此外,我将分支重命名,从“master”到“local-work”和“new_branch_name”到“master”进行了很多更改。在 master 中,执行以下操作: git -m local-changes git branch -m local-changes git checkout new_branch_name git branch -m master<
这看起来真的很短而且很圆滑,我唯一不明白或还没有看到的是 HEAD^{tree},有人可以解释一下吗?除此之外,我将其读作“从给定的提交创建新分支,通过使用来自___的给定提交消息创建一个新的提交对象来创建”
寻找有关 git 参考语法问题的答案的权威位置在 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
C
Carl

如果您有很多提交,另一个选项可能会产生大量工作,它是交互式 rebase(假设您的 git 版本是 >=1.7.12):git rebase --root -i

当在编辑器中显示提交列表时:

将第一次提交的“pick”更改为“reword”

每隔一次提交将“pick”更改为“fixup”

保存并关闭。 Git 将开始变基。

最后,您将获得一个新的根提交,它是其后所有提交的组合。

优点是您不必删除存储库,并且如果您有第二个想法,您总是有一个后备。

如果你真的想删除你的历史记录,请将 master 重置为此提交并删除所有其他分支。


变基完成后,我无法推送:error: failed to push some refs to
@Begueradj 如果您已经推送了重新设置的分支,那么您将需要强制推送 git push --force-with-lease。使用 force-with-lease 是因为它的破坏性低于 --force。
e
emotality

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

S
Shafique Jamal

以下是改编自@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

它适用于我的目的(我没有使用子模块)。


我想你忘了强制 push master 完成这个过程。
我不得不稍作修改。 git branch 将在您签出的分支旁边包含一个星号,然后将其通配,使其解析为所有文件或文件夹,就好像它们也是分支名称一样。相反,我使用了 git branch --format="%(refname:lstrip=2)",它只给了我分支名称。
@not2qubit:谢谢。确切的命令是什么? git push --force origin master 还是 git push --force-with-lease?显然后者更安全(参见stackoverflow.com/questions/5509543/…
@本理查兹。有趣的。我会在某个时候再次尝试使用与分支名称匹配的文件夹来测试它,然后更新答案。谢谢。
M
Matthias M

您可以使用浅 clones (git > 1.9):

git clone --depth depth remote-url

进一步阅读:http://blogs.atlassian.com/2014/05/handle-big-repositories-git/


此类克隆无法推送到新存储库。
知道如何规避这种限制会很有用。有人可以解释为什么不能强制推动吗?
您的问题的答案:stackoverflow.com/questions/6900103/…
A
AnoE

我想做的是从本地 Git 存储库中删除所有版本历史记录,因此存储库的当前内容显示为唯一的提交(因此不会存储存储库中旧版本的文件)。

一个更具概念性的答案:

如果没有标签/分支/引用指向它们,git 会自动垃圾收集旧提交。因此,您只需删除所有标签/分支并创建一个与任何分支关联的新孤儿提交 - 按照惯例,您应该让分支 master 指向该提交。

除非他们使用低级 git 命令进行挖掘,否则任何人都不会再看到旧的、无法访问的提交。如果这对你来说已经足够了,我就停在那里,让自动 GC 随时完成它的工作。如果您想立即摆脱它们,可以使用 git gc(可能与 --aggressive --prune=all 一起使用)。对于远程 git 存储库,您无法强制执行此操作,除非您具有对其文件系统的 shell 访问权限。


很好的补充,在@Zeelot 的回答中看到。
是的,Zeelot 的命令基本上可以做到这一点(只是不同的是,完全重新开始,这对 OP 来说可能很好)。 @MogensTrasherDK
J
Johann

只需删除 Github 存储库并创建一个新存储库。迄今为止最快、最简单、最安全的方法。毕竟,当您想要的只是带有单个提交的主分支时,您必须在公认的解决方案中执行所有这些命令吗?


要点之一是能够看到它是从哪里分叉的。
我刚做了这个,很好
j
jthill

git filter-branch 是大手术工具。

git filter-branch --parent-filter true -- @^!

--parent-filter 在标准输入上获取父母,并应在标准输出上打印重写的父母; unix true 成功退出并且什么也不打印,所以:没有父母。 @^!Git shorthand for “头部提交,但不是它的任何父母”。然后删除所有其他 refs 并在闲暇时推送。


S
Sam Watkins

下面的方法是完全可以重现的,所以如果双方一致就不需要再次运行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 foundSupport for <GIT_DIR>/info/grafts is deprecated
@ShafiqueJamal,谢谢,小“git-hash”脚本是 git log HEAD~${1:-0} -n1 --format=%H,在这里,sam.aiki.info/b/git-hash 最好将它们全部放在一个脚本中供公众使用。如果我再次使用它,我可能会想出如何使用替换“grafts”的新功能来做到这一点。
Z
Zibri

干得好:

#!/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


呸!不要让我在命令行中提供我未隐藏、不受保护的密码!此外, git branch 的输出通常不适合编写脚本。您可能想查看管道工具。
T
Tom Dörr

这将删除 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 的回答。


K
Kapilrc

以下是清除 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 答案有何不同,或者以其他方式增加价值?
J
JB Lovell

我通过从我的项目中删除 .git 文件夹并通过 IntelliJ 重新集成版本控制解决了类似的问题。注意:.git 文件夹是隐藏的。您可以使用 ls -a 在终端中查看它,然后使用 rm -rf .git 将其删除。


这就是他在第 1 步中所做的: rm -rf .git ?
k
kkarki

为此,使用 Shallow Clone 命令 git clone --depth 1 URL - 它只会克隆存储库的当前 HEAD


k
kiriloff

要从 git 中删除最后一次提交,您可以简单地运行

git reset --hard HEAD^ 

如果要从顶部删除多个提交,则可以运行

git reset --hard HEAD~2 

删除最后两个提交。您可以增加数量以删除更多提交。

More info here.

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

从存储库中删除文件或提交与问题绝对没有关系(它要求删除历史,完全不同的事情)。 OP 想要一个干净的历史记录,但想要保留存储库的当前状态。
这不会产生问题中提出的结果。您将在最后一次提交后丢弃所有更改并丢失此后的所有更改,但问题要求保留当前文件并删除历史记录。