การดำเนินการคัดลอกไฟล์บันทึกด้วย Git


141

เมื่อฉันย้ายไฟล์ใน git โดยใช้ git-mv สถานะแสดงให้เห็นว่าไฟล์นั้นถูกเปลี่ยนชื่อและแม้ว่าฉันจะเปลี่ยนบางส่วนมันก็ยังถือว่าเกือบจะเหมือนกัน (ซึ่งดีเพราะมันทำให้ฉันติดตามประวัติของมัน) .

เมื่อฉันคัดลอกไฟล์ไฟล์ต้นฉบับจะมีประวัติฉันต้องการเชื่อมโยงกับสำเนาใหม่

ฉันลองย้ายไฟล์แล้วลองเช็คเอาต์อีกครั้งในตำแหน่งเดิม - เมื่อย้ายคอมไพล์แล้วจะไม่ให้ฉันเช็คเอาต์ตำแหน่งเดิม

ฉันลองคัดลอกระบบไฟล์แล้วเพิ่มไฟล์ - git แสดงว่าเป็นไฟล์ใหม่

มีวิธีใดที่จะทำให้คอมไพล์บันทึกการดำเนินการคัดลอกไฟล์ในทำนองเดียวกันกับวิธีบันทึกการเปลี่ยนชื่อ / ย้ายไฟล์โดยที่สามารถติดตามประวัติย้อนกลับไปยังไฟล์ต้นฉบับได้หรือไม่?

คำตอบ:


112

Git ไม่ทำการเปลี่ยนชื่อการติดตามหรือการคัดลอกการติดตามซึ่งหมายความว่าจะไม่บันทึกการเปลี่ยนชื่อหรือคัดลอก สิ่งที่มันไม่แทนคือการเปลี่ยนชื่อและสำเนาการตรวจสอบ คุณสามารถขอตรวจสอบการเปลี่ยนชื่อในgit diff(และgit show) โดยใช้-Mตัวเลือกที่คุณสามารถขอตรวจสอบการคัดลอกเพิ่มเติมในไฟล์การเปลี่ยนแปลงโดยใช้-Cตัวเลือก ( -Cหมายถึง-M) และคุณสามารถขอตรวจสอบการคัดลอกมีราคาแพงมากขึ้นในหมู่ไฟล์ทั้งหมดที่มี--find-copies-harderหรือ-C -C(ซึ่งหมายถึง-Cซึ่งหมายถึง-M) ดูmanpage git-diff

คุณยังสามารถกำหนดค่าคอมไพล์ที่จะลงมือทำในการตรวจสอบการเปลี่ยนชื่อโดยการตั้งค่าdiff.renamesให้เป็นค่าที่แท้จริงของบูล (เช่นtrueหรือ1) และคุณสามารถขอคอมไพล์ที่จะทำสำเนาการตรวจสอบเช่นกันด้วยการตั้งค่าให้หรือcopy copiesดูmanpage git-config

ตรวจสอบนอกจากนี้ยังมี-lตัวเลือกในการและการกำหนดค่าตัวแปรที่เกี่ยวข้องgit diffdiff.renameLimit


โปรดทราบว่าการgit log <pathspec>ทำงานแตกต่างกันใน Git: นี่<pathspec>คือชุดของตัวคั่นเส้นทางที่เส้นทางสามารถเป็นชื่อไดเรกทอรี (ย่อย) มันกรองและลดความซับซ้อนของประวัติศาสตร์ก่อนที่จะเปลี่ยนชื่อและตรวจจับการคัดลอกเข้ามาเล่น หากคุณต้องการติดตามการเปลี่ยนชื่อและการทำสำเนาให้ใช้git log --follow <filename>(ซึ่งในปัจจุบันมีจำนวน จำกัด และใช้ได้กับไฟล์เดียวเท่านั้น)


1
@allyourcode: สิ่งที่คุณสับสนเกี่ยวกับ? หากต้องการเปิดใช้งานการตรวจจับการทำสำเนาตามค่าเริ่มต้นคุณdiff.renamesต้องตั้งค่าเป็นcopies(เช่น ' git config diff.renames copies') ฉันเห็นด้วยว่ามันค่อนข้างใช้งานง่าย
Jakub Narębski

ส่วนที่ฉันไม่สามารถแยกวิเคราะห์ได้คือ "และคุณสามารถขอให้ทำตามค่าเริ่มต้นและเปลี่ยนชื่อการตรวจจับได้" คุณกำลังบอกว่ามีค่าสี่ค่าที่แตกต่างกันชื่อเกมสามารถใช้ (จริง, 1, คัดลอก, คัดลอก) และพวกเขาทั้งหมดทำสิ่งเดียวกันได้หรือไม่?
allyourcode

