ทำไมไม่คอมไพล์บรรทัดที่อยู่ติดกันโดยไม่มีความขัดแย้ง


25

ฉันเพิ่งเรียนรู้ว่าเมื่อรวมสองสาขาในคอมไพล์ถ้ามีการเปลี่ยนแปลงในสองบรรทัดที่อยู่ติดกันคอมไพล์ประกาศความขัดแย้งนี้ ตัวอย่างเช่นหากไฟล์test.txtมีเนื้อหานี้:

Line 1: A
Line 2: B
Line 3: C
Line 4: D

และในสาขาmasterเราเปลี่ยนสิ่งนี้เป็น

Line 1: A
Line 2: B1
Line 3: C
Line 4: D

ในขณะที่สาขาtestingเราเปลี่ยนสิ่งนี้เป็น

Line 1: A
Line 2: B
Line 3: C1
Line 4: D

และจากนั้นพยายามที่จะรวมtestingเข้าไปในmasterคอมไพล์ประกาศความขัดแย้งผสาน ความคาดหวังที่ไร้เดียงสาของฉันคือการรวมจะเกิดขึ้นโดยไม่มีความขัดแย้งและให้สิ่งนี้:

Line 1: A
Line 2: B1
Line 3: C1
Line 4: D

ฉันแน่ใจว่ามีเหตุผลที่ดีว่าทำไมคอมไพล์ไม่รวมวิธีนี้ มีคนอธิบายเหตุผลนี้ได้ไหม


เฮ้ฉันเพิ่งสังเกตุเมื่อสัปดาห์ที่แล้วเช่นกัน บางทีเรากำลังทำแบบฝึกหัดเดียวกันอยู่
detly

5
ความสามารถในการรวมของ git นั้นค่อนข้างแย่ IMO
James

คุณได้ลอง @James โดยใช้อัลกอริทึมความอดทนแล้วหรือยัง ฉันพบว่าฉันได้ผลลัพธ์ที่ดีขึ้นโดยเฉพาะอย่างยิ่งเมื่อต้องรับมือกับการที่นักล่าถูกแยกออก (เช่นการจับร่างกายหนึ่งหน้าที่แทนที่จะเป็นสอง) หากคุณไม่ชอบ git คุณสามารถใช้ของคุณเองได้ (ดูที่blog.wuwon.id.au/2010/09/ …เป็นต้น)
ขัดขวาง

1
สาเหตุที่แท้จริงคือคอมไพล์พยายามทำการผสานตัวเองแทนที่จะแยกตัวประกอบออกเป็นเครื่องมือพิเศษ ทั้งหมดไม่ใช่ปรัชญาของ Unix สำหรับไฟล์ต้นฉบับคุณสามารถใช้ไวยากรณ์ภาษาเพื่อกำหนด diffs ได้อย่างน่าเชื่อถือ
MSalters

บริบททั่วไปคือ A และ D ดังนั้นทำไม A / C1 / B1 / D จึงไม่ถูกต้อง?
Izkata

คำตอบ:


13

สมมติว่าข้อมูลโค้ดนี้

x=0
x+=1 if foo
x+=1 if bar
return x

มีการเปลี่ยนแปลงในสาขาเดียวในนี้

x=0
x+=1 if foo && xyzzy
x+=1 if bar
return x

และในสาขาอื่นเข้าไปในนี้

x=0
x+=1 if foo
x+=1 if bar && xyzzy
return x

จากนั้นฉันจะไม่ต้องการให้คอมไพล์รวมเข้ากับสิ่งนี้

x=0
x+=1 if foo && xyzzy
x+=1 if bar && xyzzy
return x

โดยไม่ต้องตกใจฉัน

เพื่อหลีกเลี่ยงการก่อให้เกิดปัญหาดังกล่าว git มักจะปฏิเสธที่จะรวมการเปลี่ยนแปลงที่สัมผัสเส้นใกล้เคียงโดยอัตโนมัติ มันให้โอกาสคุณในการตรวจสอบว่าตรรกะของโปรแกรมจะเสียหายหรือไม่

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


5
ที่ไม่มีอะไรเกี่ยวข้องกับมันเพียงแค่เพิ่มเส้นไม่เปลี่ยนแปลงระหว่างสองคนนั้นและคอมไพล์ก็รวมพวกเขาโดยไม่มีปัญหา
Darkhogg

ใช่ฉันไม่ได้รับคำตอบนี้ คุณสามารถใช้ตรรกะเดียวกันเพื่อหลีกเลี่ยงการรวมอัตโนมัติทั้งหมด
Mehrdad

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

11

เป็นพฤติกรรมแบบคอมไพล์เท่านั้นหรือไม่

หลังจากสนทนากับเพื่อนร่วมงานฉันเพิ่งลองและSVN จัดการกับมันโดยไม่มีปัญหา: คุณได้รับการแก้ไข 2 บรรทัด

ความสามารถในการผสานของ VCS หลายตัวได้รับการทดสอบที่นี่เพื่อตลาดบาซ่าร์ดาร์คคอมไพล์และปรอท : https://github.com/mndrix/merge-this

ดูเหมือนว่ามีเพียง Darcs ที่ประสบความสำเร็จในการผสานกรณี "เส้นที่อยู่ติดกัน"

การใช้การเปลี่ยนแปลงที่อยู่ติดกันกับไฟล์ไม่ใช่ปัญหาที่ยาก ฉันคิดว่าพฤติกรรมนี้ได้รับการเลือกอย่างตั้งใจ

เหตุใดบางคนตัดสินใจว่าการแก้ไขบรรทัดที่อยู่ติดกันก่อให้เกิดความขัดแย้ง

