ฉันจะบอก git ให้เลือกเวอร์ชันภายในเครื่องของฉันเสมอสำหรับการผสานที่ขัดแย้งในไฟล์ใดไฟล์หนึ่งได้อย่างไร


101

สมมติว่าฉันกำลังทำงานร่วมกับใครบางคนผ่านที่เก็บ git และมีไฟล์เฉพาะที่ฉันไม่ต้องการยอมรับการเปลี่ยนแปลงใด ๆ จากภายนอก

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


1
เพิ่งเพิ่มวิธีง่ายๆผ่าน. gitattributes และ "ผสานไดรเวอร์" ขั้นพื้นฐาน
VonC

12
TD; LR:echo 'path/to/file merge=ours' >> .gitattributes && git config --global merge.ours.driver true
Ciro Santilli 郝海东冠状病六四事件法轮功

@CiroSantilli: ใช้งานได้อย่างมีเสน่ห์บน Linux ไดรเวอร์นี้ง่ายพอที่จะสร้างไว้ใน Git ...
krlmlr

คุณต้องการพุชการเปลี่ยนแปลงไปยังไฟล์หรือไม่ หรือเป็นตัวอย่างไฟล์ config ที่เก็บค่าดีฟอลต์ไว้ใน git
Ian Ringrose

ความคิดเห็นของ @CiroSantilli 新疆改造中心六四法轮功法轮功ถูกต้อง แต่จะทำให้พฤติกรรมนี้เกิดขึ้นสำหรับทุก repo บนระบบของคุณด้วย--globalแท็ก หากคุณต้องการเพียงพฤติกรรมนี้สำหรับ repo เดียวให้ทิ้ง--globalธงไว้:echo 'path/to/file merge=ours' >> .gitattributes && git config merge.ours.driver true
majorobot

คำตอบ:


140

ในอินสแตนซ์เฉพาะของไฟล์ config ฉันเห็นด้วยกับคำตอบของ Ron :
การกำหนดค่าควรเป็น "ส่วนตัว" สำหรับพื้นที่ทำงานของคุณ (ดังนั้นจึง "ละเว้น" เช่นเดียวกับใน "ประกาศใน.gitignoreไฟล์")
คุณอาจจะมีไฟล์ config แม่แบบที่มีค่า tokenizedในนั้นและสคริปต์เปลี่ยนที่config.templateไฟล์เป็นส่วนตัว (และละเว้น) ไฟล์ config


อย่างไรก็ตามคำพูดนั้นไม่ได้ตอบคำถามทั่วไปที่กว้างขึ้นนั่นคือคำถามของคุณ (!):

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

การผสานประเภทนี้คือ "การคัดลอกการผสาน" ซึ่งคุณจะคัดลอกไฟล์เวอร์ชัน "ของเรา" หรือ "ของพวกเขา" ทุกครั้งที่มีข้อขัดแย้ง

(ขณะที่ไบรอัน Vandenbergบันทึกในความคิดเห็น , ' ours' และ ' theirs' อยู่ที่นี่ใช้สำหรับการผสาน .
พวกเขาจะกลับรายการสำหรับrebase : ดู " Why is the meaning of “ours” and “theirs” reversed with git-svn" ซึ่งใช้ rebase ว่า " git rebaseการติดตาม 'ท้องถิ่น' และ 'ระยะไกล " )

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

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

IE. ตามที่ระบุไว้โดยCiro Santilli :

echo 'path/to/file merge=ours' >> .gitattributes
git config --global merge.ours.driver true

มาทดสอบกันในสถานการณ์ง่ายๆด้วย msysgit 1.6.3 บน Windows ในเซสชัน DOS เท่านั้น:

cd f:\prog\git\test
mkdir copyMerge\dirWithConflicts
mkdir copyMerge\dirWithCopyMerge
cd copyMerge
git init
Initialized empty Git repository in F:/prog/git/test/copyMerge/.git/

ตอนนี้เรามาสร้างไฟล์สองไฟล์ซึ่งทั้งสองจะมีความขัดแย้งกัน แต่จะรวมต่างกัน

echo a > dirWithConflicts\a.txt
echo b > dirWithCopyMerge\b.txt
git add -A
git commit -m "first commit with 2 directories and 2 files"
[master (root-commit) 0adaf8e] first commit with 2 directories and 2 files

เราจะแนะนำ "ความขัดแย้ง" ในเนื้อหาของทั้งสองไฟล์ในสองสาขา git ที่แตกต่างกัน:

git checkout -b myBranch
Switched to a new branch 'myBranch'
echo myLineForA >> dirWithConflicts\a.txt
echo myLineForB >> dirWithCopyMerge\b.txt
git add -A
git commit -m "add modification in myBranch"
[myBranch 97eac61] add modification in myBranch

git checkout master
Switched to branch 'master'
git checkout -b hisBranch
Switched to a new branch 'hisBranch'
echo hisLineForA >> dirWithConflicts\a.txt
echo hisLineForB >> dirWithCopyMerge\b.txt
git add -A
git commit -m "add modification in hisBranch"
[hisBranch 658c31c] add modification in hisBranch

ตอนนี้เรามาลองรวม "hisBranch" กับ "myBranch" ด้วย:

  • การแก้ปัญหาด้วยตนเองสำหรับการผสานที่ขัดแย้งกัน
  • ยกเว้นสำหรับdirWithCopyMerge\b.txtที่ฉันมักจะต้องการที่จะให้ฉันb.txtรุ่นของ

เนื่องจากการผสานเกิดขึ้นใน ' MyBranch' เราจะเปลี่ยนกลับไปใช้และเพิ่มgitattributesคำสั่ง '' ซึ่งจะปรับแต่งพฤติกรรมการผสาน

git checkout myBranch
Switched to branch 'myBranch'
echo b.txt merge=keepMine > dirWithCopyMerge\.gitattributes
git config merge.keepMine.name "always keep mine during merge"
git config merge.keepMine.driver "keepMine.sh %O %A %B"
git add -A
git commit -m "prepare myBranch with .gitattributes merge strategy"
[myBranch ec202aa] prepare myBranch with .gitattributes merge strategy

เรามี.gitattributesไฟล์ที่กำหนดไว้ในdirWithCopyMergeไดเร็กทอรี (กำหนดเฉพาะในสาขาที่การผสานจะเกิดขึ้น :) myBranchและเรามี.git\configไฟล์ที่ตอนนี้มีไดรเวอร์การผสาน

[merge "keepMine"]
        name = always keep mine during merge
        driver = keepMine.sh %O %A %B

หากคุณยังไม่ได้กำหนด keepMine.sh และเปิดการผสานต่อไปนี่คือสิ่งที่คุณจะได้รับ

git merge hisBranch
sh: keepMine.sh: command not found
fatal: Failed to execute internal merge
git st
# On branch myBranch
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   dirWithConflicts/a.txt
#
no changes added to commit (use "git add" and/or "git commit -a")

type dirWithConflicts\a.txt
a
<<<<<<< HEAD:dirWithConflicts/a.txt
myLineForA
=======
hisLineForA
>>>>>>> hisBranch:dirWithConflicts/a.txt

ไม่เป็นไร:

  • a.txt พร้อมที่จะรวมเข้าด้วยกันและมีความขัดแย้ง
  • b.txtยังคงไม่ถูกแตะต้องเนื่องจากไดรเวอร์การผสานควรจะดูแลมัน (เนื่องจากคำสั่งใน.gitattributesไฟล์ในไดเร็กทอรี)

กำหนดkeepMine.shที่ใดก็ได้ในคุณ%PATH%(หรือ$PATHสำหรับเพื่อน Unix ของเราฉันทำทั้งสองอย่างแน่นอน: ฉันมีเซสชัน Ubuntu ในเซสชัน VirtualBox)

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

git config merge.keepMine.driver true

แต่ในกรณีทั่วไปคุณสามารถกำหนดไฟล์สคริปต์:

keepMine.sh

# I want to keep MY version when there is a conflict
# Nothing to do: %A (the second parameter) already contains my version
# Just indicate the merge has been successfully "resolved" with the exit status
exit 0

(ซึ่งเป็นคนขับผสานหนึ่งง่าย;) (ถึงแม้จะง่ายในการที่กรณีการใช้งานtrue)
(ถ้าคุณไม่อยากให้รุ่นอื่น ๆ เพียงแค่เพิ่มก่อนexit 0บรรทัด:
cp -f $3 $2.
นั่นแหล่ะคุณผสานโปรแกรมควบคุมสิ่งที่จะเก็บรุ่นมาจากที่อื่น ๆ . สาขาแทนที่การเปลี่ยนแปลงในท้องถิ่น)

ตอนนี้เรามาลองผสานกันใหม่ตั้งแต่ต้น:

git reset --hard
HEAD is now at ec202aa prepare myBranch with .gitattributes merge strategy

git merge hisBranch
Auto-merging dirWithConflicts/a.txt
CONFLICT (content): Merge conflict in dirWithConflicts/a.txt
Auto-merging dirWithCopyMerge/b.txt
Automatic merge failed; fix conflicts and then commit the result.

