用Git记录文件复制操作

问题描述 投票:0回答:3

当我使用 git-mv 在 git 中移动文件时,状态显示该文件已被重命名,即使我更改了某些部分,它仍然被认为几乎是相同的东西(这很好,因为它让我可以跟踪它的历史记录) )。

当我复制文件时,原始文件有一些历史记录,我想将其与新副本关联起来。

我尝试移动文件,然后尝试在原始位置重新签出 - 一旦移动,git 将不允许我签出原始位置。

我尝试过进行文件系统复制,然后添加文件 - git 将其列为新文件。

有没有办法让 git 记录文件复制操作,就像记录文件重命名/移动一样,历史记录可以追溯到原始文件?

git file copy
3个回答
131
投票

如果由于某种原因(例如使用 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:上述方案的优点是不改变原文件的日志,不产生合并冲突,而且更短。前一个解决方案有四次提交:

  • 不要复制,而是切换到新分支并将文件移动到新位置。
  • 切换到原来的分支并重命名文件。
  • 将新分支合并到原始分支中,通过保留两个文件来解决小冲突。
  • 在单独的提交中恢复原始文件名。

(解决方案取自https://stackoverflow.com/a/44036771/1389680.


127
投票

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>
(目前有一点限制,仅适用于单个文件)。

这建立在罗伯特的答案之上。


1
投票

我的解决方案包括提示起点和终点路径。

我的解决方案还会删除为此目的创建的临时分支(如果脚本成功完成)。

注意事项:

脚本将尝试为您为第二个提示提供的输入创建一个新目录(新目标)。

此解决方案和原始解决方案都将历史记录合并到
    当前分支
  1. 中。我建议您从一个新分支开始,或者至少
  2. git stash save
  3. (如果您有任何本地修改)。
    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
    
© www.soinside.com 2019 - 2024. All rights reserved.