เป็นไปได้หรือไม่ที่ git-merge จะเพิกเฉยต่อความแตกต่างของการสิ้นสุดบรรทัด


150

เป็นไปได้หรือgit mergeไม่ที่จะละเว้นความแตกต่างของการสิ้นสุดบรรทัด

บางทีฉันอาจจะถามคำถามผิด ... แต่:

ฉันพยายาม uisng config.crlf inputแต่สิ่งที่มียุ่งบิตและออกจากการควบคุมเป็นพิเศษเมื่อฉันใช้มันตามความเป็นจริง

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

พูดตามตรงฉันไม่สนใจจริงๆว่าจะใช้การเขียนแบบบรรทัดหรือไม่ฉันชอบสไตล์ของ Unix \nแต่ไม่ว่าอะไรก็ตาม สิ่งที่ฉันสนใจคือเพื่อgit mergeให้มีความฉลาดขึ้นและเพิกเฉยต่อความแตกต่างในการวางสาย

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

ปรับปรุง:

ฉันพบว่าgit diffยอมรับ--ignore-space-at-eolตัวเลือกเป็นไปได้ไหมที่จะอนุญาตให้git mergeใช้ตัวเลือกนี้ด้วย?


28
โอ้ฉันหวังว่า สิ่งที่ลงท้ายด้วย git นี้เสียอย่างสิ้นเชิง
1800 ข้อมูล

เพียงแค่เพิ่มกรณีทดสอบแสดงผู้ผสานเครื่องมือของบุคคลที่สามจะไม่สนใจสไตล์ EOL ระหว่างการผสาน
VonC

ดังนั้นเพื่อชี้แจง (จากสิ่งที่ฉันสามารถระบุได้): ไม่มีวิธีที่จะทำให้ git เพิกเฉยต่อ CR แต่บ่นเกี่ยวกับช่องว่างอื่น ๆ
Stephen

อย่าลืมดูคำตอบด้านล่างเกี่ยวกับgit config merge.renormalize true
qneill

คำตอบ:


115

อัปเดต 2013:

เวอร์ชัน git ล่าสุดที่อนุญาตให้ใช้ผสานกับตัวเลือกrecursiveกลยุทธ์และกลยุทธ์( ):-X

git merge -s recursive -Xignore-space-at-eol

แต่การใช้ " -Xignore-space-change" ก็เป็นไปได้เช่นกัน


jakub.gยังแสดงความคิดเห็นว่ากลยุทธ์นี้ใช้ได้กับการหยิบเชอร์รี่ด้วย :

git cherry-pick abcd123456 --strategy=recursive --strategy-option=renormalize 

ignore-all-spaceนี้ทำงานได้ดีกว่า


คำตอบเดิม (พฤษภาคม 2009)

แพทช์สำหรับการละเว้นสไตล์ EOL ได้รับการเสนอในมิถุนายน 2007แต่เพียงความกังวลไม่ได้git diff --ignore-space-at-eolgit merge

ในเวลานั้นคำถามได้ถูกถามแล้ว:

ควร--ignore-space-at-eolเป็นตัวเลือกในการgit-merge?
การผสานเป็นหน้าที่การทำงานนี้มีความสำคัญ
ความหมายของการผสานการแก้ไขอัตโนมัติที่มีตัวเลือกเหล่านี้มีผลบังคับใช้ - พวกเขาใช้สำหรับการตรวจจับการเปลี่ยนชื่อเท่านั้นหรือเราเช่นไม่ตั้งค่าสถานะความขัดแย้งกับการเปลี่ยนแปลงช่องว่างเท่านั้น? และถ้าเราไม่ทำเราจะยอมรับเวอร์ชันใดโดยอัตโนมัติ

Julio C Hamano ไม่กระตือรือร้นอย่างแน่นอน:

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

แนวคิดทั่วไปเมื่อพูดถึงgit mergeคือการพึ่งพาเครื่องมือผสานของบุคคลที่สาม

ตัวอย่างเช่นฉันมีการติดตั้งDiffMergeเป็นเครื่องมือสำหรับการรวม Git การตั้งค่าrulesetซึ่งอนุญาตให้เครื่องมือผสานนั้นไม่สนใจ eol สำหรับไฟล์บางประเภท


