พยายามแก้ไขจุดสิ้นสุดของบรรทัดด้วย git filter-branch แต่ไม่มีโชค


270

ฉันถูกกัดโดยปัญหาการสิ้นสุดบรรทัด Windows / Linux ด้วย git ดูเหมือนว่าผ่าน GitHub, MSysGit และแหล่งข้อมูลอื่น ๆ ทางออกที่ดีที่สุดคือให้ repos ในพื้นที่ของคุณตั้งค่าให้ใช้การสิ้นสุดบรรทัดแบบลินุกซ์ แต่ตั้งค่าไว้core.autocrlftrueไป แต่น่าเสียดายที่ฉันไม่ได้ทำเร็วพอดังนั้นตอนนี้ทุกครั้งที่ฉันดึงการเปลี่ยนแปลงปลายสายจะถูกบอร์

ฉันคิดว่าฉันพบคำตอบแล้ว ที่นี่แต่ฉันไม่สามารถทำงานให้ฉันได้ ความรู้เกี่ยวกับบรรทัดคำสั่ง Linux ของฉันมี จำกัด อย่างดีที่สุดดังนั้นฉันจึงไม่แน่ใจด้วยซ้ำว่าบรรทัด "xargs fromdos" ทำอะไรในสคริปต์ของเขา ฉันได้รับข้อความเกี่ยวกับไม่มีไฟล์หรือไดเรกทอรีดังกล่าวอยู่และเมื่อฉันจัดการเพื่อชี้ไปยังไดเรกทอรีที่มีอยู่มันบอกฉันว่าฉันไม่มีสิทธิ์

ฉันได้ลองกับ MSysGit บน Windows และผ่านเทอร์มินัล Mac OS X


ฉันไม่สามารถลงคะแนนในหัวข้อนี้ได้เกือบจะเพียงพอ +1 ++ มันให้คำตอบที่ดีที่สุดในเรื่อง
sjas

เห็นด้วยกับชาร์ลส์ อย่างไรก็ตามในกรณีของฉัน (โดยใช้ Mac OS X 10.8)> git config core.autocrlf ทำงานผิดพลาดไม่ใช่> git config core.autocrlf อินพุต
user1045085

คำตอบ:


187

เอกสาร git สำหรับgitattributesตอนนี้เอกสารวิธีอื่นสำหรับ "แก้ไข" หรือ normalizing สิ้นสุดบรรทัดทั้งหมดในโครงการของคุณ นี่คือส่วนสำคัญของมัน:

$ echo "* text=auto" >.gitattributes
$ git add --renormalize .
$ git status        # Show files that will be normalized
$ git commit -m "Introduce end-of-line normalization"

หากไฟล์ใด ๆ ที่ไม่ควรทำให้เป็นมาตรฐานแสดงในสถานะ git ให้ยกเลิกการตั้งค่าแอตทริบิวต์ของข้อความก่อนเรียกใช้ git add -u

manual.pdf -text

ในทางกลับกันไฟล์ข้อความที่ git ตรวจไม่พบสามารถเปิดใช้งานการทำให้เป็นมาตรฐานได้ด้วยตนเอง

weirdchars.txt text

สิ่งนี้ใช้ประโยชน์จากการ--renormalizeตั้งค่าสถานะใหม่ที่เพิ่มใน git v2.16.0, เผยแพร่เมื่อมกราคม 2018 สำหรับ git รุ่นเก่ามีขั้นตอนเพิ่มเติมไม่กี่ขั้นตอน:

$ echo "* text=auto" >>.gitattributes
$ rm .git/index     # Remove the index to force git to
$ git reset         # re-scan the working directory
$ git status        # Show files that will be normalized
$ git add -u
$ git add .gitattributes
$ git commit -m "Introduce end-of-line normalization"

1
คุณช่วยบอกฉันหน่อยได้ไหมว่าจุดประสงค์ของgit resetมันคืออะไร
crdx

1
บังคับให้คอมไพล์สร้างดัชนีขึ้นใหม่ในระหว่างนั้นสแกนแต่ละไฟล์เพื่อคาดเดาว่าไบนารีของมันเป็นอย่างไร rm ลบดัชนีเก่ารีเซ็ตการสร้างดัชนีใหม่
Russ Egan

