git mark를 삭제하고 새 파일을 파일 이동으로 만드는 방법은 무엇입니까?


505

파일을 수동으로 옮긴 다음 수정했습니다. Git에 따르면 새 파일이고 제거 된 파일입니다. Git을 파일 이동으로 처리하도록 강제 할 수있는 방법이 있습니까?


3
주어진 파일의 경우 old_file.txt, 다음 git mv old_file.txt new_file.txt에 해당합니다 git rm --cached old_file.txt, mv old_file.txt new_file.txt, git add new_file.txt.
Jarl

3
Jarl : 아닙니다. 파일 내에 변경 사항이있는 경우 변경 사항 git mv을 캐시에 추가하지 않고 캐시에 추가합니다 git add. 을 사용하여 파일을 뒤로 이동 git mv한 다음 git add -p변경 세트를 검토하는 것이 좋습니다.
dhardy

내 스크립트를 체크 아웃하십시오 github.com/Deathangel908/python-tricks/blob/master/...
deathangel908


Git은 지난 8 년 동안 파일이 하나 인 경우 최고 답변 stackoverflow.com/a/433142/459 가 아무 것도하지 않았지만… stackoverflow.com/a/1541072/459 에 따라 rm / add를 업데이트 할 수 있습니다. mv / modify 상태로
dlamblin

답변:


435

수정이 너무 심각하지 않은 경우 Git은 자동으로 이동 / 이름 바꾸기를 감지합니다. 그냥 git add새 파일과 git rm이전 파일.git status그러면 이름 변경을 감지했는지 여부가 표시됩니다.

또한 디렉토리를 이동하려면 다음이 필요합니다.

  1. 해당 디렉토리 구조의 맨 위에 cd.
  2. 운영 git add -A .
  3. git status"새 파일"이 이제 "이름이 바뀐"파일인지 확인하기 위해 실행

자식 상태가 여전히 "이름 바꾸기"가 아닌 "새 파일"로 표시되면 행크 게이의 조언 을 따르고 두 가지 커밋으로 이동하고 수정해야합니다.


75
설명 : '너무 심각하지 않음'은 새 파일과 이전 파일이 git에서 사용하는 일부 유사성 인덱스를 기준으로> 50 %보다 '유사한'것을 의미합니다.
pjz

151
이름이 바뀐 파일과 삭제 된 파일이 커밋을 위해 준비되지 않은 경우 삭제 및 새 파일로 표시됩니다. 스테이징 인덱스에 추가하면 이름이 바뀐 것으로 인식됩니다.
marczych

19
" Git이 자동으로 이동 / 이름 바꾸기 "를 말할 때 언급 할 가치가 있습니다. 그것은 당신이 사용하는 시간에 그렇게 git status, git log또는 git diff, 하지 당신이 할 때 git add, git mv또는 git rm. 이름 바꾸기 감지에 대한 추가 말하기는 준비된 파일에만 적합합니다. 따라서 git mv파일을 뒤 따르는 변경은 git status마치 마치 파일 로 간주 되는 것처럼 보일 수 rename있지만 파일에서 git stage(와 동일 git add)을 사용 하면 변경이 너무 커서 이름이 바뀌지 않는다는 것이 분명해집니다.
Jarl

5
진짜 열쇠는 git add@ jrhorn424가 제안한 것처럼 새로운 위치와 오래된 위치를 모두 동시에 추가하는 것 같습니다 .
brianary

4
그러나 특히 파일이 변경되어 크기가 작은 경우에는 그럴 수 없습니다. git에게 이동에 대해 구체적으로 알려주는 방법이 있습니까?
Rebs

112

별도의 커밋으로 이동 및 수정을 수행하십시오.


12
Git은 동시에 이동과 수정을 처리 할 수 ​​있음을 이해합니다. Java로 프로그래밍하고 IDE를 사용할 때 클래스 이름을 바꾸는 것은 수정과 이동입니다. 나는 Git이 움직일 때 (제거 및 생성 중) 자동으로 알아낼 수 있어야한다는 것을 이해합니다.
pupeno

1
Perl도 이것을 필요로하며, Git이 이동 / 이름 바꾸기를 감지 한 적이 없습니다.
jrockway

10
@jrockway, 나는했다. 작은 파일로 쉽게 일어납니다. "이동을 의미하기에는 '너무 달라졌습니다'라고 생각합니다.
ANeves