ตั้งค่าบน Windows ด้วย MSysGit1.6.3 ไม่ว่าจะเป็นสำหรับเซสชัน DOS หรือ Git โดยใช้ DiffMerge หรือ KDiff3:

  • ตั้งค่าไดเรกทอรีเข้ามาในเส้นทางของคุณ (ที่นี่: c:\HOMEWARE\cmd)
  • เพิ่มในไดเรกทอรีนั้นสคริปต์ merge.sh (wrapper สำหรับเครื่องมือผสานที่คุณชื่นชอบ)

merge.sh:

#!/bin/sh

# Passing the following parameters to mergetool:
#  local base remote merge_result

alocal=$1
base=$2
remote=$3
result=$4

if [ -f $base ]
then
    #"C:/Program Files/SourceGear/DiffMerge/DiffMerge.exe" "$alocal" "$base" "$remote" -m --result="$result" --title1="Mine" --title2="Merging to: $result" --title3="Theirs"

    # for merge respecting eol, KDiff3 is better than DiffMerge (which will always convert LF into CRLF)
    # KDiff3 will display eol choices (if Windows: CRLF, if Unix LF)
    "C:/Program Files/KDiff3/kdiff3.exe" -m "$base" "$alocal" "$remote" -o "$result"
else
    #there is not always a common ancestor: DiffMerge needing 3 files, BASE will be the result
    #"C:/Program Files/SourceGear/DiffMerge/DiffMerge.exe" "$alocal" "$result" "$remote" -m --result="$result" --title1="Mine" --title2="Merging to: $result" --title3="Theirs"

    # KDiff3 however does know how to merge based on 2 files (not just 3)
    "C:/Program Files/KDiff3/kdiff3.exe" -m "$base" "$remote" -o "$result"
fi
  • ประกาศ wrapper ผสานของคุณสำหรับ Git

คำสั่ง Git config:

git config --global merge.tool diffmerge
git config --global mergetool.diffmerge.cmd "merge.sh \"$PWD/$LOCAL\" \"$PWD/$BASE\" \"$PWD/$REMOTE\" \"$PWD/$MERGED\"
git config --global mergetool.diffmerge.trustExitCode false
git config --global mergetool.diffmerge.keepBackup false
  • ตรวจสอบว่า autoCRLF เป็นเท็จ

git config ที่ระดับระบบ:

git config ---system core.autoCRLF=false
  • ทดสอบว่าเมื่อสองบรรทัดเหมือนกัน (แต่เป็น eol chars) ทั้ง DiffMerge หรือ KDiff3 จะละเว้นบรรทัดนั้นในระหว่างการผสาน

สคริปต์ DOS (หมายเหตุ: คำสั่ง dos2unix มาจากที่นี่และใช้เพื่อจำลอง Unix eol-style คำสั่งนั้นถูกคัดลอกในไดเรกทอรีที่กล่าวถึงในตอนต้นของคำตอบนี้):