การผสานล้มเหลว ... สำหรับ a.txtเท่านั้น
แก้ไข a.txt และออกจากบรรทัด 'hisBranch' จากนั้น:

git add -A
git commit -m "resolve a.txt by accepting hisBranch version"
[myBranch 77bc81f] resolve a.txt by accepting hisBranch version

ตรวจสอบว่า b.txt ได้รับการเก็บรักษาไว้ในระหว่างการผสานนี้

type dirWithCopyMerge\b.txt
b
myLineForB

สุดท้ายไม่กระทำการเป็นตัวแทนของเต็มผสาน:

git show -v 77bc81f5e
commit 77bc81f5ed585f90fc1ca5e2e1ddef24a6913a1d
Merge: ec202aa 658c31c
git merge hisBranch
Already up-to-date.

(บรรทัดที่ขึ้นต้นด้วยการผสานพิสูจน์ได้ว่า)


พิจารณาว่าคุณสามารถกำหนดรวมและ / หรือเขียนทับโปรแกรมควบคุมการผสานตามที่ Git จะ:

  • ตรวจสอบ<dir>/.gitattributes(ซึ่งอยู่ในไดเร็กทอรีเดียวกันกับพา ธ ที่เป็นปัญหา): จะมีผลเหนือกว่า.gitattributesในไดเร็กทอรีอื่น ๆ
  • จากนั้นจะตรวจสอบ.gitattributes(ซึ่งอยู่ในไดเร็กทอรีหลัก) จะกำหนดคำสั่งเท่านั้นหากยังไม่ได้ตั้งค่า
  • $GIT_DIR/info/attributesในที่สุดมันก็จะตรวจสอบ ไฟล์นี้ใช้เพื่อลบล้างการตั้งค่าในแผนผัง มันจะเขียนทับ<dir>/.gitattributesคำสั่ง

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


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

6
ควรอาจจะยกมาคือcp -f $3 $2 cp -f "$3" "$2"
Arc

1
@VonC ขอบคุณสำหรับคำตอบโดยละเอียด! ปัญหาที่ฉันพบคือมันขึ้นอยู่กับคนที่ตั้งค่าไดรเวอร์ในไฟล์. git / config ฉันต้องการเพิ่มข้อมูลไดรเวอร์ลงในโปรเจ็กต์เองดังนั้นมันจะเป็นไปโดยอัตโนมัติและต้องทำการตั้งค่าน้อยลง คำแนะนำใด ๆ
Juan Delgado

2
@ulmangt: คุณสามารถจัดเก็บสคริปต์นั้นไว้ใน git repo ได้เป็นอย่างดีเช่นกัน ... ตราบใดที่คุณหาวิธีเพิ่มไดเร็กทอรีหลักไปยังPATH(Unix หรือ Windows PATH) เนื่องจากสคริปต์นั้นจะถูกตีความผ่าน Unix bash shell หรือผ่าน MingWin bash MsysGit Windows shell จึงเป็นแบบพกพา
VonC

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

1

ตามที่ @ ciro-santilli แสดงความคิดเห็นวิธีง่ายๆในการใช้งาน.gitattributesกับการตั้งค่า:

path/to/file merge=ours

และเปิดใช้งานกลยุทธ์นี้ด้วย:

git config --global merge.ours.driver true

(ฉันกำลังเพิ่มสิ่งนี้เป็นคำตอบเพื่อให้มองเห็นได้ชัดเจนขึ้น แต่ทำให้เป็น Community Wiki เพื่อไม่พยายามให้เครดิตของผู้ใช้สูงกว่าตัวเองโปรดโหวตความคิดเห็นของเขาใต้ Q ที่นี่เพื่อให้เขาชื่นชอบ!)


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

0

เรามีไฟล์กำหนดค่าหลายไฟล์ที่เราไม่ต้องการเขียนทับ อย่างไรก็ตาม. gitignore และ. gitattributes ไม่ได้ผลในสถานการณ์ของเรา วิธีแก้ปัญหาของเราคือการจัดเก็บไฟล์กำหนดค่าในสาขาการกำหนดค่า จากนั้นอนุญาตให้เปลี่ยนไฟล์ระหว่างการผสานคอมไพล์ แต่ในทันทีหลังจากการผสานให้ใช้ "git checkout branch -" เพื่อคัดลอกไฟล์กำหนดค่าของเราจากสาขาการกำหนดค่าหลังจากการรวมทุกครั้ง คำตอบ stackoverflow โดยละเอียดที่นี่

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