2
이를 자동화 할 수있는 방법이 있습니까? 색인에 많은 파일이 있고 먼저 이동을 변경 한 다음 변경을 커밋하려고하지만 수동으로 수행하기는 어렵습니다.
ReDetection

5
한 가지 git diff확약은 한 커밋에서 이름 바꾸기를 인식하지 못하면 두 커밋에서 이름 바꾸기를 인식하지 못한다는 것입니다. 그렇게하려면 -M일명 사용해야 --find-renames합니다. 따라서이 질문으로 이끈 동기가 풀 요청에서 이름 바꾸기를 보는 것이라면 (경험에서 말하면) 두 커밋으로 나누면 더 이상 목표를 달성하지 못합니다.
mattliu

44

그것은 모두 지각적인 것입니다. GIT는 일반적으로 동작 인식에 다소 능숙합니다. GIT 콘텐츠 추적기

실제로 의존하는 것은 "통계"가 표시하는 방법입니다. 여기서 유일한 차이점은 -M 플래그입니다.

자식 로그 --stat -M

commit 9c034a76d394352134ee2f4ede8a209ebec96288
Author: Kent Fredric
Date:   Fri Jan 9 22:13:51 2009 +1300


        Category Restructure

     lib/Gentoo/Repository.pm                |   10 +++++-----
     lib/Gentoo/{ => Repository}/Base.pm     |    2 +-
     lib/Gentoo/{ => Repository}/Category.pm |   12 ++++++------
     lib/Gentoo/{ => Repository}/Package.pm  |   10 +++++-----
     lib/Gentoo/{ => Repository}/Types.pm    |   10 +++++-----
     5 files changed, 22 insertions(+), 22 deletions(-)

자식 로그 --stat

commit 9c034a76d394352134ee2f4ede8a209ebec96288
Author: Kent Fredric
Date:   Fri Jan 9 22:13:51 2009 +1300

    Category Restructure

 lib/Gentoo/Base.pm                |   36 ------------------------
 lib/Gentoo/Category.pm            |   51 ----------------------------------
 lib/Gentoo/Package.pm             |   41 ---------------------------
 lib/Gentoo/Repository.pm          |   10 +++---
 lib/Gentoo/Repository/Base.pm     |   36 ++++++++++++++++++++++++
 lib/Gentoo/Repository/Category.pm |   51 ++++++++++++++++++++++++++++++++++
 lib/Gentoo/Repository/Package.pm  |   41 +++++++++++++++++++++++++++
 lib/Gentoo/Repository/Types.pm    |   55 +++++++++++++++++++++++++++++++++++++
 lib/Gentoo/Types.pm               |   55 -------------------------------------
 9 files changed, 188 insertions(+), 188 deletions(-)

자식 도움말 로그

   -M
       Detect renames.

   -C
       Detect copies as well as renames. See also --find-copies-harder.

76
이것이 약간 비유적인 것처럼 보이지만 "GIT는 콘텐츠 추적기이기 때문에 Git은 일반적으로 움직임을 인식하는 데 다소 능숙합니다." 그것은 콘텐츠 추적기입니다. 아마도 움직임을 감지하는 데 능숙 할 수도 있지만 한 문장은 실제로 다른 문장에서 따르지 않습니다. 콘텐츠 추적기이기 때문에 움직임 감지가 반드시 좋은 것은 아닙니다. 실제로 콘텐츠 추적기는 전혀 움직임을 감지하지 못할 수 있습니다.
Laurence Gonsalves

1
@WarrenSeine 디렉토리의 이름을 바꿀 때 해당 디렉토리에있는 파일의 SHA1은 변경되지 않습니다. 동일한 SHA1을 가진 새로운 TREE 객체 만 있으면됩니다. 디렉토리 이름 변경으로 인해 데이터가 크게 변경 될 이유는 없습니다.
Kent Fredric

1
@KentFredric "git log"와 함께 -M을 사용하면 파일의 이름이 바뀌 었는지 여부를 확인할 수 있고 시도해 보았지만 정상적으로 작동하지만 검토를 위해 코드를 게시하고 해당 파일을 gerrit ( gerritcodereview.com )로 볼 때 거기에 파일이 새로 추가되고 이전이 삭제되었음을 나타냅니다. 따라서 "git commit"에 커밋을 수행하고 gerrit이 올바르게 표시하는 옵션이 있습니다.
Patrick