C:\HOMEWARE\git\test>mkdir test_merge C:\HOMEWARE\git\test>cd test_merge C:\HOMEWARE\git\test\test_merge>git init C:\HOMEWARE\git\test\test_merge>echo a1 > a.txt & echo a2 >> a.txt C:\HOMEWARE\git\test\test_merge>git add a.txt C:\HOMEWARE\git\test\test_merge>git commit -m "a.txt, windows eol style" C:\HOMEWARE\git\test\test_merge>git checkout -b windows Switched to a new branch 'windows' C:\HOMEWARE\git\test\test_merge>echo a3 >> a.txt & echo a4 >> a.txt C:\HOMEWARE\git\test\test_merge>git add a.txt C:\HOMEWARE\git\test\test_merge>git commit -m "add two lines, windows eol style" C:\HOMEWARE\git\test\test_merge>git checkout master C:\HOMEWARE\git\test\test_merge>git checkout -b unix Switched to a new branch 'unix' C:\HOMEWARE\git\test\test_merge>echo au3 >> a.txt & echo au4 >> a.txt && echo au5 >> a.txt C:\HOMEWARE\git\test\test_merge>dos2unix a.txt Dos2Unix: Processing file a.txt ... C:\HOMEWARE\git\test\test_merge>git add a.txt C:\HOMEWARE\git\test\test_merge>git commit -m "add 3 lines, all file unix eol style" [unix c433a63] add 3 lines, all file unix eol style C:\HOMEWARE\git\test\test_merge>git merge windows Auto-merging a.txt CONFLICT (content): Merge conflict in a.txt Automatic merge failed; fix conflicts and then commit the result. C:\HOMEWARE\git\test\test_merge>git ls-files -u 100644 39b4c894078a02afb9b1dfeda6f1127c138e38df 1 a.txt 100644 28b3d018872c08b0696764118b76dd3d0b448fca 2 a.txt 100644 3994da66530b4df80189bb198dcfac9b8f2a7b33 3 a.txt C:\HOMEWARE\git\test\test_merge>git mergetool Merging the files: a.txt Normal merge conflict for 'a.txt': {local}: modified {remote}: modified Hit return to start merge resolution tool (diffmerge):

ณ จุดนี้ (กดปุ่ม "return"), DiffMerge หรือ KDiff3 จะเปิดขึ้นและคุณจะเห็นด้วยตัวคุณเองว่าบรรทัดใดที่ถูกรวมกันจริง ๆ และบรรทัดใดที่ถูกละเว้น

คำเตือน : ไฟล์ผลลัพธ์จะอยู่ในโหมด Windows eol (CRLF) เสมอโดยมี DiffMerge ...
KDiff3 เสนอให้บันทึกในวิธีใดวิธีหนึ่ง


ขอบคุณสำหรับเคล็ดลับ! Meld และ FileMerge ใน Mac น่าจะเป็นแอพที่ยอดเยี่ยมเช่นกัน
LéoLéopold Hertz 준영

1
สำหรับข้อมูลกลยุทธ์ยังใช้ได้กับการเก็บเชอร์รี่ด้วย: git cherry-pick abcd123456 --strategy=recursive --strategy-option=renormalize (ใช้งานได้ดีกว่าignore-all-space)
jakub.g

1
@ jakub.g จุดดี! ฉันได้รวมไว้ในคำตอบเพื่อให้มองเห็นได้ชัดเจนขึ้น
VonC

98

ฉันกำลังมองหาคำตอบเดียวกันและฉันพบสิ่งนี้

ผสานสาขาที่มีแอตทริบิวต์การเช็คอิน / เช็คเอาต์ที่แตกต่างกัน

หากคุณได้เพิ่มแอททริบิวต์ลงในไฟล์ที่ทำให้รูปแบบที่เก็บข้อมูลของแคนนอนเปลี่ยนไปเช่นการเพิ่มฟิลเตอร์ clean / smudge หรือ text / eol / ident คุณสมบัติการรวมอะไรก็ตามที่ไม่ได้อยู่ในตำแหน่ง .

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

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

ดังนั้นการรันคำสั่งนี้ในที่เก็บใด ๆ จะทำเคล็ดลับ:

git config merge.renormalize true

20
ตอนนี้สมควรที่จะเป็นคำตอบเริ่มต้น มีการเปลี่ยนแปลงมากมายตั้งแต่คำถามถูกถามครั้งแรกการจัดการคอมไพล์ของนี้ถูกสร้างขึ้นด้วย merge.ren Normalize ตามที่คุณพูด
Anton I. Sipos

นี้จะน่ากลัวเพียง .. บันทึกวันของฉัน
Matthaeus



4

สิ่งที่ฉันทำคือปล่อยให้ทุกอย่างเป็นค่าเริ่มต้น (เช่น autocrlf = true) ให้แตะไฟล์ทั้งหมด (ค้นหา. -exec touch {} \;) ให้ git มองว่า 'แก้ไข' แล้วคอมมิทมันและทำมันใหม่ ไม่เช่นนั้นคุณจะถูกรบกวนด้วยข้อความที่น่ารำคาญหรือความแตกต่างที่น่าประหลาดใจหรือต้องปิดคุณสมบัติช่องว่างทั้งหมดของคอมไพล์

