programing tip

GIT 사본 파일 보존 히스토리

itbloger 2020. 6. 4. 19:14
반응형

GIT 사본 파일 보존 히스토리


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 project)에 있으며 고객이 런타임에 두 가지 버전을 가질 수 있도록 새로운 버전의 코드를 만들어야합니다. 정렬이 완료되면 버전이 결국 제거됩니다. 우리는 물론 maven 버전 관리를 사용할 수 있습니다. 저는 GIT의 초보자이며 git이 제공 할 수있는 것에 대해 궁금합니다.


Subversion과 달리 git에는 파일 별 기록이 없습니다. 커밋 데이터 구조를 보면 이전 커밋과이 커밋에 대한 새 트리 개체 만 가리 킵니다. 확약에 의해 파일이 변경되는 확약 오브젝트에는 명시 적 정보가 저장되지 않습니다. 이러한 변화의 본질도 아닙니다.

변경 사항을 검사하는 도구는 휴리스틱을 기반으로 이름 변경을 감지 할 수 있습니다. 예를 들어 "git diff"에는 이름 바꾸기 감지를 설정하는 -M 옵션이 있습니다. 따라서 이름을 변경하는 경우 "git diff"는 하나의 파일이 삭제되고 다른 파일이 생성되었음을 나타내며 "git diff -M"은 실제로 이동을 감지하고 그에 따라 변경 사항을 표시합니다 ( "man git diff"참조). 세부).

git에서 이것은 변경 사항을 커밋하는 방법이 아니라 나중에 커밋 된 변경 사항을 보는 방법의 문제입니다.


두 개의 다른 위치로 병렬로 옮기고 병합 한 다음 한 사본을 원래 위치로 다시 옮기면됩니다.

그런 다음 git blame특별한 옵션없이 두 사본 중 하나 를 실행할 수 있으며 두 가지 모두에 대한 최상의 기록 속성을 볼 수 있습니다. git log원본을 실행 하고 전체 기록을 볼 수도 있습니다 .

상세하게, 저장소의 foo /를 bar /에 복사한다고 가정하십시오. 이렇게하십시오 (훅으로 다시 쓰는 등을 피하기 위해 커밋하기 위해 -n을 사용하고 있습니다) :

git mv foo bar
git commit -n
SAVED=`git rev-parse HEAD`
git reset --hard HEAD^
git mv foo foo-magic
git commit -n
git merge $SAVED # This will generate conflicts
git commit -a -n # Trivially resolved like this
git mv foo-magic foo
git commit -n

참고 : Linux에서 git 2.1.4를 사용했습니다.

왜 이것이 작동 하는가

다음과 같은 개정 내역이 나타납니다.

  ORIG_HEAD
    /    \
SAVED  ALTERNATE
    \    /
    MERGED
      |
   RESTORED

git에게 'foo'의 히스토리를 물어 보면 (1) MERGED와 RESTORED 사이의 'foo-magic'에서 이름 바꾸기를 감지하고, (2) 'foo-magic'이 MERGED의 ALTERNATE 부모에서 온 것을 감지하고, (3) ORIG_HEAD와 ALTERNATE 사이의 'foo'에서 이름 바꾸기를 감지하십시오. 거기에서 그것은 'foo'의 역사를 파헤칠 것입니다.

git에게 'bar'의 히스토리를 물어 보면 (1) MERGED와 RESTORED 사이에 변화가 없음을 발견하고 (2) 'bar'가 MERGED의 SAVED 상위에서 온 것을 감지하고 (3) ' ORIG_HEAD와 SAVED 사이의 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 blamegit log

Most of this information comes from the answers here: Record file copy operation with Git


For completeness, I would add that, if you wanted to copy an entire directory full of controlled AND uncontrolled files, you could use the following:

git mv old new
git checkout HEAD old

The uncontrolled files will be copied over, so you should clean them up:

git clean -fdx new

I've slightly modified Peter's answer here to create a reusable, non-interactive shell script called 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"

In my case, I made the change on my hard drive (cut/pasted about 200 folders/files from one path in my working copy to another path in my working copy), and used SourceTree (2.0.20.1) to stage both the detected changes (one add, one remove), and as long as I staged both the add and remove together, it automatically combined into a single change with a pink R icon (rename I assume).

I did notice that because I had such a large number of changes at once, SourceTree was a little slow detecting all the changes, so some of my staged files look like just adds (green plus) or just deletes (red minus), but I kept refreshing the file status and kept staging new changes as they eventually popped up, and after a few minutes, the whole list was perfect and ready for commit.

I verified that the history is present, as long as when I look for history, I check the "Follow renamed files" option.


This process preserve history, but is little workarround:

# 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

참고URL : https://stackoverflow.com/questions/16937359/git-copy-file-preserving-history

반응형