1
아뇨, 전혀 보여주지 않았습니다. 나는 Git이 내용이 동일하기 때문에 add + delete가 이름 바꾸기 인 할 수 있음을 보여주었습니다 . 어떤 일이 일어 났는지 알 수 있는 방법 이 없으며 상관 없습니다. 모든 자식 기억은 "추가됨"과 "삭제됨"입니다. "이름 바꾸기"는 기록되지 않습니다.
Kent Fredric

1
예를 들어, 최근 리포지토리에서 "복사 + 편집"을 많이했습니다. 그것을 보는 대부분의 방법은 "새 파일"만 볼 수 있지만, 전달 git log -M1 -C1 -B1 -D --find-copies-harder하면 git은 새 파일이 먼저 복사 된 것을 "발견"할 수 있습니다. 때로는이 작업을 올바르게 수행하고 다른 경우에는 동일한 내용을 가진 완전히 관련이없는 파일을 찾습니다.
Kent Fredric

36

git diff -M또는 사소한 변경이git log -M 있는 한 이름 변경과 같은 변경 사항을 자동으로 감지해야합니다 . 귀하의 경우 사소한 변경 사소한되지 않습니다, 당신은 유사성 threashold을 줄일 수 있습니다, 예를 들어,

$ git log -M20 -p --stat

기본 50 %에서 20 %로 줄입니다.


13
구성에서 임계 값을 정의 할 수 있습니까?
ReDetection

34

다음은 커밋되지 않은 하나 또는 몇 개의 이름이 바뀌고 수정 된 파일에 대한 빠르고 더러운 솔루션입니다.

파일 이름이 지정 foo되었고 이제 이름이 지정되었다고 가정 해 봅시다 bar.

  1. bar임시 이름으로 이름 을 바꿉니다 .

    mv bar side
    
  2. 체크 아웃 foo:

    git checkout HEAD foo
    
  3. 힘내로 이름 foo을 바꾸십시오 bar:

    git mv foo bar
    
  4. 이제 임시 파일 이름을 다시로 바꿉니다 bar.

    mv side bar
    

마지막 단계는 변경된 내용을 파일로 다시 가져 오는 것입니다.

이것이 작동 할 수는 있지만, 이동 된 파일이 원래 자식과 내용이 너무 다르면 이것이 새로운 객체인지 결정하는 것이 더 효율적이라고 생각할 것입니다. 보여 드리겠습니다 :

$ git status
On branch workit
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   .gitignore
    renamed:    README -> README.md

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   README.md
    modified:   work.js

$ git add README.md work.js # why are the changes unstaged, let's add them.
$ git status
On branch workit
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   .gitignore
    deleted:    README
    new file:   README.md
    modified:   work.js

$ git stash # what? let's go back a bit
Saved working directory and index state WIP on dir: f7a8685 update
HEAD is now at f7a8685 update
$ git status
On branch workit
Untracked files:
  (use "git add <file>..." to include in what will be committed)

    .idea/

nothing added to commit but untracked files present (use "git add" to track)
$ git stash pop
Removing README
On branch workit
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   .gitignore
    new file:   README.md

Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    deleted:    README
    modified:   work.js

Dropped refs/stash@{0} (1ebca3b02e454a400b9fb834ed473c912a00cd2f)
$ git add work.js
$ git status
On branch workit
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   .gitignore
    new file:   README.md
    modified:   work.js

Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    deleted:    README

$ git add README # hang on, I want it removed
$ git status
On branch workit
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   .gitignore
    deleted:    README
    new file:   README.md
    modified:   work.js

$ mv README.md Rmd # Still? Try the answer I found.
$ git checkout README
error: pathspec 'README' did not match any file(s) known to git.
$ git checkout HEAD README # Ok the answer needed fixing.
$ git status
On branch workit
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   .gitignore
    new file:   README.md
    modified:   work.js

Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    deleted:    README.md
    modified:   work.js

Untracked files:
  (use "git add <file>..." to include in what will be committed)

    Rmd

$ git mv README README.md
$ git status
On branch workit
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   .gitignore
    renamed:    README -> README.md
    modified:   work.js

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   work.js

Untracked files:
  (use "git add <file>..." to include in what will be committed)

    Rmd

