이 답변은 git am
예제를 기반으로 한 단계별로 흥미로운 명령을 제공합니다 .
객관적인
- 한 저장소에서 다른 저장소로 일부 또는 모든 파일을 이동하려고합니다.
- 당신은 그들의 역사를 유지하고 싶습니다.
- 그러나 태그와 분기를 유지하는 것은 중요하지 않습니다.
- 이름이 바뀐 파일 (및 이름이 바뀐 디렉토리의 파일)에 대한 제한된 기록을 허용합니다.
순서
- 를 사용하여 이메일 형식으로 내역 추출
git log --pretty=email -p --reverse --full-index --binary
- 파일 트리 재구성 및 기록에서 파일 이름 변경 업데이트 [선택 사항]
- 다음을 사용하여 새 기록 적용
git am
1. 이메일 형식으로 기록을 추출
예 : 추출물의 역사 file3
, file4
그리고file5
my_repo
├── dirA
│ ├── file1
│ └── file2
├── dirB ^
│ ├── subdir | To be moved
│ │ ├── file3 | with history
│ │ └── file4 |
│ └── file5 v
└── dirC
├── file6
└── file7
임시 디렉토리 대상을 정리하십시오.
export historydir=/tmp/mail/dir # Absolute path
rm -rf "$historydir" # Caution when cleaning
당신 되찾기 청소 소스를
git commit ... # Commit your working files
rm .gitignore # Disable gitignore
git clean -n # Simulate removal
git clean -f # Remove untracked file
git checkout .gitignore # Restore gitignore
이메일 형식으로 각 파일의 히스토리 추출
cd my_repo/dirB
find -name .git -prune -o -type d -o -exec bash -c 'mkdir -p "$historydir/${0%/*}" && git log --pretty=email -p --stat --reverse --full-index --binary -- "$0" > "$historydir/$0"' {} ';'
불행하게도 옵션 --follow
또는 --find-copies-harder
함께 사용할 수 없습니다 --reverse
. 파일 이름이 변경 될 때 (또는 상위 디렉토리 이름이 변경 될 때) 히스토리가 잘리는 이유입니다.
이후 : 이메일 형식의 임시 히스토리
/tmp/mail/dir
├── subdir
│ ├── file3
│ └── file4
└── file5
2. 파일 트리를 재구성하고 기록에서 파일 이름 변경을 업데이트합니다 [선택 사항]
이 다른 리포지토리에서이 세 파일을 이동한다고 가정합니다 (동일한 리포지토리 일 수 있음).
my_other_repo
├── dirF
│ ├── file55
│ └── file56
├── dirB # New tree
│ ├── dirB1 # was subdir
│ │ ├── file33 # was file3
│ │ └── file44 # was file4
│ └── dirB2 # new dir
│ └── file5 # = file5
└── dirH
└── file77
따라서 파일을 재구성하십시오.
cd /tmp/mail/dir
mkdir dirB
mv subdir dirB/dirB1
mv dirB/dirB1/file3 dirB/dirB1/file33
mv dirB/dirB1/file4 dirB/dirB1/file44
mkdir dirB/dirB2
mv file5 dirB/dirB2
귀하의 임시 이력은 다음과 같습니다.
/tmp/mail/dir
└── dirB
├── dirB1
│ ├── file33
│ └── file44
└── dirB2
└── file5
기록 내에서 파일 이름도 변경하십시오.
cd "$historydir"
find * -type f -exec bash -c 'sed "/^diff --git a\|^--- a\|^+++ b/s:\( [ab]\)/[^ ]*:\1/$0:g" -i "$0"' {} ';'
참고 : 경로 및 파일 이름 변경을 반영하여 기록을 다시 작성합니다.
(즉, 새로운 저장소 내에서 새로운 위치 / 이름 변경)
3. 새로운 역사를 적용
다른 저장소는 다음과 같습니다.
my_other_repo
├── dirF
│ ├── file55
│ └── file56
└── dirH
└── file77
임시 히스토리 파일에서 커밋을 적용하십시오.
cd my_other_repo
find "$historydir" -type f -exec cat {} + | git am
다른 레포는 지금 :
my_other_repo
├── dirF
│ ├── file55
│ └── file56
├── dirB ^
│ ├── dirB1 | New files
│ │ ├── file33 | with
│ │ └── file44 | history
│ └── dirB2 | kept
│ └── file5 v
└── dirH
└── file77
git status
푸시 될 준비가 된 커밋의 양을 보는 데 사용 하십시오 :-)
참고 : 경로 및 파일 이름 변경을 반영하기 위해 기록이 다시 작성되었으므로
(즉, 이전 리포지토리 내의 위치 / 이름과 비교)
- 필요가 없습니다
git mv
위치 / 파일 이름을 변경할 .
git log --follow
전체 기록에 액세스 할 필요가 없습니다 .
추가 트릭 : repo 내에서 이름이 바뀌거나 이동 한 파일 감지
이름이 바뀐 파일을 나열하려면 다음을 수행하십시오.
find -name .git -prune -o -exec git log --pretty=tformat:'' --numstat --follow {} ';' | grep '=>'
추가 사용자 정의 : git log
옵션 --find-copies-harder
또는을 사용 하여 명령 을 완료 할 수 있습니다 --reverse
. cut -f3-
완전한 패턴 '{. * =>. *}'를 사용 하고 grepping 하여 처음 두 열을 제거 할 수도 있습니다 .
find -name .git -prune -o -exec git log --pretty=tformat:'' --numstat --follow --find-copies-harder --reverse {} ';' | cut -f3- | grep '{.* => .*}'