Git: วิธีลบไฟล์ออกจากดัชนีโดยไม่ต้องลบไฟล์ออกจากที่เก็บใด ๆ


163

เมื่อคุณใช้

git rm --cached myfile

มันไม่ได้ลบออกจากระบบไฟล์ในเครื่องซึ่งเป็นเป้าหมาย แต่ถ้าคุณได้กำหนดเวอร์ชันและคอมมิตไฟล์แล้วให้พุชไปยังที่เก็บส่วนกลางและดึงไปไว้ในที่เก็บอื่นก่อนที่จะใช้คำสั่งมันจะลบไฟล์ออกจากระบบนั้น

มีวิธีการเพียงแค่ลบไฟล์จากเวอร์ชันโดยไม่ต้องลบมันออกจากระบบไฟล์ใด ๆ ?

แก้ไข: ชี้แจงฉันหวังว่า


บางทีคุณสามารถขยายกรณีการใช้ของคุณ ดัชนีเป็นพื้นที่จัดเตรียมสำหรับการส่งครั้งถัดไปดังนั้นทำไมคุณต้องการลบไฟล์ออกจากดัชนีหากคุณไม่ต้องการลบออกจากสาขาปัจจุบัน
CB Bailey

1
ฉันขอโทษ. ฉันหมายถึงว่าไฟล์ของฉันมีเหตุผลบางอย่างที่ได้รับการยอมรับและเผยแพร่มานานแล้ว ตอนนี้เป้าหมายคือการลบออกจากเวอร์ชันโดยไม่ต้องลบออกจากระบบของผู้คน เหตุผลนี้เกิดขึ้นเพราะฉันตั้งใจไฟล์ปรับแต่งรุ่น จำเป็นต้องใช้ไฟล์ปรับแต่งดังนั้นฉันไม่ต้องการลบมันออกจากระบบต่างประเทศ
Fletcher Moore

ฉันแก้ไขคำถามให้ชัดเจนยิ่งขึ้น
Fletcher Moore

3
git rm - ที่เก็บไว้จะไม่ลบไฟล์ออกจากไดเรกทอรีการทำงานอื่น ๆ ไฟล์จะถูกลบออกเฉพาะในกรณีที่มีคนทำงานในไดเรกทอรีนั้นทำการดึงข้อมูล สามารถกู้คืนไฟล์ได้อย่างง่ายดายด้วย "git checkout HEAD @ {1} foo" (หากดำเนินการทันทีหลังจากดึง)
William Pursell

คำตอบ:


119

ฉันไม่คิดว่าการคอมมิทสามารถบันทึกเจตนาเช่น“ หยุดติดตามไฟล์นี้ แต่อย่าลบมัน”

การประกาศเจตนาดังกล่าวจำเป็นต้องมีการแทรกแซงนอก Git ในที่เก็บใด ๆ ที่ผสาน (หรือ rebase สู่) การกระทำที่ลบไฟล์


บันทึกสำเนา, ใช้การลบ, กู้คืน

อาจเป็นวิธีที่ง่ายที่สุดที่จะทำคือบอกผู้ใช้ดาวน์สตรีมของคุณให้บันทึกสำเนาของไฟล์ดึงการลบของคุณแล้วกู้คืนไฟล์ หากพวกเขากำลังดึงผ่าน rebase และกำลัง 'ดำเนินการ' แก้ไขไฟล์พวกเขาจะได้รับความขัดแย้ง ในการแก้ไขข้อขัดแย้งดังกล่าวให้ใช้git rm foo.conf && git rebase --continue(หากการกระทำที่ขัดแย้งกันมีการเปลี่ยนแปลงนอกเหนือจากไฟล์ที่ถูกลบ) หรือgit rebase --skip(หากการกระทำที่ขัดแย้งกันนั้นเปลี่ยนไปเป็นไฟล์ที่ถูกลบเท่านั้น)

เรียกคืนไฟล์เป็นไม่ได้ติดตามหลังจากดึงคำสั่งที่ลบออกแล้ว

หากพวกเขาดึงการลบของคุณไปแล้วพวกเขายังสามารถกู้คืนเวอร์ชันก่อนหน้าของไฟล์ด้วยgit show :

git show @{1}:foo.conf >foo.conf