$ mv Rmd README.md
$ git status
On branch workit
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   .gitignore
    renamed:    README -> README.md
    modified:   work.js

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   README.md
    modified:   work.js

$ # actually that's half of what I wanted; \
  # and the js being modified twice? Git prefers it in this case.

27
이 프로세스는 목적이 없습니다. git은 이름 바꾸기를 위해 메타 데이터를 추가하지 않으며 git mv단순히 git rm/ git add쌍 의 편의입니다 . 이미 'MV 바 foo는'일 경우에, 모든 당신은 확실히 당신이했습니다 있는지 확인해야 git add foo하고 git rm bar커밋하기 전에. 이것은 단일 git add -A명령 또는 git add foo; git commit -a시퀀스 일 수 있습니다.
CB Bailey

17
내가 아는 것은 Git이 그것을 행동으로 인식하지 못했다는 것입니다. 이 작업을 수행 한 후 Git은이를 이동으로 인식했습니다.

8
그것은 움직임으로 인식합니다. 그러나 이제는 비 단계적 변경으로 변경되었습니다. 일단 당신 add이 파일을 다시 자식 휴식 움직임가 / 삭제 / 다시 추가로 수정합니다.
Michael Piefel

4
이 프로세스는 git commit3 단계 이후에 작동하면 그렇지 않으면 올바르지 않습니다. 또한 @CharlesBailey가 정확하므로 mv blah foo3 단계에서 정상 을 수행 한 다음 커밋을 수행하고 동일한 결과를 얻을 수 있습니다.
DaFlame

5
"이 과정은 목적이 없습니다." -git이 혼란스러워서 파일이 삭제되었다고 생각하고 다른 파일이 추가되었다고 생각할 때 사용됩니다. 이것은 Git의 혼란을 없애고 파일을 중간 커밋하지 않고 명시 적으로 이동 한 것으로 표시합니다.
Danack

20

git status이름 변경을 표시하지 않는 것에 대해 이야기하는 경우 git commit --dry-run -a대신 시도하십시오.


11

TortoiseGit을 사용하는 경우 Git의 자동 이름 변경 감지는 커밋 중에 발생하지만이 사실이 항상 소프트웨어에 의해 항상 표시되는 것은 아닙니다. 두 파일을 다른 디렉토리로 옮기고 약간의 편집 작업을 수행했습니다. TortoiseGit을 커밋 도구로 사용하고 Changes made (변경된 항목) 목록에 이동하지 않고 삭제 및 추가 된 파일이 표시되었습니다. 커맨드 라인에서 git status를 실행하면 비슷한 상황이 나타납니다. 그러나 파일을 커밋 한 후 로그에서 이름이 바뀐 것으로 나타납니다. 따라서 귀하의 질문에 대한 답변은 너무 과감한 일을하지 않은 한 Git은 자동으로 이름 바꾸기를 선택해야합니다.

편집 : 분명히 새 파일을 추가 한 다음 명령 줄에서 git 상태를 수행하면 커밋 전에 이름 바꾸기가 표시되어야합니다.

편집 2 : 또한 TortoiseGit에서 커밋 대화 상자에 새 파일을 추가하지만 커밋하지 마십시오. 그런 다음 Show Log 명령으로 이동하여 작업 디렉토리를 보면 Git이 커밋하기 전에 이름 바꾸기를 감지했는지 확인할 수 있습니다.

동일한 질문이 여기에 제기되었습니다 : https://tortoisegit.org/issue/1389 여기 에서 해결하기위한 버그로 기록되었습니다 : https://tortoisegit.org/issue/1440 TortoiseGit의 커밋과 관련된 디스플레이 문제입니다 새 파일을 추가하지 않은 경우 대화 상자 및 일종의 자식 상태가 존재합니다.


2
TortoiseGit이 delete + add를 표시하더라도 git status가 delete + add를 표시하더라도 git commit --dry-run이 delete + add를 표시하더라도 git commit 후에는 이름이 바뀌고 delete + add가 표시되지 않습니다.
Tomas Kubes

1
나는 히스토리 검색 중에 자동 이름 변경 감지가 발생한다고 확신합니다 . 커밋에서 항상 추가 + 삭제입니다. 그것은 당신이 묘사하는 정신 분열증 행동을 설명합니다. 따라서 옵션은 stackoverflow.com/a/434078/155892
Mark Sowul

