从Git的裸存储库中删除文件

时间:2019-02-16 03:58:20

标签: git

有些故事,我们维护了一个提交系统,该系统允许学生将源文件提交到git存储库。这样做有两种选择:对于更高级的学生,我们只是让他们使用git。对于初学者,我们有一个Web界面,允许他们将文件上传到自己的存储库。

Web界面本身是非常基本的,现在仅支持添加文件。我们还希望使学生能够删除,但是,我们需要在裸存储库上进行删除,不进行克隆。考虑到提交系统与之交互的数百个存储库,克隆操作太昂贵且需要太多空间。

我们已经能够弄清楚如何直接将文件添加到树中而不进行克隆。我们还无法找出裸露仓库中的删除部分。我尝试了以下方法。

password

从技术上讲这是可行的,它只是从存储库中删除所有文件,而这并不是我们想要的。我不确定基于git的内部原理如何从树中删除单个blob并更新裸仓库,同时保留其他文件。

有什么想法吗?

1 个答案:

答案 0 :(得分:1)

我想我找到了一个解决方案,我不是特别喜欢它,但是它可以工作。

  1. 使用git log,获取当前HEAD的sha1 ID。
  2. git read-tree --empty,以确保我们可以添加要保留的文件,而不保留我们不保留的文件
  3. git ls-tree -r HEAD
  4. 对于上面返回的每个条目,除了您要删除的条目git update-index -add --cacheinfo <value from ls-tree> <sha1 from ls-tree> <name from ls-tree>
  5. git write-tree保存价值
  6. echo 'removing <file>' | git commit-tree <value from previous command> -p <sha1 of current master HEAD>保存价值
  7. git update-ref refs/heads/master <value from previous command>

如果有人碰巧知道实现此目标的更好方法,我将不知所措。我将附上一个python脚本(使用GitPython),以完成上述任务。

编辑:添加了Python(带有GitPython)

def repo_delete(repo, path: str):
    """Delete the specified file at <path> from the repository."""
    headSha = repo.heads[0].commit.hexsha
    import re
    g = repo.git
    tree = g.ls_tree("-r", "HEAD")
    g.read_tree("--empty")
    for blob in tree.split("\n"):
        blob_parts = re.split("[ \t]", blob)
        if blob_parts[3] != path:
            print(f"adding {blob_parts[3]}")
            g.update_index("--add", "--cacheinfo", blob_parts[0], blob_parts[2], blob_parts[3])
    treeSha = g.write_tree()
    newHeadSha = g.commit_tree(treeSha, "-m", f'"removing {path}"', "-p", headSha)
    g.update_ref("refs/heads/master", newHeadSha)
    print("done")