我的公司使用SVN存储库,但我想使用Git。目前我正在使用 git-svn,但是当我移动或重命名包含 Git 中多个文件的目录并"git svn dcommit"进行此类更改时,在 SVN 存储库中,这会导致单个文件移动:
Changed paths:
D /directory/file1
D /directory/file2
D /directory/file3
D /directory/file4
...
A /renamedDirectory
A /renamedDirectory/file1 (from /directory/file1:67918)
A /renamedDirectory/file2 (from /directory/file2:67918)
A /renamedDirectory/file3 (from /directory/file3:67918)
A /renamedDirectory/file4 (from /directory/file4:67918)
....
相反,我希望看到这样的东西:
Changed paths:
D /directory
A /renamedDirectory (from /directory:67918)
即完整目录重命名。有什么办法可以解决这个问题吗?
在 git 中重命名(移动)目录时,git 移动的只是文件,而不是目录。
如果我将名为pdfs
的文件夹重命名为pdfs2
$ git mv pdfs pdfs2
$ git status
renamed: pdfs/filea -> pdfs2/filea
renamed: pdfs/fileb -> pdfs2/fileb
所以我认为这就是 git 的工作方式,所以 git-svn 也是这样工作的。
git 没有办法说"我 100% 确定这是一个完整的目录移动操作",因此将其转换为 SVN 作为目录移动。Git 只知道/关心文件。
另外:你会注意到,如果你尝试提交一个空目录,git 会抱怨:
$ mkdir afolder
$ git add afolder && git commit -m "Added afolder"
On branch master
nothing to commit, working tree clean
这又是因为 git 不关心目录,只关心文件。
在文件移动和复制方面,SVN 和 Git 之间有一个主要区别:
-
Subversion 保留在仓库中执行的每个复制操作的复制自元数据。
-
Git 不保留这种元数据,而是依靠某些启发式方法来确定文件或目录是被复制还是移动。
不同的 Git 命令使用不同的重命名检测技术,例如git log --stat -M
确实会检测目录重命名:
git log --stat -M
...
{directory => renamedDirectory}/file1
{directory => renamedDirectory}/file2
{directory => renamedDirectory}/file3
{directory => renamedDirectory}/file4
但是,git-svn
在将 Git 提交发送到 SVN 存储库时不会尝试检测重命名的目录,因此,git-svn
生成的复制元数据不会反映您所期望的目录重命名,而是重命名相应修订版中的单个文件。
我们在SubGit中采用了不同的方法,这是git-svn
的替代方案:当一个人使用Git移动目录时:
$ git mv directory renamedDirectory
然后将此更改推送到启用 SubGit 的 Git 存储库:
$ git commit -m 'Rename directory to renamedDirectory'
$ git push
SubGit 确实将此更改转换为 Subversion 存储库中的目录重命名:
Changed paths:
D /directory
A /renamedDirectory (from /directory:123)
如果你发现在 Subversion 仓库中保留这种元数据很重要,你可以考虑尝试 SubGit。这是一个快速入门指南。