16
ขอบคุณสิ่งนี้ใช้ได้สำหรับฉัน คำสั่งที่มีประโยชน์หลังจากใช้งานgit statusคือเรียกใช้git diff --ignore-space-at-eolเพียงเพื่อให้แน่ใจว่าการเปลี่ยนแปลงที่คุณกระทำเท่านั้นคือการสิ้นสุดบรรทัด
zelanix

1
หมายเหตุ: ความแตกต่าง "ของจริง" เพียงอย่างเดียวระหว่างสิ่งนี้และโซลูชัน "เก่า" อยู่ในสถานะของ. gitattributes (มีเนื้อหาที่เหมาะสม) หากปราศจากสิ่งนี้git resetจะตรวจจับการดัดแปลงใด ๆ และไร้ประโยชน์
Rob

3
คำแนะนำเกี่ยวกับการgitattributesหน้าได้รับการปรับปรุงเพื่อใช้ประโยชน์จาก--renormalizeธงเพิ่มเข้ามาใน v2.16.0 คอมไพล์ซึ่งได้รับการปล่อยตัวในเดือนมกราคม 2018 ธงรวบรวมขั้นตอนการประมวลผลอีกครั้งตอนจบบรรทัดสำหรับแฟ้มติดตามในแต่ละคำสั่งเดียวนี้:--renormalize git add --renormalize .
Mike Hill

389

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

# From the root of your repository remove everything from the index
git rm --cached -r .

# Change the autocrlf setting of the repository (you may want 
#  to use true on windows):
git config core.autocrlf input

# Re-add all the deleted files to the index
# (You should get lots of messages like:
#   warning: CRLF will be replaced by LF in <file>.)
git diff --cached --name-only -z | xargs -0 git add

# Commit
git commit -m "Fixed crlf issue"

# If you're doing this on a Unix/Mac OSX clone then optionally remove
# the working tree and re-check everything out with the correct line endings.
git ls-files -z | xargs -0 rm
git checkout .

7
PS ฉันแนะนำการแก้ไขของคุณให้กับพวกที่ github.com และพวกเขาอัปเดตคู่มือช่วยเหลือของพวกเขาเพื่อใช้โซลูชันของคุณ (ก่อนหน้านี้เพิ่งแนะนำโคลนใหม่และรีเซ็ตฮาร์ดซึ่งดูเหมือนจะไม่ได้รับไฟล์ทั้งหมด) help.github com / การจัดการกับสายงาน
Brian Donahue

31
ขอบคุณ ... นี่เป็นการแก้ไขที่ยอดเยี่ยม พบได้ใน GitHub
PHLAK

4
คุณอาจต้องการตรวจสอบ config.safecrlf เพื่อให้แน่ใจว่าคุณไม่ได้เปลี่ยน crlfs ในไฟล์ที่ไม่ใช่ข้อความ (เช่นไบนารี) ตรวจสอบมันออกมาในเอกสารkernel.org/pub/software/scm/git/docs/git-config.html
vrish88

4
@ vrish88: หากคุณอยู่ในสถานการณ์เช่นนี้คุณมีแนวโน้มที่จะได้รับความทุกข์ทรมานจากการผสมในตอนจบและ core.safecrlf อาจป้องกันไม่ให้คุณทำสิ่งที่คุณต้องทำ มันอาจจะง่ายกว่าที่จะไม่ใช้ safecrlf git มักจะไม่ได้รับการตรวจจับไฟล์ไบนารีที่ไม่ถูกต้องและหากคุณสามารถทำเครื่องหมายด้วยตนเองว่าเป็นไบนารีด้วย. gitattribute และกู้คืนเวอร์ชันที่ถูกต้องจากการกระทำก่อนหน้า
CB Bailey

26
โซลูชันที่ใหม่กว่าที่แนะนำในคำตอบของ Russ Eganด้านล่างนั้นง่ายกว่าและไม่เกี่ยวข้องกับสิ่งที่น่ากลัวเช่นการลบซอร์สโค้ดทั้งหมดของคุณดังนั้นฉันขอแนะนำให้ผู้ใช้งานคนนั้นแม้ว่าโซลูชั่นเก่านี้จะมี 10 เท่า!
Porculus

