将已跟踪和未跟踪的文件移动到子目录中。

4
我有一个git仓库,其中包含许多文件和文件夹,其中一些被跟踪在git中,另一些则没有。 我想将所有内容移动到一个子目录中(例如mv * subdir/的结果),但是要让git知道已经移动了被跟踪的文件。我不想手动重新添加所有仓库文件到它们的新位置中。
我尝试过一些naive的方法,例如git mv * subdir/(失败,因为git mv不能移动未跟踪的文件),但无法确定是否有简单的方法来实现这一点。 有人能提出一个建议吗?

对于已跟踪的文件,使用git mv * subdir/进行移动,而mv * subdir/则无法工作? - Micha Wiedenmann
@MichaWiedenmann:git mv * subdir/什么也没移动。 - inclement
诚然,有一个技巧,可以先将未跟踪的文件mv到指定目录,然后再执行git mv * --- 但这取决于如何轻松地对未跟踪的文件进行泛化处理。(我只有一些被忽略的emacs临时文件需要保留,所以很容易使用mv *〜 path/ - Ivan Kapitonov
你们在 git mv 命令中都忘记加上 -k 标志了! - Marco van Hilst
5个回答

6

使用 git mv 很容易实现此功能:

git mv -k SOURCE... DESTINATION
mv -n SOURCE... DESTINATION

这会先移动所有已跟踪的文件,然后再移动未跟踪的文件。这不会覆盖任何东西。

如果您想要覆盖:

git mv -fk SOURCE... DESTINATION
mv -f SOURCE... DESTINATION

最终结果与预期保留了文件的已跟踪/未跟踪属性,不像使用mv && git add会出现问题。
参考文档:
git mv -k
跳过移动或重命名操作,以避免产生错误。当源不存在或未受Git控制,或者除非加上-f参数否则会覆盖现有文件时,就会发生错误。
git mv -f (git mv --force)
强制重命名或移动文件,即使目标已存在。
mv -n (mv --no-clobber)
不要覆盖现有文件。
mv -f (mv --force)
在覆盖之前不进行提示。

0

我用一个比我预期更简单的Bash一行代码解决了这个问题。在运行mv * subdir/之后:

git status | grep deleted | sed "s/ *deleted: */subdir\//" | xargs git add

如果不清楚的话,这只是将之前存储库中的所有内容添加到其中,并用新路径替换旧路径。

如果有更自然的方法可以使用git,我仍然很感兴趣。一个缺点是它实际上没有识别出文件只是被移动了,尽管它们的内容没有改变。

编辑:如果我还git rm旧的文件路径,那么重命名也会被正确检测到。


你的一行代码中,是在git add之后、git commit之前执行git rm <old filepaths>吗? - Ivan Kapitonov

0
一般来说,如果您手动移动文件(而不是使用git命令行),那么使用git rm old-filenamegit add new-filename,git将识别文件已被移动而不是删除并创建了一个新文件。

不仅仅是一般的情况。如果你在 git mv 之后过度修改文件,Git 就无法再将它们识别为已移动的文件,就像使用 mv + git rm + git add 时发生的情况一样。 - StenSoft
我可以手动完成这个任务,但问题在于如何自动化一次性处理所有任务。有很多文件需要处理,包括已被跟踪和未被跟踪的文件,看起来应该有一种方法能够以最小的努力移动这两种类型的文件。 - inclement

0

如果你只是将文件移动到新的子目录中,Git应该能够处理。

mv <list-of-files> <dest>
git add dest

git status 应该将已经跟踪的文件显示为重命名。


1
这也会将所有当前未跟踪的文件添加到git仓库中。我不想要这个(编辑:我也不想手动将每个已跟踪的文件路径添加到仓库中)。 - inclement

0
这样怎么样:
  • 在新位置手动制作一个(普通的)完整副本
  • 调用git mv * subdir/ -f (注意 -f 标志),它会更新 git 并覆盖文件,尽管从技术上讲没有区别。
  • 手动从旧位置删除文件

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接