หรือด้วยการชำระเงิน git (ต่อความคิดเห็นโดย William Pursell; แต่อย่าลืมลบออกจากดัชนีอีกครั้ง!):

git checkout @{1} -- foo.conf && git rm --cached foo.conf

ถ้าพวกเขาได้กระทำการอื่น ๆ ตั้งแต่การดึงการลบของคุณ (หรือพวกเขาจะดึงกับ rebase เป็นหัวเดี่ยว) @{1}พวกเขาอาจต้องสิ่งอื่นที่ไม่ใช่ พวกเขาสามารถใช้git log -gเพื่อค้นหาการกระทำก่อนที่จะลบการลบของคุณ


ในความคิดเห็นคุณพูดถึงว่าไฟล์ที่คุณต้องการ“ ยกเลิกการติดตาม แต่เก็บไว้” เป็นไฟล์การกำหนดค่าบางชนิดที่จำเป็นสำหรับการเรียกใช้ซอฟต์แวร์ (โดยตรงจากที่เก็บ)

เก็บไฟล์เป็น 'เริ่มต้น' และเปิดใช้งานด้วยตนเอง / โดยอัตโนมัติ

หากไม่ยอมรับอย่างสมบูรณ์เพื่อรักษาเนื้อหาของไฟล์การกำหนดค่าในที่เก็บคุณอาจสามารถเปลี่ยนชื่อไฟล์ที่ถูกติดตามจาก (เช่น) foo.confไปยังfoo.conf.defaultจากนั้นสั่งให้ผู้ใช้ของคุณcp foo.conf.default foo.confหลังจากใช้การเปลี่ยนชื่อกระทำ หรือถ้าผู้ใช้ใช้พื้นที่เก็บข้อมูลที่มีอยู่แล้วบางส่วน (เช่นสคริปต์หรือโปรแกรมอื่นที่กำหนดค่าโดยเนื้อหาในพื้นที่เก็บข้อมูล (เช่นMakefileหรือคล้ายกัน)) เพื่อเรียกใช้ / ปรับใช้ซอฟต์แวร์ของคุณคุณสามารถรวมกลไกการเริ่มต้นลงใน ปรับใช้กระบวนการ:

test -f foo.conf || test -f foo.conf.default &&
    cp foo.conf.default foo.conf

ด้วยกลไกการตั้งค่าเริ่มต้นดังกล่าวผู้ใช้ควรจะสามารถดึงการกระทำที่เปลี่ยนชื่อfoo.confเป็นfoo.conf.defaultโดยไม่ต้องทำงานพิเศษใด ๆ นอกจากนี้คุณหลีกเลี่ยงการคัดลอกไฟล์กำหนดค่าด้วยตนเองหากคุณทำการติดตั้ง / ที่เก็บเพิ่มเติมในอนาคต

ประวัติการเขียนซ้ำต้องมีการแทรกแซงด้วยตนเองอย่างไรก็ตาม ...

git filter-branch --index-filter …ถ้ามันเป็นที่ยอมรับไม่ได้ที่จะรักษาเนื้อหาในพื้นที่เก็บข้อมูลแล้วคุณอาจจะต้องการที่จะสมบูรณ์กำจัดมันจากประวัติศาสตร์กับสิ่งที่ต้องการ จำนวนเงินนี้สำหรับการเขียนประวัติใหม่ซึ่งจะต้องมีการแทรกแซงด้วยตนเองสำหรับแต่ละสาขา / พื้นที่เก็บข้อมูล (ดูที่หัวข้อ“ การกู้คืนจากการอัปสตรีมรีบูต” ในgit rebase manpage ) การดูแลเป็นพิเศษที่จำเป็นสำหรับไฟล์กำหนดค่าของคุณจะเป็นเพียงขั้นตอนอื่นที่ต้องดำเนินการในขณะที่กู้คืนจากการเขียนใหม่:

  1. บันทึกสำเนาของไฟล์กำหนดค่า
  2. กู้คืนจากการเขียนใหม่
  3. กู้คืนไฟล์กำหนดค่า

ไม่ต้องสนใจเพื่อป้องกันการเกิดซ้ำ

