如何在文件夹层次结构中将所有git内容上移一层?


78

我有一个git存储库,其结构如下:

+--repo.git
|
+----+bootstrap.py
+----+buildout.cfg
+----+.gitignore
+----+webapp
|
+---------+manage.py
+---------+modules
+---------+templates
+---------+static
+---------+...
+---------+...

我想将webapp文件夹的内容向上移动一级。我生成的回​​购应如下所示:

+--repo.git
|
+----+bootstrap.py
+----+buildout.cfg
+----+.gitignore
+----+manage.py
+----+modules
+----+templates
+----+static
+----+...
+----+...

我可以通过简单地将webapp目录的所有文件上移一层,删除空webapp目录然后提交更改来做到这一点吗?这样是否可以保留webapp目录下文件的提交历史记录?

尽管对于你们许多人来说这是一个非常简单的问题,但我想确定。我想要的最后一件事是git汤。


我尝试移动文件,但由于git不能真正处理移动或重命名,因此丢失了提交历史记录。我确实知道,即使它在日志中显示为新文件,也仍然可以使用中的某些选项来查看文件的提交历史记录git log

根据我的阅读,最好的方法是使用git-filter。我对shell或git不太满意,所以有人可以告诉我执行上述操作需要执行什么操作。


1
如果您的文件的哈希值保持不变,则git应该检测到已移动的文件没有git mv移动。您可以git add使用添加新文件后进行检查git status
Ninjakannon

Answers:


66

正确的方法是:

git mv repo.git/webapp/* repo.git/.
git rm repo.git/webapp
git add * 
git commit -m "Folders moved out of webapp directory :-)"

5
这对我不起作用。您在哪个目录中运行此文件?
wharding28年

6
这对我来说效果很好,谢谢!只要是明确的-如果你在git的目录与当前的时候,你只需要做git mv /path/new/old/* /path/new/.哪里path/new/old是哪里的文件目前是和/path/new是你想要的那样。该*代表自己的文件,而不是目录。
露西·贝恩

欢迎您@LucyBain和+1,为其他人留下有用的解释。
Sumeet Pareek 2014年

51
我得到fatal: bad source, source=webapp/*, destination=*这根本不起作用;(
安德鲁·萨维尼赫

4
正如JLRishe在另一个答案中提到的,@ AndrewSavinykh,这似乎是Windows shell隔离的问题,但是如果在Git Bash中运行,它应该可以工作。
亚历克

31

Sumeet答案的另一个变体-在“ webapp”上方的存储库目录中,执行以下命令:

git mv webapp/* ./ -k

-k-包括尚未受版本控制的文件,否则得到:

fatal: not under version control, source=webapp/somefile, destination=somefile

2
致命。在看到您的答案之前,我首先手动移开了这些文件;-)
GhostCat

1
那其他分行呢 我也需要重新设置基准吗?谢谢!
Matifou '18 -10-30

1
>其他分支呢?我也需要重新设置基准吗?-答案:您正在特定分支中进行这些更改,因此您将需要分别对每个分支执行类似的更改。
亚历克斯

7

在Windows中,您可以执行以下操作:

当您在子文件夹中时

for /f %f in ('dir /b') do git mv %f ../

结果子文件夹中的所有对象都将位于父文件夹中

请注意:当您在子文件夹中有名称等于子文件夹的对象时,可能会出现一些错误


这是在Win10中对我有用的唯一答案...不使用Powershell。+1
alan

1
得到了这一点:致命的:“ ../”在存储库外部
mrapi

7

我只需在目标文件夹中执行此操作即可使其工作:

git mv webapp/* .

看来这不会在Windows外壳(失败并显示错误的工作Bad source),但它在Windows中工作,如果你使用Git的Bash shell中,它扩展了*通配符。


5

您提到的解决方案应该可以使用,因为git首先根据文件的哈希值跟踪更改,然后根据文件的位置跟踪更改。

如果在移动文件的过程中更改了文件的内容,则此方法将无效。

大写情况下,尝试一下,如果它不起作用,则可以还原更改,然后再将更改推送到主存储库:)。这就是我非常喜欢git的原因之一。

编辑

我忘了提到要在重命名后看到更改,您需要使用'--follow'参数。检查这个例子

首先,我创建了一个新的git repo

94:workspace augusto$ mkdir gittest
94:workspace augusto$ cd gittest/
94:gittest augusto$ git init
Initialized empty Git repository in /Volumes/Data/dev/workspace/gittest/.git/

然后在文件夹/测试中创建一个文件

94:gittest augusto$ mkdir folder
94:gittest augusto$ vi folder/test
94:gittest augusto$ git add folder/test
94:gittest augusto$ git commit -am "added file"
[master (root-commit) 7128f82] added file
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 folder/test

然后将文件移动到newfolder / test

94:gittest augusto$ mkdir newfolder
94:gittest augusto$ mv folder/test newfolder/
94:gittest augusto$ git add newfolder/test 
94:gittest augusto$ git commit -am "moved/renamed file"
[master 4da41f5] moved/renamed file
 1 files changed, 0 insertions(+), 0 deletions(-)
 rename {folder => newfolder}/test (100%)

git log --follow newfolder/test显示完整的历史记录(我添加了参数-p以显示更多信息,例如路径)。

94:gittest augusto$ git log --follow -p newfolder/test 
commit 4da41f5868ab12146e11820d9813e5a2ac29a591
Author: Augusto Rodriguez <xxxx@gmail.com>
Date:   Sat Aug 20 18:20:37 2011 +0100

    moved/renamed file

diff --git a/folder/test b/newfolder/test
similarity index 100%
rename from folder/test
rename to newfolder/test

commit 7128f8232be45fd76616f88d7e164a840e1917d5
Author: Augusto Rodriguez <xxxx@gmail.com>
Date:   Sat Aug 20 18:19:58 2011 +0100

    added file

diff --git a/folder/test b/folder/test
new file mode 100644
index 0000000..3b2aed8
--- /dev/null
+++ b/folder/test
@@ -0,0 +1 @@
+this is a new file

我希望这有帮助!


嗨!请检查更新的答案,我添加了一个如何跟踪更改的示例。
Augusto

2

如果您使用的是PowerShell,则可以从项目根目录运行此命令,它将webapp的内容放在此处。

Get-ChildItem .\webapp\ | ForEach-Object { git mv $_.FullName .\ }

1

是的,您只需移动文件即可。但是,您确实需要告诉git webapp文件夹中的旧文件已经消失了,也就是说,git需要更新其已完成/已提交文件的索引。

因此,您可以git add -A .使git注意到所有更改,或使用git mv <files>告诉git自己进行移动。请参见git mv手册页

-更新。

您注意到自己以为“ .. git并没有真正处理移动或重命名..”-刚开始我也感到困惑,并且还没有完全理解Index的工作方式。一方面,民间说的git只拍摄快照,并不会跟踪重命名,但你得到击中它“失败”,如果你更新.gitignoremv文件,等等。这“失败”是一部关于困惑如何索引工作。

我的可视化是“索引/暂存”区域是一个类似情节提要墙的地方,您可以在其中放置最新和最大的“完成”文件的副本,包括其路径(使用git add),并提交该副本。如果您不从情节提要墙上拿下那个副本(即git rm),那么git将继续提交它,并且混乱无比(请参阅许多SO问题...)。git在merges期间也以类似方式使用Index


1

在Windows中,使用Bash可以进行以下工作:

git mv /c/REPO_FOLDER/X_FOLDER/Y_FOLDER/Z_FOLDER/* /c/REPO_FOLDER/X_FOLDER/Y_FOLDER

0

是的,git将跟踪过去内容的更改。它使用文件内容的哈希值,因此无论它们在目录结构中位于何处,它们都将是同一文件。

因此,您应该在一次提交中进行移动,然后在随后的提交中修复所有编辑。这将使Git能够以最大的效率确定重定向,并且不会对存储在存储库中的数据量产生任何影响(因为无论如何您都将进行这些更改)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.