ทำให้ git ลบช่องว่างต่อท้ายโดยอัตโนมัติก่อนคอมมิท


220

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

ฉันพยายามเพิ่มไฟล์ต่อไปนี้ตาม~/.gitconfigไฟล์ แต่ไม่ได้ทำอะไรเมื่อฉันส่งมอบ อาจจะออกแบบมาเพื่อสิ่งที่แตกต่าง ทางออกคืออะไร?

[core]
    whitespace = trailing-space,space-before-tab
[apply]
    whitespace = fix

ฉันใช้ทับทิมในกรณีที่มีใครมีความคิดเฉพาะทับทิม การจัดรูปแบบรหัสอัตโนมัติก่อนที่จะส่งมอบจะเป็นขั้นตอนต่อไป แต่นั่นเป็นปัญหาที่ยากและไม่ก่อให้เกิดปัญหาใหญ่จริงๆ


หากคำสั่ง core.whitespace ไม่สามารถแก้ไขปัญหาของคุณคุณยังสามารถเปลี่ยน hook ก่อนการมอบหมาย (.git / hooks / pre-commit) เพื่อค้นหาและแก้ไขปัญหาให้คุณได้ ดูโพสต์นี้สำหรับคำอธิบายโดยละเอียด
VolkA

2
ฉันหงุดหงิดกับข้อผิดพลาดช่องว่างที่คล้ายกันและการแก้ปัญหาบางส่วนและเขียนยูทิลิตี้ที่มีความยืดหยุ่นและค่อนข้างสมบูรณ์ซึ่งสามารถแก้ไขหรือรายงานข้อผิดพลาดของช่องว่างที่ระบบควบคุมเวอร์ชันเบดวิล: Whitespace Total Fixer บน Github (ขอโทษด้วย
Dan Lenski

คำตอบ:


111

การตั้งค่าเหล่านั้น ( core.whitespaceและapply.whitespace) ไม่ได้อยู่ที่นั่นเพื่อลบช่องว่างต่อท้าย แต่ไปที่:

  • core.whitespace: ตรวจจับและเพิ่มข้อผิดพลาด
  • apply.whitespace: และเปลื้องผ้า แต่เฉพาะในระหว่างการแก้ไขไม่ใช่ "เสมอโดยอัตโนมัติ"

ฉันเชื่อว่าgit hook pre-commitมันจะทำงานได้ดีขึ้นสำหรับสิ่งนั้น (รวมถึงการลบช่องว่างต่อท้าย)


โปรดทราบว่าในเวลาใดก็ตามคุณสามารถเลือกที่จะไม่เรียกใช้pre-commitเบ็ด:

  • ชั่วคราว: git commit --no-verify .
  • ถาวร: cd .git/hooks/ ; chmod -x pre-commit

คำเตือน: โดยค่าเริ่มต้นpre-commitสคริปต์ (เช่นนี้ ) ไม่มีคุณลักษณะ "ลบต่อท้าย" แต่มีคุณสมบัติ "คำเตือน" เช่น:

if (/\s$/) {
    bad_line("trailing whitespace", $_);
}

อย่างไรก็ตามคุณสามารถสร้างpre-commitเบ็ดที่ดีกว่าโดยเฉพาะเมื่อคุณพิจารณาว่า:

การกระทำใน Git กับการเปลี่ยนแปลงเพียงบางส่วนเพื่อเพิ่มพื้นที่การแสดงละครยังผลในการแก้ไข“อะตอม” ที่ไม่อาจมีชีวิตอยู่เป็นสำเนาการทำงานและอาจไม่ทำงาน


ยกตัวอย่างเช่นoldmanเสนอในคำตอบอื่นpre-commitเบ็ดซึ่งตรวจสอบและลบช่องว่าง
เนื่องจาก hook นั้นได้รับชื่อไฟล์ของแต่ละไฟล์ฉันขอแนะนำให้ระวังไฟล์บางประเภท: คุณไม่ต้องการลบช่องว่างต่อท้ายใน.mdไฟล์ (markdown)!


1
ปรากฎว่าสามารถใช้ git ในการแก้ไขช่องว่างในสำเนางานของคุณได้apply.whitespaceโดยการหลอกให้คอมไพล์จัดการกับการเปลี่ยนแปลงสำเนาทำงานเป็นแพตช์ ดูคำตอบของฉันด้านล่าง
ntc2

> "คุณไม่ต้องการลบช่องว่างต่อท้ายในไฟล์. md (markdown)" - ทำไมจึงเป็นเช่นนั้น จุดประสงค์ของการติดตามช่องว่างในไฟล์มาร์กดาวน์คืออะไร? ฉันสังเกตเห็นว่าบาง.editorconfigไฟล์มีกฎเฉพาะสำหรับเรื่องนั้น
friederbluemle

5
@friederbluemle ขึ้นอยู่กับประเภทของ markdown เครื่องหมายเว้นวรรคคู่ท้ายระบุ<br>: github.com/FriendsOfPHP/PHP-CS-Fixer/issues/ …
VonC

การตั้งค่าcore.whitespaceจะtrailing-spaceมีgit configไม่เพิ่มข้อผิดพลาดเมื่อผู้ต้องหาในgit2.5.0
Karl Richter

43

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

ใช่มันเป็นแฮ็ค


โซลูชั่นที่แข็งแกร่ง

นามแฝง Git ต่อไปนี้จะนำมาจาก ฉัน~/.gitconfig

โดย "strong" ฉันหมายถึงนามแฝงเหล่านี้ทำงานโดยไม่มีข้อผิดพลาดทำสิ่งที่ถูกต้องไม่ว่าต้นไม้หรือดัชนีจะสกปรก อย่างไรก็ตามมันจะไม่ทำงานหากการโต้ตอบgit rebase -iนั้นกำลังดำเนินการอยู่ ดูของฉัน~/.gitconfigสำหรับการตรวจสอบเพิ่มเติมหากคุณสนใจเกี่ยวกับกรณีมุมนี้ที่git add -eเคล็ดลับที่อธิบายในตอนท้ายควรจะทำงาน

หากคุณต้องการเรียกใช้โดยตรงในเชลล์โดยไม่ต้องสร้างนามแฝง Git เพียงแค่คัดลอกและวางทุกอย่างระหว่างเครื่องหมายคำพูดคู่ (สมมติว่าเชลล์ของคุณเหมือน Bash)

แก้ไขดัชนี แต่ไม่ใช่ต้นไม้

fixwsนามแฝง Git ต่อไปนี้แก้ไขข้อผิดพลาดช่องว่างทั้งหมดในดัชนีถ้ามี แต่ไม่ได้แตะที่ต้นไม้:

# Logic:
#
# The 'git stash save' fails if the tree is clean (instead of
# creating an empty stash :P). So, we only 'stash' and 'pop' if
# the tree is dirty.
#
# The 'git rebase --whitespace=fix HEAD~' throws away the commit
# if it's empty, and adding '--keep-empty' prevents the whitespace
# from being fixed. So, we first check that the index is dirty.
#
# Also:
# - '(! git diff-index --quiet --cached HEAD)' is true (zero) if
#   the index is dirty
# - '(! git diff-files --quiet .)' is true if the tree is dirty
#
# The 'rebase --whitespace=fix' trick is from here:
# https://stackoverflow.com/a/19156679/470844
fixws = !"\
  if (! git diff-files --quiet .) && \
     (! git diff-index --quiet --cached HEAD) ; then \
    git commit -m FIXWS_SAVE_INDEX && \
    git stash save FIXWS_SAVE_TREE && \
    git rebase --whitespace=fix HEAD~ && \
    git stash pop && \
    git reset --soft HEAD~ ; \
  elif (! git diff-index --quiet --cached HEAD) ; then \
    git commit -m FIXWS_SAVE_INDEX && \
    git rebase --whitespace=fix HEAD~ && \
    git reset --soft HEAD~ ; \
  fi"

แนวคิดคือการเรียกใช้git fixwsก่อนgit commitถ้าคุณมีข้อผิดพลาดช่องว่างในดัชนี

แก้ไขดัชนีและต้นไม้

fixws-global-tree-and-indexนามแฝง Git ต่อไปนี้แก้ไขข้อผิดพลาดช่องว่างทั้งหมดในดัชนีและต้นไม้ถ้ามี:

# The different cases are:
# - dirty tree and dirty index
# - dirty tree and clean index
# - clean tree and dirty index
#
# We have to consider separate cases because the 'git rebase
# --whitespace=fix' is not compatible with empty commits (adding
# '--keep-empty' makes Git not fix the whitespace :P).
fixws-global-tree-and-index = !"\
  if (! git diff-files --quiet .) && \
     (! git diff-index --quiet --cached HEAD) ; then \
    git commit -m FIXWS_SAVE_INDEX && \
    git add -u :/ && \
    git commit -m FIXWS_SAVE_TREE && \
    git rebase --whitespace=fix HEAD~2 && \
    git reset HEAD~ && \
    git reset --soft HEAD~ ; \
  elif (! git diff-files --quiet .) ; then \
    git add -u :/ && \
    git commit -m FIXWS_SAVE_TREE && \
    git rebase --whitespace=fix HEAD~ && \
    git reset HEAD~ ; \
  elif (! git diff-index --quiet --cached HEAD) ; then \
    git commit -m FIXWS_SAVE_INDEX && \
    git rebase --whitespace=fix HEAD~ && \
    git reset --soft HEAD~ ; \
  fi"

หากต้องการแก้ไขช่องว่างในไฟล์ที่ไม่มีเวอร์ชันให้ทำ

git add --intent-to-add <unversioned files> && git fixws-global-tree-and-index

โซลูชันที่เรียบง่าย แต่ไม่แข็งแกร่ง

เวอร์ชันเหล่านี้ง่ายต่อการคัดลอกและวาง แต่ไม่ได้ทำสิ่งที่ถูกต้องหากไม่พบเงื่อนไขด้านข้าง

แก้ไขรากต้นไม้ย่อยที่ไดเรกทอรีปัจจุบัน (แต่รีเซ็ตดัชนีหากยังไม่ว่าง)

การใช้git add -eเพื่อ "แก้ไข" แพตช์ด้วยตัวแก้ไขข้อมูลประจำตัว::

(export GIT_EDITOR=: && git -c apply.whitespace=fix add -ue .) && git checkout . && git reset

แก้ไขและเก็บรักษาดัชนี (แต่ล้มเหลวหากต้นไม้สกปรกหรือดัชนีว่างเปล่า)

git commit -m TEMP && git rebase --whitespace=fix HEAD~ && git reset --soft HEAD~

แก้ไขแผนผังและดัชนี (แต่จะรีเซ็ตดัชนีหากไม่มีข้อมูลว่างเปล่า)

git add -u :/ && git commit -m TEMP && git rebase --whitespace=fix HEAD~ && git reset HEAD~

คำอธิบายของexport GIT_EDITOR=: && git -c apply.whitespace=fix add -ue .เคล็ดลับ

ก่อนที่ฉันจะเรียนรู้เกี่ยวกับgit rebase --whitespace=fixเคล็ดลับจากคำตอบนี้ฉันใช้git addเคล็ดลับที่ซับซ้อนกว่านี้ทุกที่

ถ้าเราทำด้วยตนเอง:

  1. ตั้งค่าapply.whitespaceเป็นfix(คุณจะต้องทำสิ่งนี้เพียงครั้งเดียว):

    git config apply.whitespace fix
    

    นี้จะบอก Git เพื่อแก้ไขช่องว่างในแพทช์

  2. โน้มน้าวให้ Git ปฏิบัติต่อการเปลี่ยนแปลงของคุณในรูปแบบแพตช์ :

    git add -up .
    

    กดa+ enterเพื่อเลือกการเปลี่ยนแปลงทั้งหมดสำหรับแต่ละไฟล์ คุณจะได้รับคำเตือนเกี่ยวกับ Git แก้ไขข้อผิดพลาดของช่องว่าง
    ( git -c color.ui=auto diffณ จุดนี้แสดงให้เห็นว่าการเปลี่ยนแปลงที่ไม่ได้จัดทำดัชนีของคุณเป็นข้อผิดพลาดของช่องว่าง)

  3. ลบข้อผิดพลาดของช่องว่างออกจากสำเนาการทำงานของคุณ:

    git checkout .
    
  4. นำการเปลี่ยนแปลงกลับมา (ถ้าคุณยังไม่พร้อมที่จะยอมรับ):

    git reset
    

GIT_EDITOR=:วิธีการที่จะใช้:เป็นบรรณาธิการและเป็นคำสั่ง :เป็นตัวตน


1
ฉันเพิ่งทดสอบใน Windows: มันทำงานได้ดีในพรอมต์คำสั่ง DOS: set VISUAL= && git add -ue . && git checkout .หมายเหตุ ' .' ใช้กับgit add: นั่นเป็นเพราะ git1.8.3
VonC

@VonC จะไม่ยกเลิกการตั้งค่า VISUAL อย่างถาวรซึ่งอาจทำให้เกิดการใช้git commitงานตัวแก้ไขผิดพลาด ฉันหุ้มVISUAL=ส่วนใน subshell ในเวอร์ชัน unix ของฉันด้านบนเพื่อหลีกเลี่ยงปัญหานี้ แต่ฉันไม่รู้ว่า DOS มี subshells หรือไม่
ntc2

1
ขอบคุณสำหรับการแฮ็คที่ยอดเยี่ยม! หากคุณได้core.editorตั้งค่าไว้การส่งออกVISUALจะไม่มีผลกระทบใด ๆ เนื่องจากการตั้งค่า config จะมีความสำคัญman git-varมากกว่า หากต้องการลบล้างสิ่งนี้คุณต้องส่งออกGIT_EDITOR=:แทน
Nick Felt

1
นอกจากนี้ฉันปรับแต่งเวอร์ชันของฉันที่fixwsจะล้มเหลวอย่างรวดเร็วหากคุณอยู่ในการตอบโต้แบบโต้ตอบเพราะมิฉะนั้นมันจะตายที่git rebase --whitespace=fixบรรทัดและทำให้คุณอยู่ในสถานะที่แปลก ฉันยืมจากคำถามนี้และเพิ่งเพิ่มกรณีพิเศษก่อน: fixws = !"\ if test -d $(git rev-parse --git-dir)/rebase-merge ; then \ echo 'In rebase - cannot fixws' ; \ elif (! git diff-files --quiet .) && \ (! git diff-index --quiet --cached HEAD) ; then \ ...
Nick Felt

1
fyi: ฉันดัดแปลงสิ่งนี้ให้เป็นตะขอที่ผูกไว้ล่วงหน้า
Ian Kelling

29

ผมพบว่าคอมไพล์ก่อนกระทำเบ็ดที่เอาช่องว่างต่อท้าย

#!/bin/sh

if git-rev-parse --verify HEAD >/dev/null 2>&1 ; then
   against=HEAD
else
   # Initial commit: diff against an empty tree object
   against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi
# Find files with trailing whitespace
for FILE in `exec git diff-index --check --cached $against -- | sed '/^[+-]/d' | sed -r 's/:[0-9]+:.*//' | uniq` ; do
   # Fix them!
   sed -i 's/[[:space:]]*$//' "$FILE"
   git add "$FILE"
done
exit

3
การsedร้องขอที่สอง( sed -r 's/:[0-9]+:.*//') สามารถใช้แทนcut -f1 -d:ได้ สิ่งนี้จะทำงานได้เหมือนกันทั้งบนแพลตฟอร์ม Linux และ BSD
Ihor Kaharlichenko

2
@IhorKaharlichenko: จริง ๆ แล้วการใช้cutไม่ปลอดภัยเท่าที่สองsed: การตัดจะล้มเหลวในกรณีของชื่อไฟล์ที่มี ":" คุณสามารถใช้awk 'NF>2{NF-=2}1'เพื่อความปลอดภัย
MestreLion

1
BTW, หากคุณใช้ Windows (msysgit) และใช้งานcore.autocrlf=trueคุณอาจต้องการเพิ่มdos2unix -D "$FILE"เข้าไปในลูป for หลังจากลูป มิฉะนั้นจะเปลี่ยน CRLF ทั้งหมดเป็น LFs โดยการออกเฉพาะรายการ
jakub.g

49
ทำgit addในเบ็ดกระทำดูเหมือนว่าฉันชั่วร้าย เกิดอะไรขึ้นถ้าคุณกำลังทำขั้นตอนบางส่วน / กระทำไฟล์? คุณไม่ต้องการให้ไฟล์ทั้งหมดถูกคอมโพสต์ไว้ด้านหลังใช่ไหม?
Stefaan

19

บน Mac OS (หรือน่าจะเป็น BSD ใด ๆ ) พารามิเตอร์คำสั่ง sed จะต้องแตกต่างกันเล็กน้อย ลองสิ่งนี้:

#!/bin/sh

if git-rev-parse --verify HEAD >/dev/null 2>&1 ; then
   against=HEAD
else
   # Initial commit: diff against an empty tree object
   against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi

# Find files with trailing whitespace
for FILE in `exec git diff-index --check --cached $against -- | sed '/^[+-]/d' | sed -E 's/:[0-9]+:.*//' | uniq` ; do
    # Fix them!
    sed -i '' -E 's/[[:space:]]*$//' "$FILE"
    git add "$FILE"
done

บันทึกไฟล์นี้เป็น.git/hooks/pre-commit- หรือมองหาไฟล์ที่มีอยู่แล้วและวางชิ้นล่างที่อยู่ข้างใน และอย่าลืมchmod a+xมันด้วย

หรือสำหรับการใช้งานทั่วโลก (ผ่านGit commit hooks - การตั้งค่าทั่วโลก ) คุณสามารถใส่มันได้$GIT_PREFIX/git-core/templates/hooks(โดยที่ GIT_PREFIX คือ / usr หรือ / usr / local หรือ / usr / share หรือ / opt / local / share) และเรียกใช้git initภายใน repos ที่คุณมีอยู่

ตามgit help init:

การเรียกใช้ git init ในที่เก็บที่มีอยู่นั้นปลอดภัย มันจะไม่เขียนทับสิ่งที่มีอยู่แล้ว เหตุผลหลักสำหรับการเริ่มต้น git rerunning คือการรับแม่แบบที่เพิ่มเข้ามาใหม่


7
ไม่ใช่เบ็ดนี้แก้ไขไฟล์ทำงานและเขียนทับดัชนีด้วยไฟล์ทำงานแก้ไข? หากคุณต้อง 'git add -p' เพื่อสร้างดัชนีของคุณคอมมิทคอมเมิร์ซนี้ก็จะระเบิดออกไป
Matthew Dutton

2
ใช่คุณอาจจะพูดถูก บางคนอาจต้องเขียนสคริปต์นี้ใหม่เพื่อใช้ git hash-object -wและgit update-index(อีกครั้ง) แทรกไฟล์ munged ลงในดัชนีโดยตรง ใครบางคนที่กล้าหาญมาก
AlexChaffee

11

ฉันควรปล่อยให้ภารกิจนี้เป็นบรรณาธิการที่คุณชื่นชอบ

เพียงตั้งคำสั่งเพื่อลบช่องว่างต่อท้ายเมื่อบันทึก


2
ในกลุ่มคุณสามารถทำได้ด้วย: autocmd BufWritePre .cpp, .c, *. h:% / \ s \ + $ // e
Robert Massaioli

3
ขออภัยฉันอัปเดตความคิดเห็นข้างต้นก่อนทดสอบ มีเครื่องหมาย "s" ที่ขาดหายไปหลังจากเครื่องหมายเปอร์เซ็นต์และจะเลื่อนเคอร์เซอร์ไปรอบ ๆ หากพบช่องว่างและจะลบรูปแบบการค้นหาล่าสุด ดูvim.wikia.com/wiki/Remove_unwanted_spacesสำหรับทางเลือกที่ดีกว่า
เซทจอห์นสัน

1
ใน emacs Mx คือการลบต่อท้าย - ช่องว่าง
Mauvis Ledford

2
ยังดีกว่าสำหรับ emacs ให้ตั้งค่า hook เพื่อลบช่องว่างต่อท้ายก่อนบันทึกโดยเพิ่ม(add-hook 'before-save-hook 'delete-trailing-whitespace)ลงใน.emacsไฟล์ของคุณ เทคนิคช่องว่างของ Emacs
ดันแคนปาร์กส์

1
ฉันใช้ (เพิ่มเบ็ด 'ก่อนบันทึกเบ็ด' ล้างช่องว่าง) ซึ่งยังแปลงแท็บไปยังช่องว่าง
Nils Fagerburg

10

การใช้คุณลักษณะ git และตั้งค่าตัวกรองด้วยการกำหนดค่า git

ตกลงนี่เป็นวิธีการใหม่ในการแก้ปัญหานี้ ... แนวทางของฉันคือไม่ใช้ hooks แต่ใช้ตัวกรองและ git สิ่งนี้ช่วยให้คุณทำคือตั้งค่าในแต่ละเครื่องที่คุณพัฒนาบนชุดของตัวกรองที่จะตัดพื้นที่สีขาวต่อท้ายพิเศษและบรรทัดว่างพิเศษในตอนท้ายของไฟล์ก่อนที่จะยอมรับพวกเขา จากนั้นตั้งค่าไฟล์. gitattributes ที่ระบุว่าควรใช้ตัวกรองประเภทใด ตัวกรองมีสองขั้นตอนcleanซึ่งจะถูกนำไปใช้เมื่อเพิ่มไฟล์ลงในดัชนีและsmudgeจะถูกนำไปใช้เมื่อเพิ่มลงในไดเรกทอรีการทำงาน

บอกคอมไพล์ของคุณเพื่อค้นหาไฟล์คุณสมบัติโกลบอล

ก่อนอื่นให้กำหนดค่าส่วนกลางของคุณเพื่อใช้ไฟล์แอตทริบิวต์ของโลก:

git config --global core.attributesfile ~/.gitattributes_global

สร้างฟิลเตอร์ระดับโลก

ตอนนี้สร้างตัวกรอง:

git config --global filter.fix-eol-eof.clean fixup-eol-eof %f
git config --global filter.fix-eol-eof.smudge cat
git config --global filter.fix-eol-eof.required true

เพิ่มความมหัศจรรย์ของสคริปต์สคริปต์

ในที่สุดให้วางfixup-eol-eofสคริปต์ไว้ที่ใดที่หนึ่งบนเส้นทางของคุณและทำให้สามารถเรียกใช้งานได้ สคริปต์ใช้ sed เพื่อแก้ไขบางอย่างในการแก้ไขทันที (ลบช่องว่างและช่องว่างที่ท้ายบรรทัดและบรรทัดว่างภายนอกที่ส่วนท้ายของไฟล์)

fixup-eol-eof ควรมีลักษณะเช่นนี้:

#!/bin/bash
sed -e 's/[  ]*$//' -e :a -e '/^\n*$/{$d;N;ba' -e '}' $1

ส่วนสำคัญของฉันนี้

บอก git ว่าไฟล์ประเภทใดที่จะใช้ตัวกรองที่สร้างขึ้นใหม่

สุดท้ายสร้างหรือเปิด ~ / .gitattributes_global ในเครื่องมือแก้ไขที่คุณชื่นชอบและเพิ่มบรรทัดเช่น:

pattern attr1 [attr2 [attr3 […]]]

ดังนั้นหากเราต้องการแก้ไขปัญหาช่องว่างสำหรับไฟล์ต้นฉบับ c ทั้งหมดเราจะเพิ่มบรรทัดที่มีลักษณะดังนี้:

*.c filter=fix-eol-eof

เรื่องของตัวกรอง

ตัวกรองมีสองขั้นตอนคือขั้นตอนการทำความสะอาดซึ่งจะถูกนำไปใช้เมื่อมีการเพิ่มสิ่งต่าง ๆ ลงในดัชนีหรือเช็คอิน ที่นี่ smudge ของเรากำลังเรียกใช้เนื้อหาผ่านcatคำสั่งซึ่งควรปล่อยไว้โดยไม่มีการเปลี่ยนแปลงยกเว้นอาจเพิ่มอักขระขึ้นบรรทัดใหม่ต่อท้ายหากไม่มีหนึ่งที่ท้ายไฟล์ คำสั่ง clean คือการกรอง whitespace ซึ่งฉัน cobbled ร่วมกันจากบันทึกย่อที่http://sed.sourceforge.net/sed1line.txt http://sed.sourceforge.net/sed1line.txtดูเหมือนว่ามันจะต้องใส่เข้าไปในเชลล์สคริปต์ฉันไม่สามารถหาวิธีการฉีดคำสั่ง sed รวมถึงการสุขาภิบาลของบรรทัดพิเศษภายนอกที่ส่วนท้ายของไฟล์ลงในไฟล์ git-config โดยตรง (คุณทำได้กำจัดช่องว่างต่อท้ายอย่างไรก็ตามโดยไม่จำเป็นต้องใช้สคริปต์ sed แยกต่างหากเพียงตั้งค่าfilter.fix-eol-eofบางอย่างเช่นsed 's/[ \t]*$//' %fที่\tเป็นแท็บจริงโดยกดแท็บ)

การ = = จริงทำให้เกิดข้อผิดพลาดที่จะยกขึ้นหากมีสิ่งผิดปกติท

โปรดยกโทษให้ฉันหากภาษาของฉันเกี่ยวกับคอมไพล์ไม่แม่นยำ ฉันคิดว่าฉันเข้าใจแนวคิดค่อนข้างดี แต่ฉันยังคงเรียนรู้คำศัพท์


แนวทางที่น่าสนใจ +1
VonC

ขอบคุณ @VonC! ฉันยังต้องการใช้โอกาสนี้เพื่อชี้ให้เห็นว่าคุณลักษณะ git สามารถกำหนดค่าได้ในแต่ละตำแหน่งใน.gitโฟลเดอร์มากกว่าทั่วโลกซึ่งอาจเหมาะสมกว่า
zbeekman

9

ฉันเขียนฮุกที่คอมมิตก่อนหน้านี้ซึ่งจะลบเฉพาะ white-space ออกจากบรรทัดที่คุณเปลี่ยน / เพิ่มเนื่องจากคำแนะนำก่อนหน้านี้มักจะสร้างคอมมิทที่ไม่สามารถอ่านได้หากไฟล์เป้าหมายมี white-trailing space มากเกินไป

#!/bin/sh

if git rev-parse --verify HEAD >/dev/null 2>&1 ; then
   against=HEAD
else
   # Initial commit: diff against an empty tree object
   against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi

IFS='
'

files=$(git diff-index --check --cached $against -- | sed '/^[+-]/d' | perl -pe 's/:[0-9]+:.*//' | uniq)
for file in $files ; do
    diff=$(git diff --cached $file)
    if test "$(git config diff.noprefix)" = "true"; then
        prefix=0
    else
        prefix=1
    fi
    echo "$diff" | patch -R -p$prefix
    diff=$(echo "$diff" | perl -pe 's/[ \t]+$// if m{^\+}')
    out=$(echo "$diff" | patch -p$prefix -f -s -t -o -)
    if [ $? -eq 0 ]; then
        echo "$diff" | patch -p$prefix -f -t -s
    fi
    git add $file
done

1
น่าสนใจ +1 ดูคำตอบอื่น ๆ ของฉันสำหรับคำนวณต้นไม้ว่าง
VonC

1
ความคิดที่ดีนี่คือสิ่งที่ฉันต้องการ อย่างไรก็ตามโปรดระวังเมื่อใช้สิ่งนี้! สำหรับฉันใน OSX และ git เวอร์ชัน 2.3.5 มันทำให้การเปลี่ยนแปลงที่เพิ่ม แต่ไม่มีข้อผูกมัดใด ๆ ที่ฉันได้จัดเตรียมไว้ ฉันจะยังคงสนใจวิธีแก้ปัญหาการทำงานสำหรับเรื่องนี้แม้ว่า
Casper

9

โปรดลองใช้ตะขอที่ติดไว้ล่วงหน้าของฉันซึ่งสามารถตรวจจับช่องว่างท้ายและลบออกได้โดยอัตโนมัติ ขอบคุณ!

มันสามารถทำงานได้ภายใต้GitBash(windows), Mac OS X and Linux!


ภาพรวม:

$ git commit -am "test"
auto remove trailing whitespace in foobar/main.m!
auto remove trailing whitespace in foobar/AppDelegate.m!
[master 80c11fe] test
1 file changed, 2 insertions(+), 2 deletions(-)

1
น่าสนใจ +1 ฉันได้อ้างอิงตะขอของคุณในคำตอบของฉันเอง
VonC

@VonC ขอบคุณสำหรับการยืนยันของคุณ! สำหรับ '.md' ฉันพบเพียงgit commit -no-verifyความรู้สึกใด ๆ
แก่

ผมค่อนข้างจะให้เบ็ดสามารถตรวจจับ.mdไฟล์และไม่ลบช่องว่างมากกว่าขอให้ผู้ใช้เพื่อเพิ่มตัวเลือกใน--no-verify git commit
VonC

ล้มเหลวหากส่งไฟล์ / ไดเร็กทอรีที่ขึ้นต้นด้วย+หรือ-
Rody Oldenhuis

6

นี่เป็นเวอร์ชั่นที่รองรับ ubuntu + mac os x:

#!/bin/sh
#

# A git hook script to find and fix trailing whitespace
# in your commits. Bypass it with the --no-verify option
# to git-commit
#

if git-rev-parse --verify HEAD >/dev/null 2>&1 ; then
  against=HEAD
else
  # Initial commit: diff against an empty tree object
  against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi
# Find files with trailing whitespace
for FILE in `exec git diff-index --check --cached $against -- | sed '/^[+-]/d' | (sed -r 's/:[0-9]+:.*//' > /dev/null 2>&1 || sed -E 's/:[0-9]+:.*//') | uniq` ; do
  # Fix them!
  (sed -i 's/[[:space:]]*$//' "$FILE" > /dev/null 2>&1 || sed -i '' -E 's/[[:space:]]*$//' "$FILE")
  git add "$FILE"
done

# Now we can commit
exit

มีความสุข


ดูเหมือนความแตกต่างเพียงอย่างเดียวระหว่างคุณกับของฉันก็คือคุณตรวจสอบว่า sed จะแทนที่บางสิ่งบางอย่างก่อนที่จะเขียนไฟล์ใหม่ ... ฉันไม่แน่ใจว่าสำคัญเนื่องจาก git ไม่ยอมรับการเปลี่ยนแปลงที่ไม่เปลี่ยนแปลงอะไรเลย ฉันคิดว่ามันปลอดภัยกว่าเล็กน้อย แต่ก็ช้ากว่าเล็กน้อยและฉันชอบความชัดเจนที่จะไม่ทำซ้ำ regexes สองครั้งในหนึ่งบรรทัด โดยเฉพาะอย่างยิ่งไม่มีข้อโต้แย้ง!
AlexChaffee

ไม่มีความแตกต่างคือรุ่นใช้ไวยากรณ์ ubuntu ก่อนและ (หากล้มเหลว) หลังจากนั้นหนึ่ง osx
sdepold

1
ฉันแก้ไขโพสต์ของ sdepold มันควรจะสามารถอนุญาตช่องว่างในชื่อไฟล์ได้ในขณะนี้
imme

5

กำลังคิดเกี่ยวกับสิ่งนี้ในวันนี้ นี่คือทั้งหมดที่ฉันลงเอยด้วยการทำโครงการ java:

egrep -rl ' $' --include *.java *  | xargs sed -i 's/\s\+$//g'

3

สำหรับผู้ใช้Sublime Text

ตั้งค่าอย่างถูกต้องในการตั้งค่าผู้ใช้ของคุณ

"trim_trailing_white_space_on_save": true


1
เป็นวิธีตั้งค่าตามประเภทไฟล์หรือไม่? ฉันมี*.mdไฟล์ (markdown) ที่ใช้ "" (ช่องว่างต่อท้ายคู่) เพื่อทำเครื่องหมายอย่างง่าย<br />และดูเหมือนว่าการตั้งค่านั้นจะใช้กับไฟล์ทั้งหมดรวมถึงไฟล์ที่ฉันไม่ต้องการลบช่องว่างต่อท้าย
VonC

@VonC มีลำดับชั้นเกี่ยวกับวิธีการกำหนดค่าถูกนำไปใช้ดูรายละเอียดเพิ่มเติมที่นี่stackoverflow.com/questions/16983328/...หวังว่าจะช่วย
Haris จินา

2

for-loop สำหรับไฟล์ใช้ตัวแปรเชลล์ $ IFS ในสคริปต์ที่กำหนดชื่อไฟล์ที่มีตัวอักษรในนั้นที่อยู่ในตัวแปร $ IFS จะถูกมองว่าเป็นไฟล์สองไฟล์ที่แตกต่างกันใน for-loop สคริปต์นี้แก้ไขได้: ตัวดัดแปลงโหมดหลายบรรทัดตามที่ได้รับคู่มือการใช้งานดูเหมือนจะไม่ทำงานตามค่าเริ่มต้นในกล่องอูบุนตูของฉันดังนั้นฉันจึงค้นหาวิธีที่แตกต่างและพบสิ่งนี้ด้วยป้ายกำกับซ้ำแล้ว บรรทัดสุดท้ายของไฟล์ถ้าฉันเข้าใจถูกต้อง

#!/bin/sh
#

# A git hook script to find and fix trailing whitespace
# in your commits. Bypass it with the --no-verify option
# to git-commit
#

if git rev-parse --verify HEAD >/dev/null 2>&1
then
    against=HEAD
else
    # Initial commit: diff against an empty tree object
    against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi

SAVEIFS="$IFS"
# only use new-line character as seperator, introduces EOL-bug?
IFS='
'
# Find files with trailing whitespace
for FILE in $(
    git diff-index --check --cached $against -- \
    | sed '/^[+-]/d' \
    | ( sed -r 's/:[0-9]+:.*//' || sed -E 's/:[0-9]+:.*//' ) \
    | uniq \
)
do
# replace whitespace-characters with nothing
# if first execution of sed-command fails, try second one( MacOSx-version)
    (
        sed -i ':a;N;$!ba;s/\n\+$//' "$FILE" > /dev/null 2>&1 \
        || \
        sed -i '' -E ':a;N;$!ba;s/\n\+$//' "$FILE" \
    ) \
    && \
# (re-)add files that have been altered to git commit-tree
#   when change was a [:space:]-character @EOL|EOF git-history becomes weird...
    git add "$FILE"
done
# restore $IFS
IFS="$SAVEIFS"

# exit script with the exit-code of git's check for whitespace-characters
exec git diff-index --check --cached $against --

[1] รูปแบบ sed-subsition: ฉันจะเปลี่ยนบรรทัดใหม่ (\ n) โดยใช้ sed ได้อย่างไร .


2

สิ่งนี้จะไม่ลบช่องว่างออกโดยอัตโนมัติก่อนที่จะส่งมอบ แต่มันก็ง่ายที่จะทำให้เกิดผล ฉันใส่สคริปต์ perl ต่อไปนี้ในไฟล์ชื่อ git-wsf (แก้ไขช่องว่าง git) ใน dir ใน $ PATH ดังนั้นฉันสามารถ:

git wsf | ดวลจุดโทษ

และก็เอาช่องว่างทั้งหมดเท่านั้นจากสายของไฟล์ที่รายงานคอมไพล์เป็น diff

#! /bin/sh
git diff --check | perl -x $0
exit

#! /usr/bin/perl

use strict;

my %stuff;
while (<>) {
    if (/trailing whitespace./) {
        my ($file,$line) = split(/:/);
        push @{$stuff{$file}},$line;
    }
}

while (my ($file, $line) = each %stuff) {
    printf "ex %s <<EOT\n", $file;
    for (@$line) {
        printf '%ds/ *$//'."\n", $_;
    }
    print "wq\nEOT\n";
}

0

สายเล็กน้อย แต่เนื่องจากสิ่งนี้อาจช่วยให้ใครบางคนออกไปที่นี่ไป

เปิดไฟล์ใน VIM หากต้องการแทนที่แท็บด้วย whitespaces ให้พิมพ์ดังต่อไปนี้ในบรรทัดคำสั่ง vim

:%s#\t#    #gc

เพื่อกำจัดช่องว่างต่อท้ายอื่น ๆ

:%s#\s##gc

มันสวยมากสำหรับฉัน มันน่าเบื่อถ้าคุณมีไฟล์มากมายให้แก้ไข แต่ฉันพบว่าง่ายกว่าการผูกฮุกไว้ล่วงหน้าและทำงานกับผู้แก้ไขหลายคน


ถ้ามันน่าเบื่อ - และถ้าคุณมีข้อมูลสำรองของสิ่งที่คุณกำลังจะแก้ไข - ฉันมักจะใช้ sed เพื่อเปลี่ยนแท็บเป็นช่องว่าง: sed -i 's|\t| |g' filenames(ช่องว่างในตำแหน่งแทนที่) โปรดทราบว่าคุณสามารถใช้ค้นหาเพื่อรับชื่อไฟล์ของคุณ หากคุณไม่ได้คิดว่าจะได้รับการสำรองข้อมูลนั้นได้อย่างไรฉันมักจะมอบทุกอย่างแล้ว 'ยกเลิก' การกระทำด้วยการรีเซ็ตแบบเบา ๆ กลับไปที่ที่ฉันอยู่ บางครั้งฉันเพิ่มทุกอย่างลงในทรี แต่ไม่ยอมรับและบางครั้งฉันก็ใช้ stash / Apply (ไม่ใช่ป๊อป!) ถ้าผมรู้สึกกังวลผม rsync ต้นไม้ทั้งหมดของฉันไปยังสถานที่ที่ปลอดภัยก่อนที่จะเข้าไปยุ่ง ...
ปัญญาชน

0

หากต้องการลบช่องว่างต่อท้ายที่ท้ายบรรทัดในไฟล์แบบพกพาให้ใช้ed:

test -s file &&
   printf '%s\n' H ',g/[[:space:]]*$/s///' 'wq' | ed -s file

-1

สิ่งนี้อาจไม่ได้แก้ปัญหาของคุณโดยตรง แต่คุณอาจต้องการตั้งค่าเหล่านั้นผ่าน git-config ในพื้นที่โครงการจริงของคุณซึ่งการแก้ไข. /.git/config ซึ่งตรงข้ามกับ ~ / .gitconfig ยินดีที่จะให้การตั้งค่าสอดคล้องกันในหมู่สมาชิกโครงการทั้งหมด

git config core.whitespace "trailing-space,space-before-tab"
git config apply.whitespace "trailing-space,space-before-tab"

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