เพิ่มการเปลี่ยนแปลงที่ไม่ใช่ช่องว่างเท่านั้น


343

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

ทุกครั้งที่ฉันพยายามส่งแพตช์ฉันต้องเพิกเฉยต่อการเปลี่ยนแปลงทั้งหมดของช่องว่างด้วยตนเองก่อนเพื่อเลือกเฉพาะข้อมูลที่เกี่ยวข้อง ไม่เพียงแค่นั้น แต่เมื่อฉันวิ่งgit rebaseฉันมักจะพบปัญหาหลายอย่างเพราะพวกเขา

เช่นนี้ฉันต้องการเพิ่มดัชนีเฉพาะการเปลี่ยนแปลงที่ไม่ใช่ช่องว่างในลักษณะที่คล้ายกันgit add -pแต่ไม่ต้องเลือกการเปลี่ยนแปลงทั้งหมดด้วยตนเอง

ไม่มีใครรู้วิธีการทำเช่นนี้?

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

คำตอบ:


395

@ วิธีแก้ปัญหาไม่ได้เป็นสิ่งที่ฉันต้องการดังนั้นนี่คือนามแฝงที่ฉันสร้างขึ้นสำหรับปัญหาเดียวกัน:

alias.addnw=!sh -c 'git diff -U0 -w --no-color "$@" | git apply --cached --ignore-whitespace --unidiff-zero -'

หรือคุณสามารถเรียกใช้:

git diff -U0 -w --no-color | git apply --cached --ignore-whitespace --unidiff-zero -

ปรับปรุง

เพิ่มตัวเลือก-U0และ--unidiff-zeroตามลำดับเพื่อแก้ไขปัญหาการจับคู่บริบทตามความคิดเห็นนี้

โดยทั่วไปจะใช้แพทช์ซึ่งจะนำไปใช้addโดยไม่มีการเปลี่ยนแปลงช่องว่าง คุณจะสังเกตเห็นว่าหลังจากที่git addnw your/fileยังคงมีการเปลี่ยนแปลงแบบไม่ต่อเนื่องก็จะมีช่องว่างเหลืออยู่

- ไม่ต้องใช้สี แต่เนื่องจากฉันได้ตั้งค่าสีไว้เสมอฉันจึงต้องใช้มัน อย่างไรก็ตามปลอดภัยกว่าดีกว่าขออภัย


7
สิ่งนี้ใช้ได้ดีสำหรับฉัน แต่ฉันต้องใช้git apply --ignore-whitespaceมิฉะนั้นโปรแกรมแก้ไขจะไม่ใช้ด้วยเหตุผลที่ชัดเจน
jupp0r

106
ควรมีตัวเลือกในการเพิ่มคอมไพล์เช่นgit add -wนี้
Jarl

7
มันทำให้ฉันมีปัญหากับpatch does not applyและerror while searching for... ความคิดใด?
DTI-Matt

18
ไม่ได้ผลสำหรับฉัน มีpatch does not applyข้อผิดพลาด
Jerry Saravia

13
หากคุณได้รับ 'แพทช์ล้มเหลว' เนื่องจากช่องว่างในบริบทเป็น @bronson ชี้ให้เห็นงานนี้คำสั่งแก้ไข git diff -U0 -w --no-color | git apply --cached --ignore-whitespace --unidiff-zero(มันสร้างแพทช์กับบริบทไม่มี): สิ่งนี้ไม่ได้มีความเสี่ยงเพราะดัชนีมีความทันสมัยอยู่แล้วดังนั้นจึงเป็นฐานที่เชื่อถือได้สำหรับแพทช์
void.pointer

36

สิ่งนี้ใช้ได้กับฉัน:

หากคุณต้องการเก็บไว้รอบ ๆ งานนี้

git stash && git stash apply && git diff -w > foo.patch && git checkout . && git apply foo.patch && rm foo.patch

ฉันไม่ชอบการหยุดทำงาน แต่ฉันพบข้อผิดพลาดใน git + cygwin ที่ฉันสูญเสียการเปลี่ยนแปลงดังนั้นเพื่อให้แน่ใจว่าสิ่งที่ไป reflog อย่างน้อยฉันได้ตั้งค่าต่อไปนี้:

git add . && git commit -am 'tmp' && git reset HEAD^ && git diff -w > foo.patch && git checkout . && git apply foo.patch && rm foo.patch

โดยทั่วไปเราสร้างส่วนต่างที่ไม่รวมการเปลี่ยนแปลงพื้นที่คืนการเปลี่ยนแปลงทั้งหมดของเราแล้วนำส่วนต่างนั้นไปใช้


1
+1 คุณอาจต้องการgit stashทำการชำระเงินแทนเพื่อสำรองข้อมูลการเปลี่ยนแปลงของคุณอย่างน้อยก็จนกว่าจะมีการทดสอบ
Paŭlo Ebermann