10

또는 당신은이 질문에 대한 답변을하려고 coud 여기 에서 황색 ! 다시 인용하려면 :

먼저 수동으로 이동 한 파일에 대해 준비된 추가를 취소하십시오.

$ git reset path/to/newfile
$ mv path/to/newfile path/to/oldfile

그런 다음 Git을 사용하여 파일을 이동하십시오.

$ git mv path/to/oldfile path/to/newfile

물론 수동 이동을 이미 커밋 한 경우에는 이동하기 전에 수정본으로 재설정 한 다음 거기서 간단히 git mv를 사용하는 것이 좋습니다.


7

git mvOS 이동 명령 대신 명령을 사용 하여 파일을 이동하십시오. https://git-scm.com/docs/git-mv

이주의 git mv명령은 망할 놈의 버전 1.8.5 최대에 있습니다. 따라서이 명령을 사용하려면 Git을 업데이트해야 할 수도 있습니다.


3

최근에 일부 파일을 이동 (수정하지는 않음) 할 때이 문제가 발생했습니다.

문제는 Git이 파일을 이동할 때 줄 끝이 바뀌어 파일이 동일하다는 것을 알 수 없다는 것입니다.

사용 git mv하여 문제 를 분류했지만 단일 파일 / 디렉토리에서만 작동하며 저장소의 루트에 많은 파일이 있습니다.

이 문제를 해결하는 한 가지 방법은 bash / batch magic입니다.

다른 방법은 다음과 같습니다

  • 파일을 이동하십시오 git commit. 줄 끝이 업데이트됩니다.
  • 줄 끝이 바뀌 었으므로 파일을 원래 위치로 다시 이동하십시오. git commit --amend
  • 파일을 다시 이동하십시오 git commit --amend. 이번에는 라인 엔딩에 변화가 없으므로 Git은 행복합니다.

1

나를 위해 커밋 전에 모든 변경 사항을 숨기고 다시 튀어 나왔습니다. 이것은 git이 추가 / 삭제 된 파일을 다시 분석하고 올바르게 이동 된 것으로 표시했습니다.


0

이 작업을 수행하는 데 더 나은 "명령 줄"방법이있을 수 있으며 이것이 해킹이라는 것을 알고 있지만 좋은 해결책을 찾지 못했습니다.

TortoiseGIT 사용 : 파일이 약간만 변경 되어도 일부 파일 이동 작업이 이름 바꾸기 대신 추가 / 삭제로드로 표시되는 GIT 커밋이있는 경우 다음을 수행하십시오.

  1. 로컬에서 수행 한 작업 확인
  2. 두 번째 커밋에서 미니 한 줄 변경 사항 확인
  3. 거북이 git에 GIT 로그인으로 이동
  4. 두 커밋을 선택하고 마우스 오른쪽 단추를 클릭 한 다음 "하나의 커밋으로 병합"을 선택하십시오.

새로운 커밋은 이제 파일 이름 변경을 올바르게 보여줄 것입니다.


0

파일을 동시에 편집, 이름 바꾸기 및 이동하면 이러한 솔루션이 작동하지 않습니다. 해결책은 두 번의 커밋 (편집 및 이름 바꾸기 / 별도의 이동)으로 수행 한 다음 fixup두 번째 커밋을 통해 git rebase -i한 번의 커밋에 적용하는 것입니다.


0

이 질문을 이해하는 방법은 "git가 오래된 파일의 삭제와 파일 이동으로 새로운 파일의 생성을 인식하게 만드는 방법"입니다.

예. 이전 파일을 삭제하고 이전 파일을 삽입하면 작업 디렉토리에 git status" deleted: old_file"및 " Untracked files: ... new_file"라고 표시됩니다.

그러나 일단 git을 사용하여 파일을 추가하고 제거하면 스테이징 인덱스 / 레벨에서 파일 이동으로 인식됩니다. 이를 위해 운영 체제를 사용하여 삭제 및 작성을 완료했다고 가정하면 다음 명령을 제공하십시오.

git add new_file
git rm old_file

파일의 내용이 50 % 이상이면 git status명령을 실행 하면 다음을 제공합니다.

renamed: old_file -> new_file

1
git status" deleted: old_file"and " Untracked files: ... new_file": Git 2.18 이후 : stackoverflow.com/a/50573107/6309
VonC
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.