代码之家  ›  专栏  ›  技术社区  ›  Tobias Kienzler

如何将过去的内容预存到git存储库中?

git
  •  22
  • Tobias Kienzler  · 技术社区  · 14 年前

    我收到了一些源代码并决定使用git,因为我的同事使用了 mkdir $VERSION 等方法。虽然过去的代码现在看来并不重要,但我还是希望将其置于git的控制之下,以便更好地理解开发过程。所以:

    4 回复  |  直到 10 年前
        1
  •  27
  •   Tobias Kienzler    11 年前

    对于导入旧快照,您可以在中找到一些工具 Git's contrib/fast-import directory 有用。或者,如果目录中已有每个旧快照,则可以执行以下操作:

    # Assumes the v* glob will sort in the right order
    # (i.e. zero padded, fixed width numeric fields)
    # For v1, v2, v10, v11, ... you might try:
    #     v{1..23}     (1 through 23)
    #     v?{,?}       (v+one character, then v+two characters)
    #     v?{,?{,?}}   (v+{one,two,three} characters)
    #     $(ls -v v*)  (GNU ls has "version sorting")
    # Or, just list them directly: ``for d in foo bar baz quux; do''
    (git init import)
    for d in v*; do
        if mv import/.git "$d/"; then
            (cd "$d" && git add --all && git commit -m"pre-Git snapshot $d")
            mv "$d/.git" import/
        fi
    done
    (cd import && git checkout HEAD -- .)
    

    cd work && git fetch ../import master:old-history
    

    在同一个存储库中同时拥有旧历史和基于Git的历史之后,就有了几个prepend操作的选项:嫁接和替换。

    $GIT_DIR/info/grafts 文件(在 gitrepository-layout manpage

    INITIAL_SHA1=$(git rev-list --reverse master | head -1)
    TIP_OF_OLD_HISTORY_SHA1=$(git rev-parse old-history)
    echo $INITIAL_SHA1 $TIP_OF_OLD_HISTORY_SHA1 >> .git/info/grafts
    

    移植就位后(最初的初始提交没有任何父级,移植给它一个父级),您可以使用所有正常的Git工具来搜索和查看扩展历史(例如。 git log 现在应该在提交后向您显示旧的历史记录)。

    嫁接的主要问题是它们仅限于您的存储库。但是,如果你决定它们应该成为历史的永久部分,你可以使用 git筛选器分支 .git dir优先; 将保存原始引用,但有时使用普通备份更容易)。

    git filter-branch --tag-name-filter cat -- --all
    rm .git/info/grafts
    

    替换机制较新(Git) 1.6.5 git --no-replace-objects … )他们可以推动更容易的分享。替换作用于单个对象(blob、树、提交或带注释的标记),因此该机制也更通用。替换机制记录在 git replace manpage

    # the last commit of old history branch
    oldhead=$(git rev-parse --verify old-history)
    # the initial commit of current branch
    newinit=$(git rev-list master | tail -n 1)
    # create a fake commit based on $newinit, but with a parent
    # (note: at this point, $oldhead must be a full commit ID)
    newfake=$(git cat-file commit "$newinit" \
            | sed "/^tree [0-9a-f]\+\$/aparent $oldhead" \
            | git hash-object -t commit -w --stdin)
    # replace the initial commit with the fake one
    git replace -f "$newinit" "$newfake"
    

    共享此替换不是自动的。你必须推一部分(或全部) refs/replace 分享替代品。

    git push some-remote 'refs/replace/*'
    

    git筛选器分支 (与移植物相同;做一个tar/zip备份 吉特 目录优先):

    git filter-branch --tag-name-filter cat -- --all
    git replace -d $INITIAL_SHA1
    
        2
  •  3
  •   Andrew Aylett    14 年前

    如果不想更改存储库中的提交,可以使用嫁接覆盖提交的父信息。这就是Linux内核repo在开始使用Git之前用来获取历史记录的方法。

    此消息: http://marc.info/?l=git&m=119636089519572 似乎有我能找到的最好的文件。

    您将创建一系列与git之前的历史记录相关的提交,然后使用 .git/info/grafts 文件,使Git使用该序列中的最后一个提交作为使用Git生成的第一个提交的父级。

        3
  •  2
  •   Tobias Kienzler    14 年前

        4
  •  0
  •   Evandro Coan    6 年前

    如果您只想永久合并2个存储库,最好的解决方案是从第二个存储库导出所有提交(初始提交除外,它将存储库创建为另一个存储库的延续)。

    Chris Johnsen ,它将您在第二个存储库上的初始提交转换为删除提交,删除多个文件。如果您尝试跳过初始提交,它会将第二次提交转换为删除所有文件的提交(当然,我必须尝试)。我不确定它如何影响git跟踪命令中的文件历史的能力 git log --follow -- file/name.txt

    您可以导出第二个存储库的整个历史记录(第一次提交除外,它已经存在于第一个存储库中),并在第一个存储库中导入它,运行以下命令:

    1. 在第二个存储库中打开Linux命令行(以导出最新提交)
    2. commit_count=$(git rev-list HEAD --count)
    3. git format-patch --full-index -$(($commit_count - 1))
    4. .patch patches 在第一个存储库根目录的一侧
    5. 现在,在第一个存储库上打开一个Linux命令行(以导入最新的提交)
    6. git am ../patches/*.patch
    7. 如果在应用git修补程序时遇到问题,请运行 git am --abort git: patch does not apply 尝试一下 git am ../patches/*.patch --ignore-space-change --ignore-whitespace

    或者使用 git 从命令行,您可以使用git接口,如 SmartGit GitExtensions

    参考文献:

    1. https://www.ivankristianto.com/create-patch-files-from-multiple-commits-in-git/
    2. Git: How to create patches for a merge?
    3. how to apply multiple git patches in one shot
    4. https://davidwalsh.name/git-export-patch

    为了完整起见,这里我提供了一个自动shell脚本,如下所示 克里斯·约翰森 永久合并2存储库的步骤。您需要在第一个存储库上运行它,您希望在其中集成来自第二个存储库的历史,这将继续来自第一个存储库的历史。经过几个小时的实验,我发现这是最好的方法。如果你知道如何改进,请修改/分享/评论。

    请将第一个和第二个存储库完全备份到 .zip 在运行此操作之前。

    old_history=master
    new_history=master-temp
    
    old_remote_name=deathaxe
    old_remote_url=second_remote_url
    
    git remote add $old_remote_name $old_remote_url
    git fetch $old_remote_name
    git branch --no-track $new_history refs/remotes/$old_remote_name/$old_history
    git branch --set-upstream-to=origin/$old_history $new_history
    
    # the last commit of old history branch
    oldhead=$(git rev-parse --verify $old_history)
    
    # the initial commit of current branch
    # newinit=$(git rev-list $new_history | tail -n 2 | head -n -1)
    newinit=$(git rev-list $new_history | tail -n 1)
    
    # create a fake commit based on $newinit, but with a parent
    # (note: at this point, $oldhead must be a full commit ID)
    newfake=$(git cat-file commit "$newinit" \
            | sed "/^tree [0-9a-f]\+\$/aparent $oldhead" \
            | git hash-object -t commit -w --stdin)
    
    # replace the initial commit with the fake one
    # git replace <last commit> <first commit>
    # git replace <object> <replacement>
    git replace -f "$newinit" "$newfake"
    
    # If you decide to make the replacement permanent, use git filter-branch
    # (make a tar/zip backup of your .git directory first)
    git filter-branch --tag-name-filter cat -- --all
    git replace -d $newinit
    
    git push -f --tags
    git push -f origin $new_history
    
    git checkout $old_history
    git branch -d $new_history
    git pull --rebase
    

    1. https://feeding.cloud.geek.nz/posts/combining-multiple-commits-into-one/
    2. https://mirrors.edge.kernel.org/pub/software/scm/git/docs/git-replace.html
    3. Remove the last line from a file in Bash
    4. Force "git push" to overwrite remote files
    5. Git force push tag when the tag already exists on remote