ไม่ว่าคุณจะใช้วิธีใดคุณอาจต้องการรวมชื่อไฟล์การกำหนดค่าไว้ใน.gitignoreไฟล์ในที่เก็บเพื่อให้ไม่มีใครสามารถทำได้git add foo.confอีกครั้งโดยไม่ตั้งใจ(เป็นไปได้ แต่จำเป็นต้องมี-f/ --force) หากคุณมีมากกว่าหนึ่งไฟล์การกำหนดค่าคุณอาจพิจารณา 'ย้าย' พวกเขาทั้งหมดลงในไดเรกทอรีเดียวและละเว้นสิ่งทั้งหมด (โดย 'ย้าย' ฉันหมายถึงการเปลี่ยนแปลงที่โปรแกรมคาดว่าจะหาไฟล์การกำหนดค่าของมันและรับผู้ใช้ (หรือ กลไกการเรียกใช้ / ปรับใช้) เพื่อคัดลอก / ย้ายไฟล์ไปยังตำแหน่งใหม่ของพวกเขาแน่นอนคุณไม่ต้องการที่จะคอมไพล์ mvไฟล์ลงในไดเรกทอรีที่คุณจะไม่สนใจ)


5
การตอบสนองอย่างละเอียดอย่างไม่น่าเชื่อ ขอบคุณ!
ลูกธนูมัวร์

คำตอบของ Tom Power ด้านล่างดูเหมือนจะขัดแย้งกับประโยคแรกของคุณ
Mike S

1
@MikeS: ผลของการ--{,no-}assume-unchangedเป็นอย่างหมดจด: สถานะของมันไม่ได้ถูกบันทึกโดยตรงในการกระทำ มันสามารถช่วยป้องกันที่เก็บไม่ให้ยอมรับการเปลี่ยนแปลงใหม่กับไฟล์ แต่จะไม่ลบมันออกจากการควบคุมเวอร์ชัน หากคุณสามารถตั้งค่าให้กับที่เก็บข้อมูลที่เกี่ยวข้องและไม่เกี่ยวข้องทั้งหมดของคุณอาจช่วยสถานการณ์ของคุณได้ แต่ไม่ใช่สิ่งที่คุณสามารถกด + pull / rebase ลงในที่เก็บข้อมูลอื่นที่ไม่เกี่ยวข้องโดยตรงได้โดยตรงคุณไม่สามารถควบคุมได้ตามความเห็นของผู้ถามดั้งเดิมเกี่ยวกับคำถาม: ดูที่ "ระบบของผู้คน" / "ระบบต่างประเทศ")
Chris Johnsen

1
I do not think a Git commit can record an intention like “stop tracking this file, but do not delete it”.- ตอนนี้ทำได้ด้วยgit rm --cached foo.conf
Nick Volynkin

1
@NickVolynkin: คำถามนี้ไม่ได้ระบุว่าไม่เพียงพอสำหรับวัตถุประสงค์ของผู้ถาม: (โดยอัตโนมัติ) เก็บไฟล์ไว้รอบ ๆ เมื่อการคอมมิชชันผลลัพธ์ถูกดึงลงในที่เก็บอื่นหรือไม่?
Chris Johnsen

86

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

http://gitready.com/intermediate/2009/02/18/temporarily-ignoring-files.html

ทำงานได้ดีสำหรับฉันและไม่ได้กล่าวถึง

git update-index --assume-unchanged <file>

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

git update-index --no-assume-unchanged <file>

หากคุณเคยต้องการที่จะนำมันกลับมา

แก้ไข: โปรดดูความคิดเห็นจาก Chris Johnsen และ KPM ซึ่งจะใช้งานได้ในพื้นที่เท่านั้นและไฟล์ยังคงอยู่ภายใต้การควบคุมเวอร์ชันสำหรับผู้ใช้รายอื่นหากพวกเขาไม่ทำเช่นนั้น คำตอบที่ได้รับการยอมรับให้วิธีการที่สมบูรณ์ / ถูกต้องมากขึ้นสำหรับการจัดการกับสิ่งนี้ หมายเหตุจากลิงก์ด้วยหากใช้วิธีนี้:

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