1
คุณจะต้องเจอกับปัญหามากมายและโดยทั่วไปคุณไม่จำเป็นต้องทำทั้งหมดนี้ มันใช้งานได้ แต่ฉันคิดว่ามันยุ่งเล็กน้อย
Colin Hebert

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

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

1
ฉันคิดว่าท้ายคำสั่งแรก "git rm foo.patch" ควรเป็น "rm foo.patch" ขอบคุณอย่างอื่นที่เป็นประโยชน์มาก
Jack Casey

33

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

git diff> backup
git diff -w> การเปลี่ยนแปลงการ
รีเซ็ต git - ฮาร์ด
แพทช์ <การเปลี่ยนแปลง

ตรวจสอบความแตกต่างที่เหลืออยู่จากนั้นaddและcommitตามปกติ

Mercurial ที่เทียบเท่ากันคือทำสิ่งนี้:

hg diff> backup
hg diff -w> การเปลี่ยนแปลง
เปลี่ยนกลับ
hg - นำเข้า hg ทั้งหมด - ไม่มีการเปลี่ยนแปลงที่กระทำ


คำถามที่“ ได้รับการป้องกัน” คืออะไร? และฉันก็ตอบ ฉันไม่คิดว่ามีคุณสมบัตินี้แม้ในขณะที่ฉันตอบเกินไปเพราะมันจะปรากฏคำถามที่ถูกดึงออกจากอากาศบาง ...
jww

4
@jww คำถามหลักของผู้โพสต์ดั้งเดิมคือ "วิธีหลีกเลี่ยงการให้พื้นที่สีขาวเปลี่ยนไปเป็นการควบคุมแหล่งที่มา" OP เกิดขึ้นที่จะใช้ Git แต่ก็ใช้ได้กับทุกระบบควบคุมแหล่งที่มาที่ฉันเคยใช้ คำตอบนี้แสดงขั้นตอนที่ถูกต้องหากมีคนใช้ Mercurial ฉันนึกภาพคนอื่นอาจช่วยแก้ปัญหาสำหรับคนที่ใช้ Sublesion เป็นต้น
Steve Pitchers

1
@jww และ @ pagid: ฉันแก้ไขคำตอบของฉันเพื่อระบุ Git โดยเฉพาะโดยใช้วิธีการเดียวกับวิธีแก้ปัญหาสำหรับ Mercurial ในมุมมองของฉัน StackOverflow เป็นมากกว่าฟอรัม Q + A อื่น - นอกจากนี้ยังมีบทบาทเป็นที่เก็บความรู้ คนอื่นที่ไม่ใช่โปสเตอร์ดั้งเดิมอาจได้รับประโยชน์จากคำตอบที่ได้รับและสถานการณ์ของพวกเขาจะแตกต่างกันไป นั่นเป็นเหตุผลที่ฉันเชื่อว่าคำตอบที่สื่อถึงหลักการทั่วไปนั้นใช้ได้มากกว่าการกำหนดเป้าหมายเพียงสถานการณ์เดียวเท่านั้น
Steve Pitchers

@Steve - "ฉันแก้ไขคำตอบของฉันเพื่อระบุ Git ... " - ทำไมคุณไม่ถามคำถามใหม่ในบริบทของ Mercurial แล้วเพิ่มคำตอบของคุณเองในคำถามใหม่ ???
jww

8
อันที่จริงแล้วนี่เป็นวิธีที่สะอาดที่สุดเข้าใจได้และไม่แตกหักง่ายที่สุดที่ฉันเคยเห็น
Kzqai

12

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

ฉันแก้ไขคำสั่งดังนี้

$ git diff -U0 -w --no-color | git apply --cached --ignore-whitespace --unidiff-zero

สิ่งนี้สร้างแพตช์โดยไม่มีบริบท ไม่ควรเป็นปัญหาเนื่องจากแผ่นแปะมีอายุสั้น

นามแฝงที่เกี่ยวข้องกับการแก้ไขสิ่งที่ผู้ใช้รายอื่นให้ไว้แล้ว:

addw = !sh -c 'git diff -U0 -w --no-color "$@" | git apply --cached --ignore-whitespace --unidiff-zero' -

เพียงไม่สนใจเยื้องเปลี่ยนแปลงผมใช้แทน--ignore-space-change -wgit diff -U0 --ignore-space-change --no-color | git apply --cached --unidiff-zero
Andy

คำเตือนที่จะไม่ใช้เล่ห์เหลี่ยมบริบทนี้กับ--ignore-blank-linesคนอื่นคุณจะพบชิ้นส่วนที่แตกต่างถูกแพทช์ที่offsets ไม่ถูกต้องหากการเปลี่ยนแปลง 'พื้นที่สีขาว' บางอย่างที่คุณต้องการละเว้นเป็นการลบ / เพิ่มเติมบรรทัดว่างเปล่า
elbeardmorez

12

เพิ่มสิ่งต่อไปนี้ในของคุณ.gitconfig:

anw = !git diff -U0 -w --no-color -- \"$@\" | git apply --cached --ignore-whitespace --unidiff-zero "#"

