วิธีหนึ่งในการทำเช่นนี้คือการผกผัน - ลบทุกอย่างยกเว้นไฟล์ที่คุณต้องการเก็บไว้
โดยพื้นฐานแล้วให้ทำสำเนาของที่เก็บจากนั้นใช้git filter-branch
เพื่อลบทุกอย่างยกเว้นไฟล์ / โฟลเดอร์ที่คุณต้องการเก็บไว้
ตัวอย่างเช่นฉันมีโครงการที่ฉันต้องการแตกไฟล์tvnamer.py
ไปยังที่เก็บใหม่:
git filter-branch --tree-filter 'for f in *; do if [ $f != "tvnamer.py" ]; then rm -rf $f; fi; done' HEAD
ที่ใช้git filter-branch --tree-filter
เพื่อผ่านแต่ละคอมมิตรันคำสั่งและแนะนำเนื้อหาไดเร็กทอรีผลลัพธ์ นี่เป็นการทำลายล้างอย่างมาก (ดังนั้นคุณควรทำสิ่งนี้กับสำเนาของที่เก็บของคุณเท่านั้น!) และอาจใช้เวลาสักครู่ (ประมาณ 1 นาทีในที่เก็บที่มี 300 คอมมิตและประมาณ 20 ไฟล์)
คำสั่งด้านบนจะเรียกใช้เชลล์สคริปต์ต่อไปนี้ในการแก้ไขแต่ละครั้งซึ่งคุณต้องแก้ไขแน่นอน (เพื่อให้ไม่รวมไดเร็กทอรีย่อยของคุณแทนtvnamer.py
):
for f in *; do
if [ $f != "tvnamer.py" ]; then
rm -rf $f;
fi;
done
ปัญหาที่ชัดเจนที่สุดคือทิ้งข้อความคอมมิตทั้งหมดแม้ว่าจะไม่เกี่ยวข้องกับไฟล์ที่เหลือก็ตาม สคริปต์git-remove-empty-commitsแก้ไขสิ่งนี้ ..
git filter-branch --commit-filter 'if [ z$1 = z`git rev-parse $3^{tree}` ]; then skip_commit "$@"; else git commit-tree "$@"; fi'
คุณต้องใช้-f
อาร์กิวเมนต์บังคับเรียกใช้filter-branch
อีกครั้งกับอะไรก็ได้refs/original/
(ซึ่งโดยพื้นฐานแล้วเป็นข้อมูลสำรอง)
แน่นอนว่าสิ่งนี้จะไม่สมบูรณ์แบบเช่นหากข้อความคอมมิตของคุณพูดถึงไฟล์อื่น ๆ แต่มันก็ใกล้เคียงกับกระแสคอมไพล์ที่อนุญาต (เท่าที่ฉันรู้อยู่แล้ว)
อีกครั้งเรียกใช้สิ่งนี้บนสำเนาของที่เก็บของคุณเท่านั้น! - แต่โดยสรุปในการลบไฟล์ทั้งหมดยกเว้น "thisismyfilename.txt":
git filter-branch --tree-filter 'for f in *; do if [ $f != "thisismyfilename.txt" ]; then rm -rf $f; fi; done' HEAD
git filter-branch -f --commit-filter 'if [ z$1 = z`git rev-parse $3^{tree}` ]; then skip_commit "$@"; else git commit-tree "$@"; fi'