11

โพรซีเดอร์ของฉันสำหรับจัดการกับจุดสิ้นสุดของบรรทัดมีดังนี้ (การทดสอบการต่อสู้บน repos จำนวนมาก):

เมื่อสร้าง repo ใหม่:

  • ใส่.gitattributesในการกระทำแรกพร้อมกับไฟล์ทั่วไปอื่น ๆ เช่น .gitignoreและREADME.md

เมื่อจัดการกับ repo ที่มีอยู่:

  • สร้าง / แก้ไข.gitattributesตามลำดับ
  • git commit -a -m "Modified gitattributes"
  • git rm --cached -r . && git reset --hard && git commit -a -m 'Normalize CRLF' -n"
    • -n (--no-verifyคือการข้าม hooks ก่อนการกระทำ)
    • ฉันต้องทำบ่อยพอที่จะนิยามว่าเป็นนามแฝง alias fixCRLF="..."
  • ทำซ้ำคำสั่งก่อนหน้า
    • ใช่มันเป็น voodoo แต่โดยทั่วไปฉันต้องเรียกใช้คำสั่งสองครั้งครั้งแรกที่มันทำให้ไฟล์บางไฟล์เป็นปกติ โดยทั่วไปอาจเป็นการดีที่สุดที่จะทำซ้ำจนกว่าจะไม่มีการสร้างการมอบหมายใหม่ :)
  • ย้อนกลับไปมาระหว่างเก่า (ก่อนการฟื้นฟู) และสาขาใหม่สองสามครั้ง หลังจากเปลี่ยนสาขาบางครั้งคอมไพล์ก็จะพบไฟล์จำนวนมากที่จำเป็นต้องเปลี่ยนรูปแบบใหม่!

ใน.gitattributesฉันประกาศไฟล์ข้อความทั้งหมดอย่างชัดเจนว่ามี LF EOL เนื่องจากโดยทั่วไปแล้วการใช้เครื่องมือของ Windows นั้นเข้ากันได้กับ LF ในขณะที่เครื่องมือที่ไม่ใช่ Windows ไม่สามารถทำงานร่วมกับ CRLF (แม้แต่เครื่องมือบรรทัดคำสั่ง nodejs จำนวนมากถือว่า LF และด้วยเหตุนี้

เนื้อหาของ .gitattributes

ฉัน.gitattributesมักจะดูเหมือนว่า:

*.html eol=lf
*.js   eol=lf
*.json eol=lf
*.less eol=lf
*.md   eol=lf
*.svg  eol=lf
*.xml  eol=lf

หากต้องการทราบว่าส่วนขยายใดบ้างที่ถูกติดตามโดย git ใน repo ปัจจุบันดูที่นี่

ปัญหาหลังการทำให้เป็นมาตรฐาน

เมื่อทำสิ่งนี้เสร็จแล้วก็มีข้อแม้ทั่วไปอีกข้อหนึ่งไว้

สมมติว่าคุณmasterมีอยู่แล้ว up-to-date outdated-branchและปกติและจากนั้นคุณชำระเงิน ค่อนข้างบ่อยหลังจากตรวจสอบจากสาขานั้น git ทำเครื่องหมายไฟล์หลายไฟล์ว่ามีการปรับเปลี่ยน

การแก้ปัญหาคือการทำปลอมกระทำ ( git add -A . && git commit -m 'fake commit') git rebase masterแล้ว หลังจากการปฎิบัติการกระทำที่ผิด ๆ ควรจะหายไป


1
ฉันคิดว่าฉันบ้าไปแล้วจนกว่าฉันจะอ่านโพสต์ของคุณเพราะฉันต้องใช้คำสั่งตามลำดับที่ระบุหลายครั้งเช่นกัน วูดู! ;)
Sean Fausett

ในเวอร์ชัน git 2.7.0.windows.1ฉันใช้สิ่งต่อไปนี้: git rm --cached -r . && git reset --hard && git add . && git commit -m "Normalize EOL" -n
Sean Fausett

