我有一个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 log
中的一些选项查看文件的提交历史记录。
从我读过的内容来看,实现这一目标的最佳方法是使用git-filter
。我对shell或git不是很好,所以有人可以告诉我我需要执行上述操作。
答案 0 :(得分:50)
刚刚这样做,实际上非常简单。正确的方法是 -
git mv repo.git/webapp/* repo.git/.
然后
git rm repo.git/webapp
后跟
git add *
git commit -m "Folders moved out of webapp directory :-)"
答案 1 :(得分:21)
Sumeet答案的另一个变体 - 在上面的存储库目录中" webapp"执行以下命令:
git mv webapp/* ./ -k
-k - 包含尚未受版本控制的文件,否则您将获得:
fatal: not under version control, source=webapp/somefile, destination=somefile
答案 2 :(得分:4)
你提到的解决方案应该可行,因为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
我希望这有帮助!
答案 3 :(得分:2)
可以执行以下操作:
当您在子文件夹
时for /f %f in ('dir /b') do git mv %f ../
结果子文件夹中的所有对象都将位于父文件夹
中请注意:如果子文件夹中的对象名称等于子文件夹,则可能会出现一些错误
答案 4 :(得分:1)
是的,你可以简单地移动文件。但是你需要告诉git webapp文件夹中的旧文件已经消失了,也就是说,git需要更新已完成/已提交文件的索引。
因此,您可以使用git add -A .
让git注意到所有更改,或使用git mv <files>
告诉git自行执行此操作。 See the git mv man page
- 更新
你注意到你认为“.. git并没有真正处理移动或重命名......” - 我起初也很困惑,并且还没有完全理解索引的工作方式。一方面民间说git只拍摄快照而不跟踪重命名,但如果你更新.gitignore
或mv
一个文件等,你就会被它“失败”。这个'失败' '是关于指数如何的混淆。
我的可视化是索引/暂存区域是一个地方,就像故事板墙一样,您可以在其中放置最新和最好的“已完成”文件的副本,包括其路径(使用git add
),以及它是提交的副本。如果你没有从故事板墙上取下那份副本(即git rm
),那么git将继续提交它,并且混乱很多(参见许多SO问题......)。 git在merge
期间也以类似的方式使用索引
答案 5 :(得分:1)
我只需从目标文件夹中执行此操作即可使其正常工作:
git mv webapp/* .
似乎这在Windows shell中无效(失败并显示错误Bad source
),但如果使用Git Bash shell,将在Windows中运行展开*
通配符。
答案 6 :(得分:1)
如果您使用的是PowerShell,则可以从项目根目录运行此命令,它将把webapp的内容放在此处。
Get-ChildItem .\webapp\ | ForEach-Object { git mv $_.FullName .\ }
答案 7 :(得分:0)
是的,git会跟踪过去内容的变化。它使用文件内容的哈希值,因此无论它们在目录结构中的位置如何,它们都将是同一个文件。
因此,您应该在一次提交中执行移动,然后在后续提交中修复任何编辑。这将使Git能够以最高效率确定重定向,并且不会对存储库中存储的数据量产生任何影响(因为您无论如何都要进行这些更改)。
答案 8 :(得分:0)
在Windows中,使用Bash可以完成以下工作:
git mv /c/REPO_FOLDER/X_FOLDER/Y_FOLDER/Z_FOLDER/* /c/REPO_FOLDER/X_FOLDER/Y_FOLDER