如何将过去预先添加到git存储库?

如何将过去预先添加到git存储库?,git,Git,我收到一些源代码,并决定使用git,因为我的同事使用了mkdir$VERSION等方法。虽然代码的过去现在看起来并不重要,但我仍然希望将其置于git的控制之下,以便更好地理解开发过程。因此: 将这些过去的版本放入我已经存在的git repo中的方便方法是什么?目前还没有远程repo,所以我不介意重写历史,但是一个考虑到远程存储库的解决方案当然会是首选,除非它当时更加复杂。对于不需要基于目录或基于归档文件的历史记录进行更多交互的脚本,可以获得额外的积分。最简单的方法当然是创建一个新的git rep

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


将这些过去的版本放入我已经存在的git repo中的方便方法是什么?目前还没有远程repo,所以我不介意重写历史,但是一个考虑到远程存储库的解决方案当然会是首选,除非它当时更加复杂。对于不需要基于目录或基于归档文件的历史记录进行更多交互的脚本,可以获得额外的积分。

最简单的方法当然是创建一个新的git repo,首先提交历史记录,然后重新应用旧repo的补丁。但是我更喜欢一种自动化时间更少的解决方案。

对于导入旧快照,您会发现其中一些工具非常有用。或者,如果目录中已有每个旧快照,则可以执行以下操作:

#假设v*glob将按正确的顺序排序
#(即零填充、固定宽度的数字字段)
#对于v1、v2、v10、v11。。。您可以尝试:
#v{1..23}(1到23)
#v{,,}(v+一个字符,然后v+两个字符)
#v{、{、}、}(v+{1、2、3}个字符)
#$(ls-v*)(GNULS有“版本排序”)
#或者,直接列出它们:``在foo bar baz quux中代表d;“做”
(git初始化导入)
对于v*中的d;做
如果mv import/.git“$d/”;然后
(cd“$d”和&git-add--all和&git-commit-m“git快照$d之前”)
mv“$d/.git”导入/
fi
完成
(cd导入和git签出头--)
然后将旧历史记录提取到您的工作存储库中:

cd工作和git获取../import master:旧历史记录

在同一个存储库中既有旧的历史记录又有基于Git的历史记录之后,就有了两个prepend操作选项:嫁接和替换

嫁接是一种每个存储库的机制,用于(可能暂时)编辑各种现有提交的父级。嫁接由
$GIT_DIR/info/Grafts
文件控制(在的“info/Grafts”下描述)

INITIAL_SHA1=$(git版本列表——反向主控|头-1)
TIP_OF_OLD_HISTORY_SHA1=$(git rev parse OLD HISTORY)
echo$INITIAL\u SHA1$TIP\u OF_OLD\u HISTORY\u SHA1>>。git/info/grafts
移植到位后(最初的初始提交没有任何父级,移植给了它一个父级),您可以使用所有普通的Git工具来搜索和查看扩展的历史记录(例如,
Git log
现在应该在提交后向您显示旧的历史记录)

嫁接的主要问题是它们仅限于您的存储库。但是,如果您决定它们应该成为历史的永久部分,那么可以使用git filter分支来实现(首先对
.git
dir进行tar/zip备份;git filter分支将保存原始引用,但有时使用普通备份更容易)

git过滤器分支--标记名过滤器类别--all
rm.git/info/grafts

替换机制较新(Git+),但可以在每个命令的基础上禁用它们(
Git——无替换对象…
),并且可以推送它们以便于共享。替换适用于单个对象(blob、树、提交或带注释的标记),因此该机制也更通用。更换机制记录在中。由于通用性,“prepending”设置更为复杂(我们必须创建一个新的提交,而不仅仅是命名新的父级):

#旧历史分支的最后一次提交
oldhead=$(git版本解析——验证旧历史)
#当前分支的初始提交
newinit=$(git版本列表主目录| tail-n1)
#基于$newinit创建一个假提交,但使用父级
#(注意:此时,$oldhead必须是完整的提交ID)
newfake=$(git cat文件提交“$newinit”\
|sed“^tree[0-9a-f]\+\$/aparent$oldhead”\
|git散列对象-t提交-w--stdin)
#用伪提交替换初始提交
git replace-f“$newinit”“$newfake”
共享此替换不是自动的。您必须推送部分(或全部)
refs/replace
以共享替换

git推送一些远程“refs/replace/*”
如果决定永久替换,请使用git筛选器分支(与grafts相同;首先对
.git
目录进行tar/zip备份):

git过滤器分支--标记名过滤器类别--all
git替换-d$INITIAL_SHA1

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

这条信息:似乎有我能找到的最好的文档


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

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

我认为这是最好的,因为当您执行中解释的步骤时,它会将您在第二个存储库上的初始提交转换为删除提交,删除多个文件。如果您尝试跳过初始提交,它会将第二次提交转换为删除所有文件的提交(当然,我必须尝试)。我不确定它如何影响git跟踪命令中文件历史记录的能力,如
git log--follow--file/name.txt

您可以导出整个历史记录(fi除外)
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