Git copy file preserving history [复制]

jljoyd4f  于 12个月前  发布在  Git
关注(0)|答案(7)|浏览(118)

此问题在此处已有答案

Record file copy operation with Git(3个答案)
三年前关闭。
我在Git中有一个有点令人困惑的问题,比如说,我提交了一个文件dir1/A.txt,而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可以提供什么在这里。

p3rjfoxz

p3rjfoxz1#

你要做的就是:
1.将文件移动到两个不同的位置,
1.合并完成上述任务的两个提交,
1.将一个副本移回原始位置。
您将能够看到这两个文件的历史属性(使用git blame)和完整的更改历史(使用git log)。
假设你想创建一个名为bar的文件foo的副本。在这种情况下,你使用的工作流程如下所示:

git mv foo bar
git commit

SAVED=`git rev-parse HEAD`
git reset --hard HEAD^
git mv foo copy
git commit

git merge $SAVED     # This will generate conflicts
git commit -a        # Trivially resolved like this

git mv copy foo
git commit

字符串

为什么会这样

执行上述命令后,最终会得到一个类似于以下内容的修订历史记录:

( revision history )            ( files )

    ORIG_HEAD                      foo
     /     \                      /   \
SAVED       ALTERNATE          bar     copy
     \     /                      \   /
      MERGED                     bar,copy
        |                           |
     RESTORED                    bar,foo


当你向Git询问foo的历史时,它会:
1.在合并和恢复之间检测copy的重命名,
1.检测到copy来自MERGED的ALTERNATE父代,以及
1.在ORIG_HEAD和ALTERNATE之间检测foo的重命名。
从那里,它将深入了解foo的历史。
当你向Git询问bar的历史时,它会:
1.注意合并和恢复之间没有变化,
1.检测到bar来自MERGED的SAVED父节点,并且
1.在ORIG_HEAD和SAVED之间检测foo的重命名。
从那里,它将深入了解foo的历史。
就这么简单:)
你只需要强制Git进入一个合并的状态,在那里你可以接受文件的两个可跟踪的副本,我们通过并行移动原始文件来完成这一点(我们很快就会恢复)。

liwlm1x9

liwlm1x92#

与Subversion不同的是,git没有每个文件的历史记录。如果你查看提交的数据结构,它只指向以前的提交和这次提交的新树对象。提交对象中没有存储明确的信息,也没有存储这些提交改变了哪些文件,以及这些改变的性质。
检查更改的工具可以基于语法来检测重命名。例如,git diff具有打开重命名检测的选项-M。因此,在重命名的情况下,git diff可能会显示一个文件已被删除,另一个文件已被创建,而git diff -M实际上会检测移动并相应地显示更改(有关详细信息,请参阅man git diff)。
所以在git中,这不是你如何提交更改的问题,而是你以后如何看待提交的更改。

qxsslcnc

qxsslcnc3#

只需复制文件,添加并提交它:

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 blamegit log检查历史时 * 检测 * 副本。
大部分信息来自这里的答案:Record file copy operation with Git

huwehgph

huwehgph4#

我稍微修改了Peter's answer here,创建了一个可重用的、非交互式的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"

字符串

z4iuyo4d

z4iuyo4d5#

为了完整起见,我想补充一点,如果你想复制一个充满受控和不受控文件的整个目录,你可以使用以下方法:

git mv old new
git checkout HEAD old

字符串
不受控制的文件将被复制,所以你应该清理它们:

git clean -fdx new

tp5buhyn

tp5buhyn6#

在我的情况下,我在我的硬盘上进行了更改(剪切/粘贴大约200个文件夹/文件从一个路径在我的工作副本到另一个路径在我的工作副本),并使用SourceTree(2.0.20.1)对检测到的变化进行分级(一个添加,一个删除),只要我把添加和删除放在一起,它自动组合成一个粉红色的R图标(重命名我假设)的单一变化。
我确实注意到,因为我一次有这么多的更改,SourceTree检测所有更改的速度有点慢,所以我的一些暂存文件看起来像只是添加(绿色加号)或只是删除(红色减号),但我不断刷新文件状态,并不断暂存新的更改,因为它们最终弹出,几分钟后,整个列表都很完美,可以提交了。
我验证了历史是存在的,只要当我寻找历史,我检查“跟随重命名的文件”选项。

tct7dpnv

tct7dpnv7#

这个过程保留了历史,但几乎没有变通方法:

# 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

字符串

相关问题