保存历史的Git拷贝文件
我在Git中有一个有点令人困惑的问题。 比如说,我提交了一个文件保存历史的Git拷贝文件,git,file,copy,filenames,Git,File,Copy,Filenames,我在Git中有一个有点令人困惑的问题。 比如说,我提交了一个文件dir1/a.txtcommitted,git保留了提交的历史记录 现在我需要将文件复制到dir2/A.txt(不是移动,而是复制)。 我知道有一个git mv命令,但我需要dir2/a.txt具有与dir1/a.txt相同的提交历史,并且dir1/a.txt仍保留在那里 我不打算在创建副本后更新A.txt,所有未来的工作都将在dir2/A.txt 我知道这听起来很混乱,我要补充的是,这种情况是在基于java的模块(mavenize
dir1/a.txt
committed,git保留了提交的历史记录
现在我需要将文件复制到dir2/A.txt
(不是移动,而是复制)。
我知道有一个git mv
命令,但我需要dir2/a.txt
具有与dir1/a.txt
相同的提交历史,并且dir1/a.txt
仍保留在那里
我不打算在创建副本后更新A.txt
,所有未来的工作都将在dir2/A.txt
我知道这听起来很混乱,我要补充的是,这种情况是在基于java的模块(mavenized项目)上发生的,我们需要创建一个新版本的代码,以便我们的客户能够在运行时拥有两个不同的版本,第一个版本最终将在对齐完成时删除。
当然,我们可以使用maven版本控制,我只是Git的新手,很好奇Git在这里能提供什么。与subversion不同,Git没有每个文件的历史记录。如果查看提交数据结构,它只指向以前的提交和此提交的新树对象。提交对象中未存储由提交更改的文件的明确信息;也不知道这些变化的性质 检查更改的工具可以基于启发式检测重命名。例如,“git diff”有一个选项-M,用于启用重命名检测。因此,在重命名的情况下,“git-diff”可能会显示一个文件已被删除,另一个文件已创建,而“git-diff-M”实际上会检测到移动并相应地显示更改(有关详细信息,请参阅“man-git-diff”)
因此,在git中,这不是您如何提交更改的问题,而是您以后如何看待提交的更改。为了完整起见,我想补充一点,如果您想复制一个包含受控和非受控文件的整个目录,您可以使用以下方法:
git mv old new
git checkout HEAD old
不受控制的文件将被复制,因此您应该清理它们:
git clean -fdx new
在我的例子中,我在硬盘上进行了更改(将大约200个文件夹/文件从我工作副本的一个路径剪切/粘贴到我工作副本的另一个路径),并使用SourceTree(2.0.20.1)来暂存检测到的更改(一次添加,一次删除),只要我同时暂存添加和删除,它会自动组合成一个带有粉红色R图标的单一更改(我假设重命名) 我确实注意到,因为我一次进行了大量更改,SourceTree在检测所有更改时有点慢,所以我的一些暂存文件看起来只是添加(绿色加号)或删除(红色减号),但我不断刷新文件状态,并在新更改最终弹出时不断暂存,几分钟后,整个清单都很完美,可以提交了 我验证了历史记录是否存在,只要在查找历史记录时选中“遵循重命名文件”选项即可。您只需执行以下操作:
git日志
)和完整的更改历史(使用git日志
)
假设要创建名为bar
的文件foo
的副本。在这种情况下,您将使用的工作流如下所示:
( revision history ) ( files )
ORIG_HEAD foo
/ \ / \
SAVED ALTERNATE bar copy
\ / \ /
MERGED bar,copy
| |
RESTORED bar,foo
git mv foo-bar
git提交
SAVED=`git rev parse HEAD`
git重置--硬头^
git mv foo拷贝
git提交
git merge$SAVED#这将产生冲突
git commit-a#像这样简单地解决
git mv copy foo
git提交
为什么会这样
执行上述命令后,将生成如下所示的修订历史记录:
( revision history ) ( files )
ORIG_HEAD foo
/ \ / \
SAVED ALTERNATE bar copy
\ / \ /
MERGED bar,copy
| |
RESTORED bar,foo
当您向Git询问foo
的历史时,它会:
复制的重命名
copy
是否来自合并的备用父级,以及foo
检测重命名foo
的历史
当您向Git询问条形码的历史时,它会:
请注意,合并和恢复之间没有更改
检测条
是否来自合并的已保存父项,以及
检测原始头和保存头之间从foo
的重命名
从那里,它将深入挖掘foo
的历史
就这么简单。:)
您只需强制Git进入合并状态,在合并状态下,您可以接受文件的两个可跟踪副本,我们通过平行移动原始副本(我们很快会恢复)来实现这一点。只需复制文件,添加并提交:
cp dir1/A.txt dir2/A.txt
git add dir2/A.txt
git commit -m "Duplicated file from dir1/ to dir2/"
然后,以下命令将显示完整的预复制历史记录:
git log --follow dir2/A.txt
要查看从原始文件继承的逐行注释,请使用以下命令:
git blame -C -C -C dir2/A.txt
Git不会在提交时跟踪副本,而是在检查历史记录时检测副本,例如使用Git-dull
和Git-log
这些信息大部分来自这里的答案:我稍微修改了一下,创建了一个可重用的、非交互式的shell脚本,名为git split.sh
:
#!/bin/sh
if [[ $# -ne 2 ]] ; then
echo "Usage: git-split.sh original copy"
exit 0
fi
git mv "$1" "$2"
git commit -n -m "Split history $1 to $2 - rename file to target-name"
REV=`git rev-parse HEAD`
git reset --hard HEAD^
git mv "$1" temp
git commit -n -m "Split history $1 to $2 - rename source-file to temp"
git merge $REV
git commit -a -n -m "Split history $1 to $2 - resolve conflict and keep both files"
git mv temp "$1"
git commit -n -m "Split history $1 to $2 - restore name of source-file"
这一过程保留了历史,但没有什么效果:
# make branchs to new files
$: git mv arquivos && git commit
# in original branch, remove original files
$: git rm arquivos && git commit
# do merge and fix conflicts
$: git merge branch-copia-arquivos
# back to original branch and revert commit removing files
$: git revert commit
我在上的可复制示例显示,git-dull
也知道重命名历史-不使用任何选项。这难道不告诉我们历史是以某种方式存储的吗?@danielder No.Likegit diff-M
这只是对树对象的智能分析。在git-dull
手册页中:“整个文件重命名过程中自动跟随行的原点(目前没有关闭以下重命名的选项)。“那么为什么git-mv
存在?@skirsch-convenciency和Mercurial不同。Mercurial有保存历史的副本。尽我所能