7
นี่ไม่ใช่คำตอบสำหรับปัญหาเฉพาะที่กล่าวถึง มันจะทำงานเฉพาะกับที่เก็บข้อมูลในพื้นที่ของคุณเองดังนั้นผู้ใช้แต่ละคนต้องทำด้วยตนเอง มันเป็นความเจ็บปวด
KPM

28

หากต้องการลบไฟล์ออกจากดัชนีให้ใช้:

git reset myfile

สิ่งนี้ไม่ควรกระทบกับสำเนาในเครื่องของคุณหรือของบุคคลอื่น


1
resetลบไฟล์ออกจากดัชนีเท่านั้นหากไฟล์ไม่ได้อยู่ใน HEAD ปัจจุบันที่กระทำมิฉะนั้นจะเปลี่ยนกลับเวอร์ชันดัชนีเป็นเวอร์ชัน HEAD ปัจจุบัน
CB Bailey

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

ดังที่ชาร์ลส์กล่าวว่าการรีเซ็ตไม่ได้ "ลบไฟล์" พิมพ์ git help reset สำหรับข้อมูลเพิ่มเติม
Simon B.

4
วิธีนี้จะตอบคำถามในหัวข้อ "วิธีลบไฟล์ออกจากดัชนีโดยไม่ลบไฟล์ออกจากที่เก็บ" แม้ว่า OP จริง ๆ กำลังถามว่า "ฉันจะยกเลิกการติดตามไฟล์โดยไม่ลบสำเนาภายในเครื่องได้อย่างไร"
Hewsonism

@ hewsonism OP ได้พูดว่า "ระบบไฟล์ใด ๆ " (แม้กระทั่งก่อนการแก้ไขใด ๆ )
jbobbins


15

หลังจากทำgit rm --cachedคำสั่งแล้วให้ลองเพิ่มmyfileลงใน.gitignoreไฟล์ (สร้างหนึ่งไฟล์หากไม่มีอยู่) myfileนี้ควรจะบอกคอมไพล์ที่จะไม่สนใจ

.gitignoreไฟล์ versioned ดังนั้นคุณจะต้องกระทำมันและผลักดันให้พื้นที่เก็บข้อมูลระยะไกล


1

ทางออกของฉันคือการดึงสำเนาการทำงานอื่น ๆ แล้วทำ:

git log --pretty="format:" --name-only -n1 | xargs git checkout HEAD^1

ซึ่งระบุว่ารับพา ธ ไฟล์ทั้งหมดในความคิดเห็นล่าสุดและตรวจสอบจากพาเรนต์ของ HEAD งานเสร็จแล้ว


0

การแก้ปัญหาข้างต้นทำงานได้ดีสำหรับกรณีส่วนใหญ่ อย่างไรก็ตามหากคุณต้องการลบร่องรอยทั้งหมดของไฟล์นั้น (เช่นข้อมูลที่ละเอียดอ่อนเช่นรหัสผ่าน) คุณจะต้องลบไฟล์นั้นออกจากประวัติการกระทำทั้งหมดของคุณเนื่องจากไฟล์นั้นยังสามารถเรียกคืนได้จากที่นั่น

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

https://help.github.com/articles/remove-sensitive-data/

คุณสามารถข้ามไปยังขั้นตอนที่ 3 ได้หากคุณอยู่ในที่เก็บ git ในพื้นที่และไม่จำเป็นต้องทำแบบ dry run ในกรณีของฉันฉันต้องการเพียงขั้นตอนที่ 3 และ 6 เนื่องจากฉันได้สร้างไฟล์. gitignore ของฉันแล้วและอยู่ในที่เก็บที่ฉันต้องการทำงาน

หากต้องการดูการเปลี่ยนแปลงของคุณคุณอาจต้องไปที่รูท GitHub ของที่เก็บของคุณและรีเฟรชหน้า จากนั้นนำทางไปยังลิงก์ต่างๆเพื่อไปยังการกระทำที่เก่าซึ่งครั้งหนึ่งเคยมีไฟล์เพื่อดูว่าตอนนี้มันถูกลบไปแล้ว สำหรับฉันการรีเฟรชหน้าการผูกมัดเก่าไม่ได้แสดงการเปลี่ยนแปลง

มันดูน่ากลัวในตอนแรก แต่จริงๆแล้วมันง่ายและทำงานได้อย่างมีเสน่ห์! :-)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.