0

我一直跟踪childrepo 中的文件。但现在我还需要跟踪另一个child,所以我将它们重命名为child1and child2。我只想维护一个parent包含两个文件夹的目录,但我不想丢失来自childrepo 的提交。

前:

/
/docs/
/docs/child/
/docs/child/.git/           # repo at child level
/docs/child/file-a
/docs/child/file-b

后:

/
/docs/
/docs/parent/
/docs/parent/.git/          # parent repo contains all files and child1 commits
/docs/parent/child1/
/docs/parent/child1/file-a
/docs/parent/child1/file-b
/docs/parent/child2/
/docs/parent/child2/file-c

如何才能实现这种简单的设置?

4

2 回答 2

1

请记住,Git 存储库包含提交,而不是文件。(然后提交包含文件,但我们是逐个提交,而不是逐个文件。)

您存储的现有存储库docs/child(作为.git其中的目录)包含一系列提交。每个提交都有每个文件的完整快照。1 例如,这些提交中的文件是file-afile-b

您现在希望同一存储库添加提交,其中提交中的文件名为child1/file-a,child1/file-bchild2/file-c例如。这很容易做到:进入存储库工作树,创建child1child2子目录,并且——<strong>为了方便2——使用git mv重命名file-a为 namechild1/file-a并重命名file-bchild1/file-b. 创建新文件child2/file-cgit add在其上使用并运行git commit,然后向现有存储库添加一个新提交;在这个新的提交中,内容存储在这些新名称下,而在所有现有提交中,快照将文件存储在它们的旧名称下。

请注意,Git 不存储目录:它只存储名称可能包含或不包含嵌入(正向)斜杠的文件。Git 将根据需要创建一个您的操作系统需要的目录,因为您的操作系统坚持不存在名为 的文件child1/file-a:这是一个名为的目录,child1其中包含一个名为file-a. Git 坚持认为,不,这是一个名为child1/file-a;的文件。Git 完全管理3 Git 的文件概念与您的操作系统之间的这种不匹配。

请记住:Git 存储库保存提交。 Git 不是关于文件或分支,而是关于提交。提交保存文件(我们需要完成工作),分支名称帮助我们(和 Git)找到我们想要的包含我们需要的文件的提交。但是在存储库级别,Git 是关于提交的。当您考虑存储在 Git 存储库中的内容时,请考虑提交。每个都包含所有文件的快照,以及一些元数据。


1提交中的文件被压缩和 Git 化,因此只有 Git 可以读取它们,而实际上没有任何东西可以写入它们。它们也被重复删除(在提交内和提交之间),因此每次提交每次都保存每个文件这一事实不会导致存储库膨胀到荒谬的大小(尽管一些二进制文件会破坏这个技巧,然后存储库膨胀到荒谬的大小,这就是为什么在 Git 中存储大型二进制文件是不明智的)。

2就 Git 而言,删除某个名为的文件file-a并创建一个包含相同内容的全新child1/file-a文件与将现有文件重命名file-achild1/file-a. 最终的提交只是保存内容;如果child1/file-a新提交中的内容与旧提交中的内容逐字节匹配,则会对file-a它们进行重复数据删除。尽管如此,在这里使用起来还是要方便得多git mv,除非您已经使用过普通mv的或您的操作系统使用的任何重命名或重组命令。如果是这样,请随意使用git rm和/或git add更新 Git 对文件名称和内容的看法。Git 不会关心你是如何从旧设置到新设置的:它包含的只是commits,这些提交只保存文件的快照(加上元数据,但元数据不包含重命名信息)。

3对于“完全”的某些值:Git 中的目录/文件冲突代码有偶尔出现小错误的历史。总而言之,考虑到 Git 的思维方式和操作系统之间的这种不匹配有多复杂,这非常好。尽管如此,在某些复杂的事后检测重命名跨提交导致文件移动到新目录的情况下,某些版本的 Git 比其他版本更好。

于 2021-12-28T08:00:06.373 回答
0

根据 torek 的回答,由于我不需要将两个子存储库合并到一个父存储库中,因此我最终将初始存储库重新child用作父存储库。我所做的是:

# enter the child repo
cd child
# create the new child folder
mkdir child1
# move all files inside "child" from their original location to their multi-child destination
# the -k flag avoids the error caused by copying child1 into child1
# this operation doesn't copy files or folders starting with a dot
git mv -k * ./child1
# running `git add -A && git status` would show that all files have been renamed (moved)
# create child2 and move files there
mkdir child2

现在结构看起来像这样:

/
/docs/
/docs/child/
/docs/child/.git/
/docs/child/child1/
/docs/child/child1/file-a
/docs/child/child1/file-b
/docs/child/child2/
/docs/child/child2/file-c

现在,如果需要,可以将“子”文件夹重命名为“父”文件夹并git config -e在其中运行以指向另一个远程仓库。

于 2021-12-28T12:15:38.587 回答