मैं यह कैसे बताऊं कि किसी विशिष्ट फ़ाइल पर विवादित मर्ज के लिए हमेशा अपने स्थानीय संस्करण का चयन करें?


100

कहो कि मैं किसी के साथ एक git रिपॉजिटरी के माध्यम से सहयोग कर रहा हूं, और एक विशेष फ़ाइल है जिसे मैं किसी भी बाहरी परिवर्तन को स्वीकार नहीं करना चाहता।

क्या मेरे लिए कोई रास्ता नहीं है कि मैं अपने स्थानीय रेपो को स्थापित करने के लिए हर बार जब भी मैं पुल से टकराता हूं, तब किसी विवादित विलय के बारे में शिकायत न करें? इस फ़ाइल को मर्ज करते समय मैं हमेशा अपने स्थानीय संस्करण का चयन करना चाहूंगा।


1
बस .ITattributes और एक बहुत ही बुनियादी "मर्ज ड्राइवर" के माध्यम से एक सरल समाधान जोड़ा गया
VonC

12
टीडी; LR:echo 'path/to/file merge=ours' >> .gitattributes && git config --global merge.ours.driver true
सिरो सेंटिल्ली

@CiroSantilli: लिनक्स पर एक आकर्षण की तरह काम करता है। यह चालक Git में निर्मित होने के लिए काफी सरल है ...
krlmlr

क्या आप फ़ाइल में अपने परिवर्तनों को आगे बढ़ाना चाहते हैं? या यह उदाहरण के लिए एक कॉन्फ़िग फ़ाइल है जहाँ डिफ़ॉल्ट को git में संग्रहीत किया जाता है।
इयान रिंगरोस 11

@CiroSantilli 新疆 ill ill 事件 法轮功 correct की टिप्पणी सही है, लेकिन --globalटैग के साथ आपके सिस्टम पर प्रत्येक रेपो के लिए यह व्यवहार करेगा । यदि आप केवल एकल रेपो के लिए इस व्यवहार को चाहते हैं, तो --globalध्वज को छोड़ दें :echo 'path/to/file merge=ours' >> .gitattributes && git config merge.ours.driver true
majorobot

जवाबों:


140

एक कॉन्फ़िगर फ़ाइल के विशिष्ट उदाहरण पर, मैं रॉन के जवाब से सहमत होगा :
एक कॉन्फ़िगरेशन आपके कार्यक्षेत्र के लिए "निजी" होना चाहिए (इसलिए "अनदेखा", जैसा कि "एक .gitignoreफ़ाइल में घोषित किया गया है ")।
आपके पास इसमें टोकन मूल्यों के साथ एक कॉन्फिग फाइल टेम्प्लेट हो सकती है और एक स्क्रिप्ट उस फाइल को एक निजी (और उपेक्षित) कॉन्फिगर फाइल में बदल सकती है।config.template


हालाँकि, उस विशिष्ट टिप्पणी का उत्तर नहीं है कि व्यापक सामान्य प्रश्न क्या है, अर्थात आपका प्रश्न (!)

मैं यह कैसे बताऊं कि किसी विशिष्ट फ़ाइल पर विवादित मर्ज के लिए हमेशा अपने स्थानीय संस्करण का चयन करें? (किसी फ़ाइल या फ़ाइल के समूह के लिए)

इस तरह का मर्ज एक "कॉपी मर्ज" है, जिसमें आप हमेशा किसी फाइल के 'हमारा' या 'उनके' वर्जन को कॉपी करेंगे जब भी कोई टकराव होता है।

(के रूप में ब्रायन वन्देंबेर्ग नोटों टिप्पणी में , ' ours' और ' theirs' यहाँ किसी मर्ज के लिए उपयोग किया जाता है
वे कर रहे हैं उलट एक के लिए रिबेस : देखें " Why is the meaning of “ours” and “theirs” reversed with git-svn" है, जो एक रिबेस का उपयोग करता है, " git rebase, का ट्रैक रखने के 'स्थानीय' और 'दूरस्थ' " )

"एक फ़ाइल" के लिए (सामान्य रूप से एक फ़ाइल, "कॉन्फ़िग" फ़ाइल की बात नहीं कर रही है, क्योंकि यह एक बुरा उदाहरण है), आप इसे प्राप्त करेंगे जो मर्ज के माध्यम से बुलाए गए कस्टम स्क्रिप्ट के साथ होगा।
Git उस स्क्रिप्ट को कॉल करेगा क्योंकि आपने एक gitattributes मान निर्धारित किया होगा , जो एक कस्टम मर्ज ड्राइवर को परिभाषित करता है ।

"कस्टम मर्ज ड्राइवर" इस ​​मामले में, एक बहुत ही सरल स्क्रिप्ट है जो मूल रूप से वर्तमान संस्करण को अपरिवर्तित रखेगा, इसलिए आपको हमेशा अपने स्थानीय संस्करण का चयन करने की अनुमति देगा।

आईई।, जैसा कि सिरो सेंटिल्ली ने नोट किया है :

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

आइए परीक्षण करें कि एक साधारण परिदृश्य में, विंडोज पर एमएसआईजित 1.6.3 के साथ, केवल डॉस सत्र में:

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 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

अब, "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हमारे यूनिक्स दोस्त के लिए कहीं भी परिभाषित करें । मैं दोनों कोर्स करता हूं: मेरे पास वर्चुअलबॉक्स सत्र में एक उबंटू सत्र है)

