当我使用 git-mv 在 git 中移动文件时,状态显示该文件已被重命名,即使我更改了某些部分,它仍然被认为几乎是相同的东西(这很好,因为它让我可以跟踪它的历史记录) )。
当我复制文件时,原始文件有一些历史记录,我想将其与新副本关联起来。
我尝试移动文件,然后尝试在原始位置重新签出 - 一旦移动,git 将不允许我签出原始位置。
我尝试过进行文件系统复制,然后添加文件 - git 将其列为新文件。
有没有办法让 git 记录文件复制操作,就像记录文件重命名/移动一样,历史记录可以追溯到原始文件?
如果由于某种原因(例如使用 gitk)您无法打开复制检测(如Jakub Narębski 的回答),您可以强制 Git 在三个提交中检测复制文件的历史记录:
--no-ff
。归功于Raymond Chen。接下来是他的流程。假设该文件名为
SomeFile.cpp
,并且您希望将副本命名为 SomeOtherFile.cpp
:
origFile=SomeFile.cpp
copyName=SomeOtherFile.cpp
branchName=duplicate-SomeFile
git checkout -b $branchName # create and switch to branch
git mv $origFile $copyName # make the duplicate
git commit -m "duplicate $origFile to $copyName"
git checkout HEAD~ $origFile # bring back the original
git commit -m "restore duplicated $origFile"
git checkout - # switch back to source branch
git merge --no-ff $branchName -m "Merge branch $branchName" # merge dup into source branch
请注意,这可以在 Windows 上的 Git Bash 中执行。
2020-05-19:上述方案的优点是不改变原文件的日志,不产生合并冲突,而且更短。前一个解决方案有四次提交:
Git 不进行重命名跟踪或复制跟踪,这意味着它不会“记录”重命名或复制。相反,它所做的是重命名和复制检测。您可以使用 git diff
选项在
git show
(和 -M
)中请求重命名检测,您可以使用 -C
选项请求在更改的文件中进行额外的副本检测,并且您可以在其中请求更昂贵的副本检测所有带有 -C -C
的文件。请参阅 git-diff联机帮助页。
-C -C
意味着
-C
,-C
意味着 -M
。-M
是
--find-renames
的缩写,-C
表示 --find-copies
,-C -C
也可以拼写为 --find-copies-harder
。您还可以通过将 diff.renames
设置为布尔真值(例如
true
或 1
)来配置 git 始终进行重命名检测,并且您可以通过将其设置为 copy
或 来请求 git 进行复制检测copies
。请参阅 git-config联机帮助页。 另请检查
-l
的
git diff
选项以及相关的配置变量 diff.renameLimit
。
git log <pathspec>
在 Git 中的工作方式不同:这里
<pathspec>
是一组路径分隔符,其中路径可以是(子)目录名称。它会在重命名和复制检测发挥作用之前过滤并简化历史记录。如果您想进行重命名和复制,请使用 git log --follow <filename>
(目前有一点限制,仅适用于单个文件)。
这建立在罗伯特的答案之上。
我的解决方案包括提示起点和终点路径。
我的解决方案还会删除为此目的创建的临时分支(如果脚本成功完成)。
注意事项:
脚本将尝试为您为第二个提示提供的输入创建一个新目录(新目标)。
git stash save
branchName=chore/temp/duplicate-file-history-by-script
currentBranchName="$(git branch --show-current)"
function copy_git_history() {
targetToCopy=$1
newDestination=$2
echo "copying $targetToCopy to $newDestination and restoring it's history"
git mv "$targetToCopy" "$newDestination"
git commit -m "duplicating $targetToCopy to $newDestination to retain git history"
git checkout HEAD~ "$targetToCopy"
git commit -m "restoring moved file $targetToCopy to its original location"
}
### USER PROMPTS ###
echo "proceeding to copy files to current branch. Please make sure you are prepared to have the current git branch modified: $currentBranchName"
# spacing to make things easier to read
printf "\n"
echo "Please enter the path to the file(s) you wish to duplicate, relative to $PWD"
read -r originalFileLoc
echo "Please enter the new path where you wish to copy the original file(s)"
read -r newFileLoc
### END: USER PROMPTS ###
# create the new branch to store the changes
git checkout -b $branchName
# create the duplicate file(s)
if [[ -d "$originalFileLoc" ]]
then
files="$originalFileLoc/*"
echo "copying files from $originalFileLoc to $newFileLoc"
mkdir -p "$newFileLoc"
for file in $files
do
copy_git_history "$file" "$newFileLoc"
done
else
copy_git_history "$originalFileLoc" "$newFileLoc"
fi
# switch back to source branch
git checkout -
# merge the history back into the source branch to retain both copies
git merge --no-ff $branchName -m "Merging file history for copying $originalFileLoc to $newFileLoc"
# delete the branch we created for history tracking purposes
git branch -D $branchName