git 将文件和目录与提交历史一起移动到子目录中
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18667308/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Move file and directory into a sub-directory along with commit history
提问by rst.ptl
How can I move a directory and files to a sub-directory along with commit history?
如何将目录和文件连同提交历史一起移动到子目录?
For example:
例如:
Source directory structure:
[project]/x/[files & sub-dirs]
Target directory structure:
[project]/x/p/q/[files & sub-dirs]
源码目录结构:
[project]/x/[files & sub-dirs]
目标目录结构:
[project]/x/p/q/[files & sub-dirs]
回答by VonC
To add to bmargulies's comment, the complete sequence is:
添加到bmargulies的评论,完整的序列是:
mkdir -p x/p/q # make sure the parent directories exist first
git mv x/* x/p/q # move folder, with history preserved
git commit -m "changed the foldername x into x/p/q"
Try it first to see a preview of the move:
首先尝试查看移动的预览:
git mv -n x/* x/p/q
If you're using bash, you can avoid the issue of trying to move a folder into itself by using an extended glob like so (using the
shopt
built-in):
如果你正在使用bash,就可以避免试图通过使用扩展水珠像这样的一个文件夹移动到其自身的问题(使用了
shopt
内置的):
shopt -s extglob; git mv !(folder) folder
Captain Manreports in the commentshaving to do:
mkdir temp
git mv x/* temp
mkdir -p x/p/q
git mv temp x/p/q
rmdir temp;
Context:
语境:
I am on Windows with Cygwin.
I just realized I did theshopt -s extglob
example wrong so my way may not have be necessary, but I typically do use zsh instead of bash, and it didn't have the commandshopt -s extglob
(though I'm sure there is an alternative), so this approach should work across shells (subbing in your shell'smkdir
andrmdir
if it's especially foreign)
我在 Windows 上使用 Cygwin。
我刚刚意识到我shopt -s extglob
做错了这个例子,所以我的方法可能没有必要,但我通常使用 zsh 而不是 bash,并且它没有命令shopt -s extglob
(尽管我确定有替代方法),所以这种方法应该跨壳工作(在你的壳中加入mkdir
,rmdir
如果它特别陌生)
As an alternative, spankymentions in the commentsthe -k
option of git mv
:
作为替代方案,spanky在评论中提到了以下-k
选项git mv
:
Skip move or rename actions which would lead to an error condition.
跳过会导致错误情况的移动或重命名操作。
git mv -k * target/
That would avoid the "can not move directory into itself
" error.
这将避免“ can not move directory into itself
”错误。
回答by PiQuer
Git does a very good job to track content even if it is moved around, so git mv
is clearly the way to go if you move files because they used to belong in x
, but now they belong in x/p/q
because the project evolved that way.
即使内容被移动,Git 也能很好地跟踪内容,因此git mv
如果您移动文件,显然是要走的路,因为它们曾经属于x
,但现在它们属于,x/p/q
因为项目是这样发展的。
Sometimes, however, there is a reason to move files to a subdirectory throughout the history of a project. For example if the files have been put somewhere by mistake and some more commits have been made since, but the intermittent commits don't even make sense with the files in the wrong place. If all that happened on a local branch, we want to clean up the mess before pushing.
然而,有时在整个项目历史中将文件移动到子目录是有原因的。例如,如果文件被错误地放置在某个地方,并且此后又进行了一些提交,但间歇性提交甚至对错误位置的文件没有意义。如果所有这些都发生在本地分支上,我们希望在推送之前清理混乱。
The question states "along with commit history", which I would interpret as rewriting the history in exactly that way. This can be done with
问题说明“连同提交历史”,我将其解释为完全以这种方式重写历史。这可以用
git filter-branch --tree-filter "cd x; mkdir -p p/q; mv [files & sub-dirs] p/q" HEAD
The files then appear in the p/q
subdirectory throughout the history.
然后这些文件出现在p/q
整个历史记录的子目录中。
The tree filter is well suited for small projects, its advantage is that the command is simple and easy to understand. For large projects this solution does not scale very well, if performance matters then consider to use an index filter as outlined in this answer.
树过滤器非常适合小型项目,它的优点是命令简单易懂。对于大型项目,此解决方案不能很好地扩展,如果性能很重要,则考虑使用本答案中概述的索引过滤器。
Please note that the result should not be pushed to a public server if the rewrite touches commits which were already pushed before.
请注意,如果重写涉及之前已经推送的提交,则不应将结果推送到公共服务器。
回答by peroyhav
I can see this is an old question, but I still feel obliged to answer With my current solution to the problem, that I have derived from one of the examples in the git book.
In stead of using an inefficient --tree-filter
I move the files directly on the index With an --index-filter
.
我可以看到这是一个老问题,但我仍然觉得有必要用我目前对这个问题的解决方案来回答,这是我从git book中的一个例子中得出的。--tree-filter
我没有使用效率低下的文件,而是直接在索引上使用--index-filter
.
git filter-branch -f --index-filter 'PATHS=`git ls-files -s | sed "s/^<old_location>/<new_location>/"`;GIT_INDEX_FILE=$GIT_INDEX_FILE.new; echo -n "$PATHS" | git update-index --index-info && if [ -e "$GIT_INDEX_FILE.new" ]; then mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"; fi' -- --all
this is a specialization of one of the examples from the book I've also used the same example to mass rename files in the commit history in one special case. if moving files in subdirectories: remember to escape the / character in the paths With a \ to make the sed command work as expected.
这是本书中的一个示例的特化,我还使用相同的示例在一个特殊情况下批量重命名提交历史记录中的文件。如果在子目录中移动文件:请记住使用 \ 对路径中的 / 字符进行转义,以使 sed 命令按预期工作。
Example:
例子:
Project Directory
|-a
| |-a1.txt
| |-b
| | |-b1.txt
to move the b directory to the project root:
将 b 目录移动到项目根目录:
git filter-branch -f --index-filter 'PATHS=`git ls-files -s | sed "s/a\/b\//b\//"`;GIT_INDEX_FILE=$GIT_INDEX_FILE.new; echo -n "$PATHS" | git update-index --index-info && if [ -e "$GIT_INDEX_FILE.new" ]; then mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"; fi' -- --all
Result:
结果:
Project Directory
|-a
| |-a1.txt
|
|-b
| |-b1.txt
回答by Jeremy Hutchins
The git mv command is the simplest way. However, at least on my Linux box, I needed to supply the -k flag to avoid getting an error back that a folder cannot be moved into itself. I was able to perform the action by using...
git mv 命令是最简单的方法。但是,至少在我的 Linux 机器上,我需要提供 -k 标志以避免返回无法将文件夹移入自身的错误。我能够通过使用执行该操作...
mkdir subdirectory
git mv -k ./* ./subdirectory
# check to make sure everything moved (see below)
git commit
As a warning, this will skip allmoves which would lead to an error condition, so you will probably want to check that everything worked properly after the move and before a commit.
作为警告,这将跳过所有会导致错误情况的移动,因此您可能希望在移动之后和提交之前检查一切是否正常工作。