जैसा कि lrkwz द्वारा टिप्पणी की गई है , और कस्टमाइज़िंग गिट - गिट एट्रिब्यूट्स के " मर्ज स्ट्रैटेजीज़ " खंड में वर्णित है , आप शेल स्क्रिप्ट को शेल कमांड से बदल सकते हैं ।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
यही है आप मिला चालक aways संस्करण दूसरे से आते रहते हैं। शाखा, किसी भी स्थानीय परिवर्तन को ओवरराइड करते हुए)

अब, शुरुआत से मर्ज को पुन: प्रयास करें:

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निर्देशों को अधिलेखित कर देगा ।

"संयोजन" से मेरा मतलब है कि "मर्ज" कई मर्ज ड्राइवर।
निक ग्रीन की कोशिश करता, टिप्पणी में , वास्तव में मर्ज ड्राइवरों गठबंधन करने के लिए: देखें " मर्ज पोम के माध्यम से अजगर Git ड्राइवर "।
हालांकि, जैसा कि उनके अन्य प्रश्न में उल्लेख किया गया है , यह केवल संघर्षों (दोनों शाखाओं में समवर्ती संशोधन) के मामले में काम करता है।


1
विस्तृत उत्तर के लिए धन्यवाद! मैं समझता हूं कि यह संस्करण-नियंत्रण कॉन्फ़िगरेशन फ़ाइलों के लिए कोई मतलब नहीं है, लेकिन मैं एक सीधे-सीधे प्रेरक उदाहरण के बाद था। वास्तव में, यह व्यापक सवाल है कि मुझे दिलचस्पी है। मैंने इससे पहले कभी भी git मर्ज ड्राइवरों के बारे में नहीं सुना था, इसलिए मेरा ज्ञानवर्धन करने के लिए धन्यवाद।
सैफड्स

6
cp -f $3 $2शायद उद्धृत किया जाना चाहिए, यानी cp -f "$3" "$2"
आर्क

1
@VonC विस्तृत जवाब के लिए धन्यवाद! मेरे पास जो समस्या है, वह यह है कि यह उन लोगों पर निर्भर करता है जो अपने .it / config फाइल में ड्राइवर सेट कर रहे हैं। मैं ड्राइवर की जानकारी प्रोजेक्ट में स्वयं जोड़ना चाहूंगा, इसलिए यह स्वचालित और कम सेटअप वाला काम होगा। कोई संकेत?
जुआन डेलगाडो

2
@ulmangt: आप उस स्क्रिप्ट को git रेपो में भी संग्रहीत कर सकते हैं, ... जब तक कि आप इसके मूल निर्देशिका PATH(Unix या Windows PATH) में जोड़ने का कोई तरीका ढूंढते हैं । चूँकि उस स्क्रिप्ट की व्याख्या यूनिक्स बैश शेल के माध्यम से की जाएगी, या मिंगविन बैश MsysGit विंडोज शेल के माध्यम से, यह पोर्टेबल होगी।
वॉनच

5
@VonC धन्यवाद। एक और मुद्दा। कुछ परिस्थितियों में (यदि स्थानीय शाखा में कोई बदलाव नहीं किया गया है) तो ऐसा प्रतीत होता है कि मर्ज ड्राइवर को कभी भी कॉल नहीं किया जाता है, जिसके परिणामस्वरूप स्थानीय फ़ाइलों को संशोधित किया जाता है (जो कस्टम मर्ज ड्राइवर का उपयोग करने वाले होते हैं मर्ज के दौरान उन्हें बदलने से रोकने के लिए)। क्या हमेशा मर्ज ड्राइवर का उपयोग करने के लिए गिट को मजबूर करने का कोई तरीका है ?
उलमांग

1

जैसा कि @ ciro-santilli ने टिप्पणी की है, इसे .gitattributesसेटिंग्स के साथ उपयोग करने का सरल तरीका :

path/to/file merge=ours

और इस रणनीति को सक्षम करें:

git config --global merge.ours.driver true

(मैं इसे और अधिक दृश्यमान बनाने के लिए एक उत्तर के रूप में जोड़ रहा हूं, लेकिन इसे एक सामुदायिक विकी बना रहा हूं ताकि अपने लिए उपयोगकर्ता के क्रेडिट से ऊपर जाने की कोशिश न की जा सके। कृपया उसे क्यू के तहत देने के लिए यहां क्यू के तहत उसकी टिप्पणी को बढ़ाएं!)


(एक तरफ: यदि कोई व्यक्ति एक टिप्पणी के रूप में जवाब देता है और एक उत्तर नहीं जोड़ता है, तो गैर-सीडब्ल्यू उत्तर लिखना और क्रेडिट प्राप्त करना पूरी तरह से ठीक है। यदि वे अभी भी एक सक्रिय सदस्य हैं, तो आप एक उत्तर जोड़ने के लिए उन्हें पिंग कर सकते हैं। आप चाहें, लेकिन उनके पास तकनीकी रूप से पहले से ही मौका था :-))।
२१:

0

हमारे पास कई कॉन्फ़िगर फाइलें हैं जिन्हें हम कभी नहीं लिखना चाहते हैं। हालाँकि .itignignore और .gitattributes ने हमारी स्थिति में काम नहीं किया। हमारा समाधान कॉन्फिग ब्रांच में कॉन्फिग फाइल को स्टोर करना था। फिर, गिट मर्ज के दौरान फ़ाइलों को बदलने की अनुमति दें, लेकिन तुरंत मर्ज के बाद "गिट चेकआउट शाखा -" का उपयोग करें। हर मर्ज के बाद कॉन्फिग ब्रांच से हमारी कॉन्फिग फाइल को कॉपी करना। विस्तृत स्टैकओवरफ़्लो उत्तर यहाँ

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.