คุณจะสูญเสียข้อมูลการตำหนิ แต่มันจะดีกว่าถ้าทำเร็วกว่านี้ :)




1

http://stahlforce.com/dev/index.php?tool=remcrlf

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


0

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

ฉัน googled "แปลง crlf เป็น lf" และพบว่านี่เป็นผลลัพธ์แรก:
http://stahlforce.com/dev/index.php?tool=remcrlf

ฉันดาวน์โหลดและใช้งานดูเหมือนว่าเป็นเครื่องมือที่ดี

>sfk remcr . .py

ตรวจสอบให้แน่ใจว่าระบุไดเรกทอรีและประเภทไฟล์ (เช่น. py) มิฉะนั้นอาจพยายามยุ่งกับเนื้อหาของ.gitไดเรกทอรี!


0

AFAICT (ผมไม่ได้พยายามมัน) คุณสามารถใช้เพื่อเปรียบเทียบสาขาที่คุณต้องการผสานกับบรรพบุรุษร่วมกันแล้วใช้ผลกับgit diff git applyทั้งสองคำสั่งมี --ignore-whitespaceตัวเลือกในการละเว้นการสิ้นสุดบรรทัดและข้อผิดพลาดของ white space

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


-1

หลังจากอ่านการแก้ไขข้อขัดแย้งผสาน: บังคับให้เขียนทับไฟล์ทั้งหมด

ในที่สุดฉันก็แก้ไขปัญหานี้ในเวอร์ชันของฉัน ฉันพยายามดึงการอัปเดตจาก repo อัปสตรีม แต่รายการปัจจุบันของฉันมีปัญหาเกี่ยวกับ CRLF และไม่สามารถรวมเป็นผลได้ ควรสังเกตว่าฉันไม่มีการเปลี่ยนแปลงในท้องถิ่นที่ฉันต้องกังวล ขั้นตอนต่อไปนี้สามารถแก้ไขปัญหาของฉันได้:

ตามคำแนะนำของ Github เกี่ยวกับการซิงค์ส้อม ( https://help.github.com/articles/syncing-a-fork/ ):

  1. git fetch upstream

  2. git reset --hard upstream/master
    ความเข้าใจที่ จำกัด ของฉันเกี่ยวกับคอมไพล์บอกฉันว่านี่เป็นการทำในสิ่งที่ฉันต้องการ - รีบูตส้อมของฉัน (โดยไม่มีการเปลี่ยนแปลงจริง ๆ ที่ไม่มีข้อผูกมัด) เพื่อรับการเปลี่ยนแปลงทั้งหมดที่เกิดขึ้นกับแหล่งข้อมูลต้นน้ำ ตามหน้าแหล่งที่มาปกติแล้วขั้นตอนนี้ไม่ควรจำเป็น แต่ปัญหา CRLF ทำให้จำเป็น

  3. git merge upstream/master

  4. git push

1
คุณรู้หรือไม่ว่าการgit reset --hard upstream/masterขว้างสาขาในพื้นที่ของคุณออกไปแล้วชี้ไปที่upstream/masterทำgit merge upstream/masterไม่โอป?
Christoffer Hammarström

-1

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

วิธีที่ดีที่สุดคือ:

  1. คัดลอกไฟล์โครงการเท่านั้น (ละเว้น.gitไดเรกทอรี) ไปยังไดเรกทอรีอื่นสร้างพื้นที่เก็บข้อมูลในนั้นเพิ่มไฟล์และยอมรับพวกเขา (ควรจะอยู่ในสาขาหลักในพื้นที่เก็บข้อมูลใหม่)
  2. คัดลอกไฟล์จากโครงการที่สองไปยังโฟลเดอร์เดียวกัน แต่สาขาอื่นเช่นdev( git checkout -b dev), ยอมรับไฟล์ในสาขานี้และเรียกใช้ (หากโครงการแรกอยู่ในระดับปริญญาโท): git diff master..dev --names-only เพื่อดูชื่อของไฟล์ที่เปลี่ยนแปลงเท่านั้น
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.