วัตถุประสงค์
- ใช้(แรงบันดาลใจจากSmarยืมมาจากExherbo )
git am
- เพิ่มประวัติการส่งไฟล์ที่คัดลอกหรือย้าย
- จากไดเรกทอรีหนึ่งไปยังอีก
- หรือจากที่เก็บหนึ่งไปอีกที่หนึ่ง
การ จำกัด
- แท็กและสาขาจะไม่ถูกเก็บไว้
- ประวัติถูกตัดในการเปลี่ยนชื่อไฟล์พา ธ (เปลี่ยนชื่อไดเรกทอรี)
สรุป
- แยกประวัติในรูปแบบอีเมลโดยใช้
git log --pretty=email -p --reverse --full-index --binary
- จัดโครงสร้างไฟล์ต้นไม้ใหม่และอัปเดตชื่อไฟล์
- ผนวกประวัติใหม่โดยใช้
cat extracted-history | git am --committer-date-is-author-date
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 the folder
แยกประวัติของแต่ละไฟล์ในรูปแบบอีเมล
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
Dan Bonacheaแนะนำให้ย้อนกลับลูปของคำสั่งการสร้างบันทึก git ในขั้นตอนแรกนี้: แทนที่จะเรียกใช้บันทึก git หนึ่งครั้งต่อไฟล์ให้เรียกใช้หนึ่งครั้งด้วยรายการไฟล์ในบรรทัดคำสั่งและสร้างบันทึกรวมเดียว วิธีนี้กระทำที่แก้ไขหลายไฟล์ยังคงกระทำเดียวในผลและกระทำใหม่ทั้งหมดรักษาลำดับเดิมของพวกเขา โปรดทราบว่าสิ่งนี้ยังต้องมีการเปลี่ยนแปลงในขั้นตอนที่สองด้านล่างเมื่อเขียนชื่อไฟล์ใหม่ในบันทึก (รวมตอนนี้)
2. จัดระเบียบไฟล์ต้นไม้ใหม่และอัปเดตชื่อไฟล์
สมมติว่าคุณต้องการย้ายไฟล์ทั้งสามนี้ใน repo อื่น (อาจเป็น repo เดียวกัน)
my_other_repo
├── dirF
│ ├── file55
│ └── file56
├── dirB # New tree
│ ├── dirB1 # from subdir
│ │ ├── file33 # from file3
│ │ └── file44 # from file4
│ └── dirB2 # new dir
│ └── file5 # from file5
└── dirH
└── file77
ดังนั้นจัดระเบียบไฟล์ของคุณใหม่:
cd /tmp/mail/dir
mkdir -p dirB/dirB1
mv subdir/file3 dirB/dirB1/file33
mv subdir/file4 dirB/dirB1/file44
mkdir -p 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 --committer-date-is-author-date
--committer-date-is-author-date
รักษาตราประทับเวลาเดิม ( ความคิดเห็นของDan Bonachea )
repo อื่นของคุณคือตอนนี้:
my_other_repo
├── dirF
│ ├── file55
│ └── file56
├── dirB
│ ├── dirB1
│ │ ├── file33
│ │ └── file44
│ └── dirB2
│ └── file5
└── dirH
└── file77
ใช้git status
เพื่อดูจำนวนการกระทำที่พร้อมจะผลักดัน :-)
เคล็ดลับพิเศษ: ตรวจสอบไฟล์ที่ถูกเปลี่ยนชื่อ / ย้ายภายใน repo ของคุณ
หากต้องการแสดงรายการไฟล์ที่ถูกเปลี่ยนชื่อ:
find -name .git -prune -o -exec git log --pretty=tformat:'' --numstat --follow {} ';' | grep '=>'
การปรับแต่งเพิ่มเติมได้ที่: คุณสามารถดำเนินการคำสั่งgit log
โดยใช้ตัวเลือกหรือ--find-copies-harder
--reverse
นอกจากนี้คุณยังสามารถลบสองคอลัมน์แรกโดยใช้cut -f3-
และ grepping pattern ที่สมบูรณ์ '{. * =>. *}'
find -name .git -prune -o -exec git log --pretty=tformat:'' --numstat --follow --find-copies-harder --reverse {} ';' | cut -f3- | grep '{.* => .*}'
git mv
: stackoverflow.com/questions/1094269/whats-the-purpose-of-git-mv