1
@allyourcode: ฉันขอโทษฉันไม่ได้สังเกตสิ่งนี้ แก้ไขแล้วขอบคุณ
Jakub Narębski

4
@ peschü: Git ใช้ฐานข้อมูลวัตถุที่ระบุเนื้อหาเป็นที่เก็บข้อมูล เนื้อหาไฟล์ถูกเก็บไว้ในเนื้อหา 'หยด' ภายใต้ที่อยู่ซึ่งเป็นเนื้อหาของ SHA-1 (เช่นเนื้อหา + ความยาว + เนื้อหา) ซึ่งหมายความว่าเนื้อหาที่ได้รับจะถูกเก็บไว้เพียงครั้งเดียว nb การขจัดข้อมูลซ้ำซ้อนอัตโนมัตินี้เป็นเหตุผลที่อยู่เบื้องหลังการสร้างระบบสำรองข้อมูล "bup" โดยใช้รูปแบบแพ็ค git
Jakub Narębski

1
ซึ่งแตกต่างจากวิธีการแก้ปัญหาด้านล่างนี้ไม่สามารถใช้ได้กับการติดตามการเปลี่ยนแปลงในช่วง บันทึก Git อนุญาตให้มีการโต้แย้งในช่วง ( git log -L123,456:file.xyz) ที่ตามหลังการเปลี่ยนชื่ออย่างถูกต้อง แต่ไม่ใช่การคัดลอกและคุณไม่สามารถผ่าน - ติดตามในกรณีนั้น นอกจากนี้ AFAICT สิ่งนี้ไม่สามารถใช้ได้กับการตำหนิคอมไพล์
Clément

57

2020-05-19: โซลูชันต่อไปนี้มีข้อดีของการไม่เปลี่ยนแปลงบันทึกของไฟล์ต้นฉบับไม่สร้างความขัดแย้งผสานและสั้นลง

คุณสามารถบังคับให้ Git ตรวจสอบประวัติของไฟล์ที่ถูกคัดลอกได้สามคอมมิท:

  • แทนที่จะคัดลอกสลับไปที่สาขาใหม่และย้ายไฟล์ไปยังตำแหน่งใหม่ที่นั่น
  • เพิ่มไฟล์ต้นฉบับใหม่ที่นั่น
  • --no-ffผสานสาขาใหม่สาขาเดิมที่มีตัวเลือกที่ไม่มีข้างหน้าอย่างรวดเร็ว

(เครดิตไปที่Raymond Chen )


วิธีการแก้ปัญหาเดิมมีสี่กระทำ:

  • แทนที่จะคัดลอกสลับไปที่สาขาใหม่และย้ายไฟล์ไปยังตำแหน่งใหม่ที่นั่น
  • เปลี่ยนเป็นสาขาดั้งเดิมและเปลี่ยนชื่อไฟล์
  • ผสานสาขาใหม่เข้ากับสาขาเดิมแก้ไขความขัดแย้งเล็กน้อยโดยการรักษาทั้งสองไฟล์
  • กู้คืนชื่อไฟล์ต้นฉบับในการส่งที่แยกต่างหาก

(โซลูชันนำมาจากhttps://stackoverflow.com/a/44036771/1389680 )


7
ความเรียบง่ายกะทัดรัด 100% ... คำตอบนี้เป็นบริการสาธารณะ ... upvoting ทุกอย่างที่เห็น
ptim

1
อะไรคือความแตกต่างระหว่างmoveและrename?
vovan

@ vovan คุณหมายถึงความจริงที่ว่าในทุบตีคุณจะใช้mvสำหรับการดำเนินงานทั้งสอง? ฉันใช้ 'ย้าย' สำหรับกรณีที่อาจเกี่ยวข้องกับการเปลี่ยนไดเรกทอรีของไฟล์และ 'เปลี่ยนชื่อ' สำหรับกรณีที่ไม่มี
Robert Pollak

2
ฉันพยายามติดตามสูตรนี้ (ใหม่) และมันใช้งานไม่ได้ มันอาจช่วยถ้าคุณแสดงคำสั่งจริง
Greg Lindahl

1
@RobertPollak ฉันลองรุ่นนี้มาหลายรุ่นแล้วแต่ใช้งานไม่ได้ โดย "ย้ายไฟล์" คุณหมายถึงgit mv orig newอะไร โดย "readd the original" คุณหมายถึงcp new orig && git add origอะไร
ᆼᆺᆼ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.