4
git status --short|grep "^ *M"|awk '{print $2}'|xargs fromdos

คำอธิบาย:

  • git status --short

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

  • grep "^ *M"

    ตัวกรองนี้จะกรองเฉพาะไฟล์ที่ถูกแก้ไขเท่านั้น

  • awk '{print $2}'

    นี่แสดงเฉพาะชื่อไฟล์ที่ไม่มีเครื่องหมายใด ๆ

  • xargs fromdos

    ซึ่งจะใช้ชื่อไฟล์จากคำสั่งก่อนหน้าและเรียกใช้ผ่านยูทิลิตี้ 'fromdos' เพื่อแปลง line-endings


นี่มันเจ๋งมาก. ขอบคุณ. สำหรับใครที่กำลังมองหาวิธีการแก้ปัญหาโดยใช้การใช้ Homebrew แทนdos2unix fromdos
Almir Sarajčić

4

git filter-branchนี่คือวิธีที่ฉันคงจบบรรทัดทั้งหมดในประวัติศาสตร์ทั้งหมดใช้ ^Mตัวละครจะต้องมีการป้อนโดยใช้+CTRL-V CTRL-Mฉันเคยdos2unixแปลงไฟล์ตั้งแต่นี้จะข้ามไฟล์ไบนารีโดยอัตโนมัติ

$ git filter-branch --tree-filter 'grep -IUrl "^M" | xargs -I {} dos2unix "{}"'


3

"| xargs fromdos" อ่านจากอินพุตมาตรฐาน (ไฟล์findค้นหา) และใช้เป็นอาร์กิวเมนต์สำหรับคำสั่งfromdosซึ่งแปลงบรรทัดสิ้นสุด (เป็นมาตรฐานจากในสภาพแวดล้อมเหล่านั้นหรือไม่ฉันคุ้นเคยกับ dos2unix) โปรดทราบว่าคุณสามารถหลีกเลี่ยงการใช้ xargs (มีประโยชน์อย่างยิ่งหากคุณมีไฟล์เพียงพอที่รายการอาร์กิวเมนต์ยาวเกินไปสำหรับ xargs):

find <path, tests...> -exec fromdos '{}' \;

หรือ

find <path, tests...> | while read file; do fromdos $file; done

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

วิธีง่ายๆในการรับข้อผิดพลาด 'ไม่พบไฟล์' สำหรับสคริปต์คือการใช้พา ธ สัมพัทธ์ - ใช้อันที่แน่นอน ในทำนองเดียวกันคุณอาจได้รับข้อผิดพลาดในการอนุญาตหากคุณไม่ได้ทำให้สคริปต์ของคุณทำงานได้ (chmod + x)

เพิ่มความคิดเห็นและฉันจะลองและช่วยคุณออก!


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

1

โอเค ... ภายใต้ cygwin เราไม่สามารถใช้งาน fromdos ได้ง่ายและ substeb awk นั้นระเบิดหน้าของคุณถ้าคุณมีช่องว่างในพา ธ ไปยังไฟล์ที่แก้ไข (ซึ่งเรามี) ดังนั้นฉันต้องทำสิ่งนั้นค่อนข้างแตกต่าง:

git status --short | grep "^ *M" | sed 's/^ *M//' | xargs -n 1 dos2unix

รุ่งโรจน์ถึง @lloyd สำหรับกลุ่มของโซลูชันนี้


-2

ทำตามขั้นตอนเหล่านี้หากไม่มีคำตอบอื่นใดที่เหมาะกับคุณ:

  1. หากคุณใช้ Windows ให้ทำ git config --global core.autocrlf true ; ถ้าคุณอยู่บน Unix ให้ทำgit config core.autocrlf input
  2. วิ่ง git rm --cached -r .
  3. ลบไฟล์ .gitattributes
  4. วิ่ง git add -A
  5. วิ่ง git reset --hard

ถ้าอย่างนั้นท้องถิ่นของคุณควรจะสะอาด


4
จริงๆ? การลบ.gitattributesไฟล์เป็นวิธีแก้ปัญหาการจบบรรทัดหรือไม่
Aleksandr M

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