ขอบคุณ@Colin Herbertสำหรับคำตอบของแรงบันดาลใจ

คำอธิบายไวยากรณ์

สุดท้าย#จะต้องยกมาดังนั้นจึงไม่ถือว่ามันเป็นความคิดเห็นภายใน.gitconfigแต่แทนที่จะได้รับการส่งผ่านและจะถือว่าเป็นความคิดเห็นภายในเปลือก - มันจะถูกแทรกระหว่างปลายgit applyและอาร์กิวเมนต์ที่ผู้ใช้กำหนดgitโดยอัตโนมัติที่ สิ้นสุดบรรทัดคำสั่ง อาร์กิวเมนต์เหล่านี้ไม่ต้องการที่นี่ - เราไม่ต้องการที่git applyจะบริโภคพวกเขาดังนั้นตัวละครความคิดเห็นก่อนหน้านี้ คุณอาจต้องการเรียกใช้คำสั่งนี้GIT_TRACE=1 git anwเพื่อดูการดำเนินการนี้

--สัญญาณสิ้นสุดของการขัดแย้งและช่วยให้การกรณีที่คุณมีไฟล์ชื่อหรือสิ่งที่จะมีลักษณะเหมือนสวิทช์ไป-wgit diff

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

หมายเหตุ: .gitconfigนามแฝงแยกไม่รู้จักคำพูดเดียวเป็นอะไรเป็นพิเศษ - ตัวอักษรพิเศษเท่านั้นที่มี", \, \nและ;(ด้านนอกของ"สตริง -quoted) นี่คือเหตุผลที่"จะต้องมีการหลบหนีอยู่เสมอแม้ว่ามันจะดูเหมือนว่ามันอยู่ในสตริงที่ยกมาเดี่ยว (ซึ่งคอมไพล์ไม่เชื่อเรื่องพระเจ้าอย่างสมบูรณ์)

นี่เป็นสิ่งสำคัญเช่น หากคุณมีนามแฝงที่มีประโยชน์ในการรันbashคำสั่งในรูทของต้นไม้ทำงาน สูตรที่ไม่ถูกต้องคือ:

sh = !bash -c '"$@"' -

ในขณะที่หนึ่งที่ถูกต้องคือ:

sh = !bash -c '\"$@\"' -

ยอดเยี่ยม ทำให้ฉันสามารถเพิ่มไฟล์ได้ครั้งละหนึ่งไฟล์ นอกเหนือจากการเพิ่มไดเรกทอรีรากสำหรับการโต้แย้งมีวิธีทำให้งานนี้เช่น 'git add -A' หรือไม่
Chucky

7

วิธีการเกี่ยวกับต่อไปนี้:

git add `git diff -w --ignore-submodules |grep "^[+][+][+]" |cut -c7-`

คำสั่งภายใน backquotes ได้รับชื่อของไฟล์ที่มีการเปลี่ยนแปลงที่ไม่ใช่ช่องว่าง


2
หรือเพียงแค่git add `git diff -w |grep '^+++' |cut -c7-`ถ้าไม่ได้ใช้ submodules
karmakaze

-1

คุณควรพิจารณาว่าช่องว่างต่อท้ายนั้นมีเจตนาหรือไม่ หลายโครงการรวมถึงเคอร์เนล Linux, Mozilla, Drupal และ Kerberos (เพื่อชื่อไม่กี่จากหน้า Wikipedia ในสไตล์) ห้ามมิให้ช่องว่างต่อท้าย จากเอกสารเคอร์เนล Linux:

รับโปรแกรมแก้ไขที่ดีและไม่ต้องเว้นช่องว่างท้ายบรรทัด

ในกรณีของคุณปัญหาคืออีกด้านหนึ่ง: หน้าที่ก่อนหน้า (และอาจเป็นปัญหาปัจจุบัน) ไม่ได้ทำตามคำแนะนำนี้

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

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


16
มันไม่ได้ตั้งใจ แต่ฉันไม่สามารถเปลี่ยนวิธีคิด 100 คนที่มีส่วนร่วมในโครงการคิด พวกเขาไม่สนใจและไม่ยอมรับการแก้ไขที่มีการเปลี่ยนแปลงมากกว่า 1,000 รายการที่เกี่ยวข้องกับช่องว่างต่อท้าย พวกเขารู้เกี่ยวกับปัญหาและตัดสินใจเพิกเฉย การสนทนานี้เกิดขึ้นแล้วในรายการและถูกปิด ในกรณีนี้มันเป็นฉันที่ต้องการปรับให้เข้ากับพวกเขา
Edu Felipe

19
จากนั้นกำหนดค่าตัวแก้ไขของคุณโดยที่ไม่ตัดช่องว่างต่อท้ายเมื่อทำงานกับรหัสของโครงการนี้
jamessan

-2

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

  #!/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"
  done
  exit

4
คำถามนี้ถามว่าจะรักษาช่องว่างต่อท้ายได้อย่างไร
Douglas

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