ฉันจะคิดว่านี่คือการบังคับให้คุณมองไปที่มัน

int max = MAX_ITEMS;
for(unsigned int i = 0; i < max; i++)
    do_stuff(i);

Modif number 1, กับ master:

int max = MAX_ITEMS/2; // Do stuff only on the first half
for(unsigned int i = 0; i < max; i++)
    do_stuff(i);

Modif หมายเลข 2 ผสานจากสาขา:

int max = MAX_ITEMS;
for(unsigned int i = 0; i < max/2; i++) // max/2: only on 1st half
    do_stuff(i);

หลังจากผสานคุณไม่ต้องการ:

int max = MAX_ITEMS/2; // Do stuff only on the first half
for(unsigned int i = 0; i < max/2; i++) // max/2: only on 1st half
    do_stuff(i);

เห็นพฤติกรรมนี้เป็นคุณสมบัติ

คุณสามารถเปลี่ยนพฤติกรรมการรวมคอมไพล์เป็นข้อได้เปรียบ เมื่อคุณต้องการให้มี 2 บรรทัดที่สอดคล้องกัน แต่คุณไม่สามารถตรวจพบได้ (ในเวลารวบรวมการทดสอบ แต่อย่างใด) คุณสามารถลองเข้าร่วมได้

เขียนสิ่งนี้ ... :

for(unsigned int i = 0; i < max; i++)
    r = do_stuff(i);
    // Need to do something else
    do_something_else(r);

...สำหรับสิ่งนี้:

for(unsigned int i = 0; i < max; i++)
    r = do_stuff(i);
    do_something_else(r); // Need to do something else

ดังนั้นเมื่อคุณรวม Modif 1 ... :

for(unsigned int i = 0; i < max; i++)
    r = do_stuff(i)/2; // we need only the half
    do_something_else(r); // Need to do something else

... ด้วย Modif 2 ... :

for(unsigned int i = 0; i < max; i++)
    r = do_stuff(i);
    if(r < 0) // do_stuff can return an error
        handle_error(r);
    do_something_else(r/2); // Need to do something else

... , คอมไพล์จะสร้างความขัดแย้งและคุณจะบังคับให้คุณดูมัน


2
ฉันแค่จะไปข้างหน้าและบอกว่าฉันคิดว่าคำตอบของคุณมีความเหมาะสมอย่างสมบูรณ์ แต่ขึ้นอยู่กับความซับซ้อนการใช้งานร่วมกันกำหนดไว้ระหว่างรหัสของคุณและการควบคุมแหล่งที่มาของคุณสำหรับการตรวจสอบสติเป็นไปอย่างรวดเร็ว thedailywtf.com การผสานรหัสโดยไม่มีตัวแยกวิเคราะห์ภาษาเป็นความพยายามที่ดีที่สุดอยู่เสมอและฉันมีบางกรณีที่คอมไพล์ช่วยบางสิ่งบางอย่างโดยอัตโนมัติอย่างที่มันไม่ควรมีและผลิตรหัสที่ไม่ได้รวบรวม
2560

5

ฉันคาดเดาส่วนใหญ่ แต่ฉันคิดว่ามันเกี่ยวข้องกับการใช้บรรทัด 2 เป็นบริบทสำหรับการเปลี่ยนแปลงบรรทัดที่ 3

Git ไม่สามารถพูดได้ว่า "บรรทัดที่มี C กลายเป็นเส้นตรงกับ C1" เพราะอาจมีอีกบรรทัดที่มี "C" ดังนั้นมันจึงบอกว่า "บรรทัดที่มี C นั้นถูกต้องหลังจากเริ่มต้นไฟล์แล้วบรรทัดที่มี A และเส้นกับ B คือตอนนี้ C1 "

หาก "บรรทัดที่มี B" ไม่มีอยู่อีกต่อไปบริบทบางอย่างจะหายไปและคอมไพล์สามารถบอกได้อย่างคร่าวๆว่าบรรทัดใหม่ต้องไปที่ใด


5
ยังมีโอกาสมากที่ C ขึ้นอยู่กับ B ดังนั้นผสานไร้เดียงสาอาจจะลำบากแม้ว่าคอมไพล์ "รู้วิธีการ" ที่จะทำมัน
Lucina

เชื่อฉัน Git เท่านั้น "คิดว่ามันรู้" Git เป็นสุสานแห่งความคิดผิด ๆ พยายามยืดตัวออกไป!
user3833732

2

คำตอบอื่น ๆ ที่นี่เป็นจุด แต่สำหรับฉันนี้มักจะดูเหมือนข้อ จำกัด ที่ไม่จำเป็น

อย่างที่คนอื่น ๆ พูดไว้ในกรณีนี้คุณไม่ต้องการให้ Git รวมเส้นโดยไม่มีการเตือนล่วงหน้า

แต่ฉันยังต้องการตัวเลือกให้ทำโดยอัตโนมัติหลังจากถูกเตือน ดังนั้นฉันจึงเขียนไดร์เวอร์ git merge แบบกำหนดเองที่สามารถผสานความขัดแย้งบนบรรทัด (หรือบุคคล) ที่อยู่ติดกันแบบโต้ตอบ:

ป้อนคำอธิบายรูปภาพที่นี่

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

สคริปต์นี้มีอยู่ใน GitHub ภายใต้ลิขสิทธิ์ GPLv3 + บางทีคุณอาจพบว่ามีประโยชน์:

https://github.com/paulaltin/git-subline-merge


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

ฉันยังไม่ได้ลองเลย แต่ฉันมาหาวิธีทำให้เป็นอัตโนมัติและดีใจที่พบมันที่นี่ ขอบคุณ :) คุณยอดเยี่ยม
Mehrdad

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