Câu trả lời này cung cấp các lệnh thú vị dựa trên git amvà được trình bày bằng các ví dụ, từng bước một.
Mục tiêu
- Bạn muốn di chuyển một số hoặc tất cả các tệp từ kho này sang kho khác.
 
- Bạn muốn giữ lịch sử của họ.
 
- Nhưng bạn không quan tâm đến việc giữ thẻ và chi nhánh.
 
- Bạn chấp nhận lịch sử giới hạn cho các tệp được đổi tên (và các tệp trong thư mục được đổi tên).
 
Thủ tục
- Trích xuất lịch sử ở định dạng email bằng cách sử dụng
git log --pretty=email -p --reverse --full-index --binary 
- Sắp xếp lại cây tập tin và cập nhật thay đổi tên tệp trong lịch sử [tùy chọn]
 
- Áp dụng lịch sử mới bằng cách sử dụng 
git am 
1. Trích xuất lịch sử ở định dạng email
Ví dụ: Trích xuất lịch sử của file3, file4vàfile5
my_repo
├── dirA
│   ├── file1
│   └── file2
├── dirB            ^
│   ├── subdir      | To be moved
│   │   ├── file3   | with history
│   │   └── file4   | 
│   └── file5       v
└── dirC
    ├── file6
    └── file7
Làm sạch đích thư mục tạm thời
export historydir=/tmp/mail/dir  # Absolute path
rm -rf "$historydir"             # Caution when cleaning
Làm sạch nguồn repo của bạn
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
Trích xuất lịch sử của từng tệp ở định dạng email
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"' {} ';'
Thật không may tùy chọn --followhoặc --find-copies-harderkhông thể được kết hợp với --reverse. Đây là lý do tại sao lịch sử bị cắt khi tập tin được đổi tên (hoặc khi thư mục mẹ được đổi tên).
Sau: Lịch sử tạm thời ở định dạng email
/tmp/mail/dir
    ├── subdir
    │   ├── file3
    │   └── file4
    └── file5
2. Sắp xếp lại cây tập tin và cập nhật thay đổi tên tệp trong lịch sử [tùy chọn]
Giả sử bạn muốn di chuyển ba tệp này trong repo khác này (có thể là cùng một repo).
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
Do đó, sắp xếp lại các tệp của bạn:
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
Lịch sử tạm thời của bạn là bây giờ:
/tmp/mail/dir
    └── dirB
        ├── dirB1
        │   ├── file33
        │   └── file44
        └── dirB2
             └── file5
Thay đổi tên tập tin trong lịch sử:
cd "$historydir"
find * -type f -exec bash -c 'sed "/^diff --git a\|^--- a\|^+++ b/s:\( [ab]\)/[^ ]*:\1/$0:g" -i "$0"' {} ';'
Lưu ý: Điều này viết lại lịch sử để phản ánh sự thay đổi của đường dẫn và tên tệp. 
      (tức là thay đổi vị trí / tên mới trong repo mới)
3. Áp dụng lịch sử mới
Repo khác của bạn là:
my_other_repo
├── dirF
│   ├── file55
│   └── file56
└── dirH
    └── file77
Áp dụng các cam kết từ các tệp lịch sử tạm thời:
cd my_other_repo
find "$historydir" -type f -exec cat {} + | git am 
Repo khác của bạn bây giờ là:
my_other_repo
├── dirF
│   ├── file55
│   └── file56
├── dirB            ^
│   ├── dirB1       | New files
│   │   ├── file33  | with
│   │   └── file44  | history
│   └── dirB2       | kept
│        └── file5  v
└── dirH
    └── file77
Sử dụng git status để xem số lượng cam kết sẵn sàng được đẩy :-)
Lưu ý: Vì lịch sử đã được viết lại để phản ánh đường dẫn và thay đổi tên tệp: 
      (nghĩa là so với vị trí / tên trong repo trước đó)
- Không cần phải 
git mvthay đổi vị trí / tên tệp. 
- Không cần phải 
git log --followtruy cập đầy đủ lịch sử. 
Thêm mẹo: Phát hiện các tệp đã đổi tên / di chuyển trong repo của bạn
Để liệt kê các tập tin đã được đổi tên:
find -name .git -prune -o -exec git log --pretty=tformat:'' --numstat --follow {} ';' | grep '=>'
Thêm tùy chỉnh: Bạn có thể hoàn thành lệnh git logbằng các tùy chọn --find-copies-harderhoặc --reverse. Bạn cũng có thể xóa hai cột đầu tiên bằng cách sử dụng cut -f3-và lấy mẫu hoàn chỉnh '{. * =>. *}'.
find -name .git -prune -o -exec git log --pretty=tformat:'' --numstat --follow --find-copies-harder --reverse {} ';' | cut -f3- | grep '{.* => .*}'