Git के साथ एक शाखा बिंदु ढूँढना?


455

मेरे पास शाखाओं मास्टर और ए के साथ एक भंडार है और दोनों के बीच बहुत सारी मर्ज गतिविधि है। जब मैं मास्टर के आधार पर शाखा ए बनाया गया था तो मैं अपने भंडार में प्रतिबद्ध कैसे पा सकता हूं?

मेरा भंडार मूल रूप से इस तरह दिखता है:

-- X -- A -- B -- C -- D -- F  (master) 
          \     /   \     /
           \   /     \   /
             G -- H -- I -- J  (branch A)

मैं संशोधन ए की तलाश कर रहा हूं, जो नहीं git merge-base (--all)मिल रहा है।


जवाबों:


499

मैं उसी चीज की तलाश में था, और मुझे यह सवाल मिला। यह पूछने के लिए धन्यवाद!

हालांकि, मैंने पाया कि उत्तर मैं यहाँ देखने के लिए नहीं है काफी जवाब आप के लिए (या कि मैं खोज रहा था) से पूछा दे - वे देने के लिए लग रहे Gकरने के बजाय Aप्रतिबद्ध।

इसलिए, मैंने निम्नलिखित पेड़ (कालानुक्रमिक क्रम में दिए गए पत्र) बनाए हैं, इसलिए मैं चीजों का परीक्षण कर सकता हूं:

A - B - D - F - G   <- "master" branch (at G)
     \   \     /
      C - E --'     <- "topic" branch (still at E)

यह आपकी तुलना में थोड़ा अलग दिखता है, क्योंकि मैं यह सुनिश्चित करना चाहता था कि मुझे मिला (इस ग्राफ का उल्लेख करते हुए, आपका नहीं) बी, लेकिन ए (और डी या ई नहीं)। यहाँ SHA उपसर्गों और प्रतिबद्ध संदेशों से जुड़े पत्र हैं (मेरी रेपो को यहाँ से क्लोन किया जा सकता है , अगर यह किसी के लिए दिलचस्प है):

G: a9546a2 merge from topic back to master
F: e7c863d commit on master after master was merged to topic
E: 648ca35 merging master onto topic
D: 37ad159 post-branch commit on master
C: 132ee2a first commit on topic branch
B: 6aafd7f second commit on master before branching
A: 4112403 initial commit on master

तो, लक्ष्य: बी खोजें । यहां तीन तरीके हैं जो मैंने पाया, थोड़ा सा छेड़छाड़ के बाद:


1. नेत्रहीन, gitk के साथ:

आपको नेत्रहीन इस तरह से एक पेड़ देखना चाहिए (जैसा कि मास्टर से देखा गया है):

मास्टर से कब्जा स्क्रीन कब्जा

या यहाँ (विषय से देखा गया):

विषय से gitk स्क्रीन पर कब्जा

दोनों ही स्थितियों में, मैंने वह कमिट चुना है Bजो मेरे ग्राफ में है। एक बार जब आप इस पर क्लिक करते हैं, तो इसका पूरा SHA ग्राफ के ठीक नीचे एक टेक्स्ट इनपुट फील्ड में प्रस्तुत किया जाता है।


2. नेत्रहीन, लेकिन टर्मिनल से:

git log --graph --oneline --all

(संपादित / साइड-नोट: जोड़ना --decorateभी दिलचस्प हो सकता है; यह शाखा के नाम, टैग, आदि का एक संकेत जोड़ता है। इसे कमांड-लाइन से ऊपर नहीं जोड़ना है क्योंकि नीचे आउटपुट इसके उपयोग को प्रतिबिंबित नहीं करता है।)

जो दिखाता है (मानते हुए git config --global color.ui auto):

git लॉग -ग्राफ --online --all का आउटपुट

या, सीधे पाठ में:

* a9546a2 विषय से वापस मास्टर में विलय
| \  
| * 648ca35 विषय पर मास्टर विलय
| | \  
| * 132ee2a पहले विषय शाखा पर आधारित है
* | e7c863d मास्टर के विषय पर प्रतिबद्ध होने के बाद विषय में विलय कर दिया गया
| | /  
| / |   
* 37ad159 पोस्ट-ब्रांच मास्टर पर प्रतिबद्ध
| /  
* 6aafd7f ब्रांचिंग से पहले मास्टर पर दूसरा वचन
* 4112403 मास्टर पर प्रारंभिक प्रतिबद्धता

या तो मामले में, हम 6aafd7f को सबसे कम सामान्य बिंदु के रूप में देखते हैं, अर्थात Bमेरे ग्राफ में, या आप Aमें।


3. शैल जादू के साथ:

आप अपने प्रश्न में निर्दिष्ट नहीं करते हैं कि क्या आप उपरोक्त जैसा कुछ चाहते थे, या एक ही आदेश जो आपको केवल एक संशोधन मिलेगा, और कुछ नहीं। खैर, यहाँ बाद है:

diff -u <(git rev-list --first-parent topic) \
             <(git rev-list --first-parent master) | \
     sed -ne 's/^ //p' | head -1
6aafd7ff98017c816033df18395c5c1e7829960d

जिसे आप अपने ~ / .itconfig में भी डाल सकते हैं (ध्यान दें: ट्रेलिंग डैश महत्वपूर्ण है; उस पर ध्यान देने के लिए ब्रायन का धन्यवाद :

[alias]
    oldest-ancestor = !zsh -c 'diff -u <(git rev-list --first-parent "${1:-master}") <(git rev-list --first-parent "${2:-HEAD}") | sed -ne \"s/^ //p\" | head -1' -

जो निम्नलिखित के माध्यम से किया जा सकता है (उद्धृत के साथ जटिल) कमांड-लाइन:

git config --global alias.oldest-ancestor '!zsh -c '\''diff -u <(git rev-list --first-parent "${1:-master}") <(git rev-list --first-parent "${2:-HEAD}") | sed -ne "s/^ //p" | head -1'\'' -'

नोट: zshबस के रूप में आसानी से किया जा सकता है bash, लेकिन काम नहींsh करेगा - सिंटैक्स वेनिला में मौजूद नहीं है । (इस पृष्ठ पर एक और उत्तर पर टिप्पणी में मुझे इसके बारे में जानने के लिए @conny, फिर से धन्यवाद!)<()sh

नोट: उपरोक्त का वैकल्पिक संस्करण:

यह इंगित करने के लिए लियोरी के लिए धन्यवाद कि समान शाखाओं की तुलना करने पर ऊपर नीचे हो सकता है, और एक वैकल्पिक रूप के साथ आ रहा है जो मिक्स से सेड फॉर्म को निकालता है, और यह "सुरक्षित" बनाता है (अर्थात यह एक परिणाम देता है (अर्थात्) सबसे हाल का वचन) तब भी जब आप गुरु की तुलना गुरु से करते हैं):

.Git-config लाइन के रूप में:

[alias]
    oldest-ancestor = !zsh -c 'diff --old-line-format='' --new-line-format='' <(git rev-list --first-parent "${1:-master}") <(git rev-list --first-parent "${2:-HEAD}") | head -1' -

शेल से:

git config --global alias.oldest-ancestor '!zsh -c '\''diff --old-line-format='' --new-line-format='' <(git rev-list --first-parent "${1:-master}") <(git rev-list --first-parent "${2:-HEAD}") | head -1'\'' -'

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


तो, यही मैं [और liori] के साथ आया था। ऐसा लगता है यह मेरे लिए काम का होगा। यह उपनामों की एक अतिरिक्त जोड़ी की भी अनुमति देता है जो उपयोगी साबित हो सकती हैं:

git config --global alias.branchdiff '!sh -c "git diff `git oldest-ancestor`.."'
git config --global alias.branchlog '!sh -c "git log `git oldest-ancestor`.."'

खुश git-ing!


5
धन्यवाद lindes, शेल विकल्प उन स्थितियों के लिए बहुत अच्छा है जहां आप लंबे समय तक चलने वाली रखरखाव शाखा के शाखा बिंदु को ढूंढना चाहते हैं। जब आप एक संशोधन की तलाश कर रहे हैं जो अतीत में एक हजार हो सकता है, तो दृश्य विकल्प वास्तव में इसे काटने नहीं जा रहे हैं। * 8 ')
मार्क बूथ

4
अपनी तीसरी विधि में आप इस बात पर निर्भर करते हैं कि संदर्भ पहली अपरिवर्तित रेखा दिखाएगा। यह कुछ विशेष मामलों में नहीं होगा या यदि आप कुछ अलग-अलग आवश्यकताओं के लिए होते हैं (उदाहरण के लिए मुझे केवल एक ही हिस्टरी की आवश्यकता है - फ़र्स्ट-पैरेंट, और मैं इस पद्धति का उपयोग स्क्रिप्ट में कर रहा हूं जो कभी-कभी उसी का उपयोग कर सकता है दोनों तरफ शाखाएँ)। मैंने पाया कि diffअगर-तब-तब मोड का उपयोग करना सुरक्षित था और इसके आउटपुट से परिवर्तित / हटाए गए लाइनों को बड़े पर्याप्त संदर्भ होने पर गिनने के बजाय अपने आउटपुट से मिटा / मिटा दिया diff --old-line-format='' --new-line-format='' <(git rev-list …) <(git rev-list …)|head -1
liori

3
git log -n1 --format=format:%H $(git log --reverse --format=format:%H master..topic | head -1)~के रूप में अच्छी तरह से काम करेंगे, मुझे लगता है
टोबीस शुल्त

4
@ JakubNar Jakbski: क्या आपके पास इस पेड़ के लिए git merge-base --fork-point ...प्रतिबद्ध बी (कमिट 6aafd7f) देने का कोई तरीका है ? जब आप इसे पोस्ट करते हैं, तो मैं अन्य सामानों में व्यस्त था, और यह अच्छा लग रहा था, लेकिन मैंने आखिरकार बस कोशिश की, और मैं इसे काम नहीं कर रहा हूं ... मुझे या तो हाल ही में कुछ मिला है, या बस एक मूक विफलता (कोई त्रुटि नहीं है) संदेश है, लेकिन बाहर निकलने का दर्जा 1), जैसे तर्कों की कोशिश कर रहा git co master; git merge-base --fork-point topic, git co topic; git merge-base --fork-point master, git merge-base --fork-point topic master(या तो चेकआउट के लिए), आदि वहाँ कुछ मैं गलत कर या याद कर रहा हूँ है?
22:29 पर lindes

25
@ JakubNar Jakbski @lindes रिफ्लग --fork-pointपर आधारित है, इसलिए यह केवल तभी काम करेगा जब आपने स्थानीय स्तर पर बदलाव किए हों। फिर भी, रिफ्लॉग प्रविष्टियाँ समाप्त हो सकती थीं। यह उपयोगी है लेकिन विश्वसनीय नहीं है।
डैनियल लुबरोव

131

आप के लिए देख रहे हो सकता है git merge-base:

git मर्ज-बेस तीन-मर्ज में उपयोग करने के लिए दो कमिट के बीच सबसे अच्छा सामान्य पूर्वज (s) पाता है। एक सामान्य पूर्वज अन्य सामान्य पूर्वजों की तुलना में बेहतर है यदि बाद वाला पूर्व का पूर्वज है। एक सामान्य पूर्वज जिसमें कोई बेहतर सामान्य पूर्वज नहीं होता है, वह एक सबसे अच्छा सामान्य पूर्वज होता है , जो एक मर्ज आधार होता है । ध्यान दें कि एक जोड़ी के लिए एक से अधिक मर्ज का आधार हो सकता है।


10
--allgit merge-base
जैकब नरęबस्की

10
यह मूल प्रश्न का उत्तर नहीं देता है, लेकिन अधिकांश लोग बहुत सरल प्रश्न पूछते हैं जिसके लिए यह उत्तर है :)
FelipeC

6
उन्होंने कहा कि उन्होंने गेट मर्ज-बेस का परिणाम नहीं निकाला
टॉम टेनर

9
@TomTanner: मैंने सिर्फ प्रश्न इतिहास को देखा और मूल प्रश्न को git merge-baseमेरे उत्तर पोस्ट किए जाने के लगभग पांच घंटे बाद नोट करने के लिए संपादित किया गया था (शायद मेरे जवाब के जवाब में)। फिर भी, मैं इस उत्तर को छोड़ दूंगा क्योंकि यह अभी भी किसी और के लिए उपयोगी हो सकता है जो इस प्रश्न को खोज के माध्यम से पाता है।
ग्रेग हेवगिल

मेरा मानना ​​है कि आप मर्ज-बेस --all से परिणाम का उपयोग कर सकते हैं और फिर सूची से सबसे पुराने सामान्य पूर्वज को खोजने के लिए मर्ज-बेस - पूर्वज का उपयोग करके वापसी की सूची के माध्यम से झारना कर सकते हैं, लेकिन यह सबसे आसान तरीका नहीं है ।
मैट_जी

42

मैंने git rev-listइस तरह की चीज के लिए उपयोग किया है। उदाहरण के लिए, ( 3 बिंदुओं पर ध्यान दें )

$ git rev-list --boundary branch-a...master | grep "^-" | cut -c2-

शाखा बिंदु को बाहर थूक देगा। अब, यह सही नहीं है; चूँकि आपने मास्टर को शाखा A में एक बार विलय कर दिया है, इसलिए यह कुछ संभावित शाखा बिंदुओं (मूल रूप से मूल शाखा बिंदु और फिर प्रत्येक बिंदु पर जिसे आपने शाखा A में विलय कर दिया है) को विभाजित कर देगा। हालांकि, इसे कम से कम संभावनाओं को कम करना चाहिए।

मैंने उस उपनाम को इस ~/.gitconfigरूप में जोड़ा है :

[alias]
    diverges = !sh -c 'git rev-list --boundary $1...$2 | grep "^-" | cut -c2-'

इसलिए मैं इसे कॉल कर सकता हूं:

$ git diverges branch-a master

नोट: यह आम पूर्वज के बजाय शाखा पर पहली प्रतिबद्धता देने के लिए लगता है। (यानी यह मूल प्रश्न में ग्राफ के अनुसार के Gबजाय देता है A।) मेरे पास एक उत्तर है जो मिलता है A, कि मैं वर्तमान में पोस्ट कर रहा हूं।
14'11

@ लिंड्स: यह मेरे द्वारा आजमाए गए हर मामले में सामान्य पूर्वज देता है। क्या आपके पास एक उदाहरण है जहां यह नहीं है?
मियादी

हाँ। में मेरा उत्तर (जो एक रेपो आप को क्लोन कर सकते हैं के लिए एक लिंक है;git checkout topic और उसके बाद के साथ इस चलाने topicके स्थान पर branch-a), यह सूचियों 648ca357b946939654da12aaf2dc072763f3caeeऔर 37ad15952db5c065679d7fc31838369712f0b338- दोनों 37ad159और 648ca35वर्तमान शाखाओं के ancestory में हैं (बेलन के वर्तमान प्रधान जा रहा है topic), लेकिन न तो ब्रांचिंग होने से पहले की बात है। क्या आपको कुछ अलग मिलता है?
15'11

@ लिंड्स: मैं आपके रेपो (संभवतः एक अनुमति समस्या?) का क्लोन बनाने में असमर्थ था।
मियादी

अरे! माफ़ करना! मुझे जानकारी देने के लिए धन्यवाद। मैं git update-server-info चलाना भूल गया। अब जाना अच्छा होना चाहिए। :)
16'11

31

यदि आपको ट्रिक्स कमांड पसंद हैं,

git रि-लिस्ट $ (git Rev-list --first-parent ^ ब्रांच_नाम मास्टर | टेल -n1) ^ ^! 

यहाँ एक स्पष्टीकरण है।

निम्नलिखित कमांड आपको मास्टर में सभी कमिट्स की सूची देता है जो ब्रांच_नाम बनने के बाद हुई थी

git Rev-list --first-parent ^ ब्रांच_नाम मास्टर 

चूँकि आप केवल उन कमियों के बारे में परवाह करते हैं जो आप चाहते हैं कि आउटपुट की अंतिम पंक्ति हो:

git की रि-लिस्ट ^ Branch_name --first- पैरेंट मास्टर | पूंछ-n1

जल्द से जल्द की मूल प्रतिबद्ध है कि "branch_name" के एक पूर्वज नहीं है परिभाषा से, है, में "branch_name," और "मास्टर" में है, क्योंकि यह कुछ के एक पूर्वज है "गुरु।" तो आप दोनों शाखाओं में जल्द से जल्द प्रतिबद्ध है।

आदेश

git रि-लिस्ट प्रतिबद्ध ^ ^!

माता-पिता के संदर्भ को दिखाने का एक तरीका है। आप उपयोग कर सकते हैं

git लॉग -1 प्रतिबद्ध ^

जो कुछ भी।

पुनश्च: मैं इस तर्क से असहमत हूं कि पूर्वजों का आदेश अप्रासंगिक है। आपको क्या चाहिए इस पर यह निर्भर है। उदाहरण के लिए, इस मामले में

_C1___C2_______ मास्टर
  \ \ _XXXXX_ शाखा A (X, मास्टर और A के बीच मनमाने ढंग से क्रॉस ओवरों को दर्शाता है)
   \ _____ / शाखा बी

यह C2 को "ब्रांचिंग" कमिट के रूप में आउटपुट करने के लिए सही समझ में आता है। यह तब होता है जब डेवलपर "मास्टर" से बाहर निकल जाता है। जब उन्होंने शाखा लगाई, तो शाखा "बी" का उनकी शाखा में विलय भी नहीं हुआ था! इस पोस्ट में समाधान क्या है।

यदि आप जो चाहते हैं वह अंतिम प्रतिबद्ध सी है जैसे कि शाखा "ए" पर मूल से अंतिम प्रतिबद्ध तक के सभी रास्ते सी के माध्यम से जाते हैं, तो आप पैतृक क्रम को अनदेखा करना चाहते हैं। यह विशुद्ध रूप से सामयिक है और आपको एक विचार देता है जब आपके पास एक ही समय में कोड के दो संस्करण होते हैं। जब आप मर्ज-बेस आधारित दृष्टिकोणों के साथ जाएंगे, और यह मेरे उदाहरण में C1 लौटाएगा।


3
यह अब तक का सबसे साफ जवाब है, आइए इस वोट को शीर्ष पर पहुंचाएं। एक सुझाए गए संपादन: git rev-list commit^^!को सरल बनाया जा सकता हैgit rev-parse commit^
रसेल डेविस

इसका उत्तर होना चाहिए!
त्रिपिटक

2
यह उत्तर अच्छा है, मैंने सिर्फ इसलिए प्रतिस्थापित git rev-list --first-parent ^branch_name masterकिया git rev-list --first-parent branch_name ^masterक्योंकि यदि मास्टर शाखा अन्य शाखा (इसके आगे तेजी से अग्रेषित) के आगे 0 कमिट है, तो कोई आउटपुट नहीं बनाया जाएगा। मेरे समाधान के साथ, यदि मास्टर सख्ती से आगे है (यानी शाखा पूरी तरह से विलय कर दी गई है), तो कोई आउटपुट नहीं बनता है, जो कि मैं चाहता हूं।
माइकल शमीउर

3
यह तब तक काम नहीं करेगा जब तक कि मैं पूरी तरह से कुछ याद नहीं कर रहा हूं। उदाहरण शाखाओं में दोनों दिशाओं में विलय होते हैं। ऐसा लगता है कि आपने इसे ध्यान में रखने की कोशिश की, लेकिन मेरा मानना ​​है कि यह आपके उत्तर को विफल कर देगा। git rev-list --first-parent ^topic masterकेवल आप के लिए वापस पहले से पिछले मर्ज के बाद प्रतिबद्ध ले जाएगा masterमें topic(यह है कि यदि भी मौजूद है)।
जेरी

1
@ जेरी आप सही हैं, यह उत्तर कचरा है; उदाहरण के लिए, इस मामले में कि एक बैकमरेज अभी हुआ है (विषय में मास्टर विलय), और मास्टर के बाद कोई नया कमिट नहीं है, पहली git रि-लिस्ट-first- पैरेंट कमांड कमांड कुछ भी नहीं आउटपुट करता है।
TamaMcGlinn

19

यह देखते हुए कि इस सूत्र में बहुत सारे उत्तर उस प्रश्न का उत्तर नहीं देते हैं जो प्रश्न पूछ रहा था, यहां प्रत्येक समाधान के परिणामों का एक सारांश है, साथ ही स्क्रिप्ट मैं प्रश्न में दिए गए भंडार को दोहराने के लिए उपयोग किया गया था।

लकड़ी का लठा

दी गई संरचना के साथ एक रिपॉजिटरी बनाते हुए, हमें इसका लॉग लॉग मिलता है:

$ git --no-pager log --graph --oneline --all --decorate
* b80b645 (HEAD, branch_A) J - Work in branch_A branch
| *   3bd4054 (master) F - Merge branch_A into branch master
| |\  
| |/  
|/|   
* |   a06711b I - Merge master into branch_A
|\ \  
* | | bcad6a3 H - Work in branch_A
| | * b46632a D - Work in branch master
| |/  
| *   413851d C - Merge branch_A into branch master
| |\  
| |/  
|/|   
* | 6e343aa G - Work in branch_A
| * 89655bb B - Work in branch master
|/  
* 74c6405 (tag: branch_A_tag) A - Work in branch master
* 7a1c939 X - Work in branch master

मेरा एकमात्र जोड़, वह टैग है जो उस बिंदु के बारे में स्पष्ट करता है, जिस पर हमने शाखा बनाई थी और इस प्रकार हम जिस प्रतिबद्धता को खोजना चाहते हैं।

जो समाधान काम करता है

एकमात्र समाधान जो काम करता है द्वारा प्रदान की एक है lindes सही ढंग से रिटर्न A:

$ diff -u <(git rev-list --first-parent branch_A) \
          <(git rev-list --first-parent master) | \
      sed -ne 's/^ //p' | head -1
74c6405d17e319bd0c07c690ed876d65d89618d5

चार्ल्स बेली के रूप में बताते हैं, यह समाधान बहुत भंगुर है।

यदि आप बिना किसी रोक-टोक के विलय branch_Aकरते हैं masterऔर फिर आपस masterमें branch_Aजुड़ते हैं तो लिंड्स का समाधान आपको सबसे हाल ही में पहला गोताखोरी देता है

इसका मतलब है कि मेरे वर्कफ़्लो के लिए, मुझे लगता है कि मुझे लंबे समय तक चलने वाली शाखाओं के शाखा बिंदु को टैग करने के साथ रहना होगा, क्योंकि मैं गारंटी नहीं दे सकता कि उन्हें मज़बूती से बाद में पाया जा सकता है।

यह वास्तव में सब पर निर्भर करने के लिए gitरों क्या की कमी के कारण hgकॉल नामित शाखाओं । ब्लॉगर jhw ने अपने लेख में इन वंशों बनाम परिवारों को क्यों बुलाया है I मुझे मर्क्यूरियल मोर ऑफ़ गिट और उनके अनुवर्ती लेख मोर ऑन मर्क्यूरियल बनाम गिट (ग्राफ़ के साथ!) । मैं लोगों को उन्हें पढ़ने के लिए सलाह दूंगा कि क्यों कुछ भाड़े के धर्मान्तरित लोगों को शाखा में नाम नहीं मिलाgit

जो समाधान काम नहीं करते हैं

मिपाडी द्वारा प्रदान किया गया समाधान दो उत्तर देता है, Iऔर C:

$ git rev-list --boundary branch_A...master | grep ^- | cut -c2-
a06711b55cf7275e8c3c843748daaa0aa75aef54
413851dfecab2718a3692a4bba13b50b81e36afc

ग्रेग Hewgill वापसी द्वारा प्रदान समाधानI

$ git merge-base master branch_A
a06711b55cf7275e8c3c843748daaa0aa75aef54
$ git merge-base --all master branch_A
a06711b55cf7275e8c3c843748daaa0aa75aef54

कार्ल रिटर्न द्वारा प्रदान किया गया समाधान X:

$ diff -u <(git log --pretty=oneline branch_A) \
          <(git log --pretty=oneline master) | \
       tail -1 | cut -c 2-42
7a1c939ec325515acfccb79040b2e4e1c3e7bbe5

लिपी

mkdir $1
cd $1
git init
git commit --allow-empty -m "X - Work in branch master"
git commit --allow-empty -m "A - Work in branch master"
git branch branch_A
git tag branch_A_tag     -m "Tag branch point of branch_A"
git commit --allow-empty -m "B - Work in branch master"
git checkout branch_A
git commit --allow-empty -m "G - Work in branch_A"
git checkout master
git merge branch_A       -m "C - Merge branch_A into branch master"
git checkout branch_A
git commit --allow-empty -m "H - Work in branch_A"
git merge master         -m "I - Merge master into branch_A"
git checkout master
git commit --allow-empty -m "D - Work in branch master"
git merge branch_A       -m "F - Merge branch_A into branch master"
git checkout branch_A
git commit --allow-empty -m "J - Work in branch_A branch"

मुझे संदेह है कि git संस्करण को इससे बहुत फर्क पड़ता है, लेकिन:

$ git --version
git version 1.7.1

उदाहरण भंडार को स्क्रिप्ट करने के लिए मुझे और अधिक कॉम्पैक्ट तरीका दिखाने के लिए चार्ल्स बेली को धन्यवाद ।


2
कार्ल द्वारा समाधान को ठीक करना आसान है diff -u <(git rev-list branch_A) <(git rev-list master) | tail -2 | head -1:। रेपो बनाने के लिए निर्देश प्रदान करने के लिए धन्यवाद :)
फेलिपेक्ट

मुझे लगता है कि आपका मतलब है "कार्ल रिटर्न एक्स द्वारा प्रदान किए गए समाधान की साफ-सुथरी विविधता।" मूल काम ठीक था यह सिर्फ बदसूरत था :-)
कार्ल

नहीं, आपका मूल ठीक काम नहीं करता है। दी, विविधता भी सबसे खराब काम करती है। लेकिन विकल्प को जोड़ने --टॉप-ऑर्डर से आपका संस्करण काम करता है :)
फेलिपेस्क

@felipec - चार्ल्स बैली के जवाब पर मेरी अंतिम टिप्पणी देखें । काश हमारी चैट (और इस तरह सभी पुरानी टिप्पणियां) अब हटा दी गईं। समय मिलने पर मैं अपने उत्तर को अपडेट करने की कोशिश करूंगा।
मार्क बूथ

दिलचस्प। मुझे लगता है कि टोपोलॉजिकल डिफ़ॉल्ट था। मूर्खतापूर्ण मुझे :-)
कार्ल

10

सामान्य तौर पर, यह संभव नहीं है। एक शाखा के इतिहास में एक शाखा और एक विलय से पहले एक नामित शाखा को बंद कर दिया गया था और दो नामित शाखाओं की एक मध्यवर्ती शाखा समान दिखती है।

गिट में, शाखाएं इतिहास के वर्गों की युक्तियों के वर्तमान नाम हैं। उनकी वास्तव में मजबूत पहचान नहीं है।

यह आमतौर पर एक बड़ा मुद्दा नहीं है क्योंकि दो-कमिट्स का मर्ज-बेस (ग्रेग हेवगिल का उत्तर देखें) आमतौर पर बहुत अधिक उपयोगी होता है, जिससे सबसे हालिया कमिटमेंट मिलता है जिसे दोनों शाखाओं ने साझा किया है।

एक प्रतिबद्ध माता-पिता के आदेश पर निर्भर एक समाधान स्पष्ट रूप से उन स्थितियों में काम नहीं करेगा जहां एक शाखा को शाखा के इतिहास में कुछ बिंदु पर पूरी तरह से एकीकृत किया गया है।

git commit --allow-empty -m root # actual branch commit
git checkout -b branch_A
git commit --allow-empty -m  "branch_A commit"
git checkout master
git commit --allow-empty -m "More work on master"
git merge -m "Merge branch_A into master" branch_A # identified as branch point
git checkout branch_A
git merge --ff-only master
git commit --allow-empty -m "More work on branch_A"
git checkout master
git commit --allow-empty -m "More work on master"

यह तकनीक भी नीचे गिर जाती है अगर एक एकीकरण मर्ज उलटा हुआ माता-पिता के साथ किया गया है (उदाहरण के लिए एक अस्थायी शाखा का उपयोग मास्टर में एक परीक्षण मर्ज करने के लिए किया गया था और फिर आगे की ओर बनाने के लिए सुविधा शाखा में तेजी से अग्रेषित किया गया)।

git commit --allow-empty -m root # actual branch point
git checkout -b branch_A
git commit --allow-empty -m  "branch_A commit"
git checkout master
git commit --allow-empty -m "More work on master"
git merge -m "Merge branch_A into master" branch_A # identified as branch point
git checkout branch_A
git commit --allow-empty -m "More work on branch_A"

git checkout -b tmp-branch master
git merge -m "Merge branch_A into tmp-branch (master copy)" branch_A
git checkout branch_A
git merge --ff-only tmp-branch
git branch -d tmp-branch

git checkout master
git commit --allow-empty -m "More work on master"


3
धन्यवाद चार्ल्स, आपने मुझे आश्वस्त किया है, अगर मैं उस बिंदु को जानना चाहता हूं जिस पर मूल रूप से शाखा निकाली गई है , तो मुझे इसे टैग करना होगा। मैं वास्तव में है कि इच्छा gitएक बराबर ही था hg, 'एस शाखाओं नामित यह लंबे समय से रहते थे रखरखाव शाखाओं प्रबंध होगा तो बहुत आसान है।
मार्क बूथ

1
"Git में, शाखाएँ इतिहास के वर्गों की युक्तियों के वर्तमान नाम हैं। उनके पास वास्तव में एक मजबूत पहचान नहीं है" यह कहने के लिए एक डरावनी बात है और मुझे आश्वस्त किया है कि मुझे Git शाखाओं को बेहतर समझने की आवश्यकता है - धन्यवाद (+ 1)
dumbledad

एक शाखा के इतिहास में एक शाखा और एक विलय से पहले एक नामित शाखा को बंद कर दिया गया था और दो नामित शाखाओं की एक मध्यवर्ती शाखा समान दिखती है। हां। +1।
user1071847

5

कैसे कुछ के बारे में

git log --pretty=oneline master > 1
git log --pretty=oneline branch_A > 2

git rev-parse `diff 1 2 | tail -1 | cut -c 3-42`^

यह काम। यह वास्तव में बोझिल है, लेकिन यह केवल एक चीज है जो मैंने पाया है कि वास्तव में काम करने के लिए लगता है।
गैरीओ

1
Git उर्फ बराबर: diverges = !bash -c 'git rev-parse $(diff <(git log --pretty=oneline ${1}) <(git log --pretty=oneline ${2}) | tail -1 | cut -c 3-42)^'(कोई अस्थायी फ़ाइलों के साथ)
conny

@conny: ओह, वाह - मैंने कभी <(foo) सिंटैक्स नहीं देखा ... यह अविश्वसनीय रूप से उपयोगी है, धन्यवाद! (वर्क्स zsh में, भी, FYI करें।)
lindes

यह मुझे आम पूर्वजों के बजाय शाखा पर पहली प्रतिबद्धता देने के लिए लगता है। (यानी यह मूल प्रश्न में ग्राफ के अनुसार के Gबजाय देता है A।) मुझे लगता है कि मुझे एक उत्तर मिला है, हालांकि, जो मैं वर्तमान में पोस्ट करूंगा।
lindes

'Git log --pretty = oneline' के बजाय आप केवल 'git Rev-list' कर सकते हैं, फिर आप कट को भी छोड़ सकते हैं, इसके अलावा, यह विचलन के बिंदु की मूल प्रति देता है, इसलिए सिर्फ टेल -2 | सिर 1. तो:diff -u <(git rev-list branch_A) <(git rev-list master) | tail -2 | head -1
FelipeC

5

निश्चित रूप से मुझे कुछ याद आ रहा है, लेकिन IMO, उपरोक्त सभी समस्याएं इसलिए हैं क्योंकि हम हमेशा इतिहास में शाखा बिंदु को वापस खोजने की कोशिश कर रहे हैं, और जो कि विलय के संयोजन के कारण सभी प्रकार की समस्याओं का कारण बनता है।

इसके बजाय, मैंने एक अलग दृष्टिकोण का पालन किया है, इस तथ्य के आधार पर कि दोनों शाखाएं बहुत सारे इतिहास साझा करती हैं, वास्तव में शाखा से पहले सभी इतिहास 100% समान हैं, इसलिए वापस जाने के बजाय, मेरा प्रस्ताव आगे बढ़ने के बारे में है (1 से प्रतिबद्ध), दोनों शाखाओं में 1 अंतर की तलाश में। शाखा बिंदु, बस, पहले अंतर के जनक पाया जाएगा।

प्रयोग में:

#!/bin/bash
diff <( git rev-list "${1:-master}" --reverse --topo-order ) \
     <( git rev-list "${2:-HEAD}" --reverse --topo-order) \
--unified=1 | sed -ne 's/^ //p' | head -1

और यह मेरे सभी सामान्य मामलों को हल कर रहा है। सुनिश्चित करें कि सीमा वाले कवर नहीं हैं लेकिन ... ciao :-)


diff <(git Rev-list "$ {1: -master}" --first-parent) <(git Rev-list "$ {2: -HEAD}" --first-parent) -U1 | पूंछ -1
अलेक्जेंडर बर्ड

मुझे यह तेज (2-100x) पाया गया:comm --nocheck-order -1 -2 <(git rev-list --reverse --topo-order topic) <(git rev-list --reverse --topo-order master) | head -1
आंद्रेई नेकुलॉउ

4

मुझे हाल ही में इस समस्या को हल करने की आवश्यकता थी और इसके लिए एक रूबी स्क्रिप्ट लिखना समाप्त किया: https://github.com/vaneyckt/git-find-branching-point


यह काम नहीं कर रहा है, "unpack_object_header_gently" में विफल रहा है और इसे बनाए नहीं रखा गया है।
पुचु

4

बहुत सारे शोध और चर्चाओं के बाद, यह स्पष्ट है कि कोई भी जादू की गोली नहीं है जो सभी स्थितियों में काम करेगी, कम से कम गिट के वर्तमान संस्करण में नहीं।

इसलिए मैंने एक-दो पाट लिखे, जो एक tailशाखा की अवधारणा को जोड़ते हैं । हर बार जब एक शाखा बनाई जाती है, तो मूल बिंदु पर एक संकेतक भी बनाया जाता हैtail रेफ। हर बार शाखा में छूट होने पर यह रेफ अपडेट हो जाता है।

देवल शाखा के शाखा बिंदु का पता लगाने के लिए, आपको बस इतना करना है devel@{tail}कि इसका उपयोग करना है , बस।

https://github.com/felipec/git/commits/fc/tail


1
एकमात्र स्थिर समाधान हो सकता है। क्या आपने देखा कि क्या यह पकड़ में आ सकता है? मुझे पुल अनुरोध नहीं दिखाई दिया।
अलेक्जेंडर क्लिमेत्स्क

@AlexanderKlimetschek मैंने पैच नहीं भेजे, और मुझे नहीं लगता कि उन्हें स्वीकार किया जाएगा। हालांकि, मैंने एक अलग विधि की कोशिश की: एक "अपडेट-ब्रांच" हुक जो कुछ समान करता है। इस तरह से डिफ़ॉल्ट रूप से Git कुछ भी नहीं करेगा, लेकिन आप पूंछ शाखा को अपडेट करने के लिए हुक को सक्षम कर सकते हैं। आपके पास हालांकि, {{पूँछ} devel नहीं होगा, लेकिन इसके बजाय पूंछ / devel का उपयोग करना इतना बुरा नहीं होगा।
फेलिपक

3

यहाँ मेरे पिछले उत्तर पिछले उत्तर के एक उन्नत संस्करण है । यह विलय से प्रतिबद्ध संदेशों पर निर्भर करता है ताकि यह पता लगाया जा सके कि शाखा पहले कहां बनाई गई थी।

यह यहाँ उल्लिखित सभी रिपॉजिटरी पर काम करता है, और मैंने कुछ मुश्किल लोगों को भी संबोधित किया है जो मेलिंग सूची में शामिल हैं । मैंने इसके लिए परीक्षण भी लिखा था

find_merge ()
{
    local selection extra
    test "$2" && extra=" into $2"
    git rev-list --min-parents=2 --grep="Merge branch '$1'$extra" --topo-order ${3:---all} | tail -1
}

branch_point ()
{
    local first_merge second_merge merge
    first_merge=$(find_merge $1 "" "$1 $2")
    second_merge=$(find_merge $2 $1 $first_merge)
    merge=${second_merge:-$first_merge}

    if [ "$merge" ]; then
        git merge-base $merge^1 $merge^2
    else
        git merge-base $1 $2
    fi
}

3

निम्न आदेश कमेंट A के SHA1 को प्रकट करेगा

git merge-base --fork-point A


यह अभ्यस्त यदि माता-पिता और बच्चे की शाखाओं के बीच में एक दूसरे के मध्यवर्ती विलय होते हैं।
नवाफल

2

मुझे लगता है कि मुझे कुछ खुशी मिल रही है

git rev-list branch...master

आपके द्वारा प्राप्त की जाने वाली अंतिम पंक्ति शाखा पर पहली प्रतिबद्ध है, इसलिए यह उस के माता-पिता को प्राप्त करने की बात है। इसलिए

git rev-list -1 `git rev-list branch...master | tail -1`^

मेरे लिए काम करने लगता है और इसकी आवश्यकता नहीं है और इतने पर (जो सहायक है क्योंकि हमारे पास भिन्नता का संस्करण नहीं है)

सुधार: यह काम नहीं करता है यदि आप मास्टर शाखा पर हैं, लेकिन मैं इसे एक स्क्रिप्ट में कर रहा हूं ताकि यह एक समस्या से कम हो


2

शाखामिलन बिंदु से आने के लिए, आप इसका उपयोग कर सकते हैं।

git log --ancestry-path master..topicbranch

यह कमांड मेरे द्वारा दिए गए छूट पर काम नहीं करता है। कृपया आप प्रतिबद्ध सीमा के लिए पैरामीटर के रूप में क्या प्रदान करेंगे?
जेसपर रॉन-जेनसेन

2

कभी-कभी यह प्रभावी रूप से असंभव है (कुछ अपवादों के साथ जहां आप अतिरिक्त डेटा रखने के लिए भाग्यशाली हो सकते हैं) और यहां समाधान काम नहीं करेंगे।

Git रेफरी इतिहास (जिसमें शाखाएँ शामिल हैं) को संरक्षित नहीं करता है। यह केवल प्रत्येक शाखा (प्रमुख) के लिए वर्तमान स्थिति को संग्रहीत करता है। इसका अर्थ है कि आप समय के साथ कुछ शाखा इतिहास खो सकते हैं। जब भी आप उदाहरण के लिए शाखा करते हैं, यह तुरंत खो जाता है कि कौन सी शाखा मूल थी। सभी एक शाखा है:

git checkout branch1    # refs/branch1 -> commit1
git checkout -b branch2 # branch2 -> commit1

आप मान सकते हैं कि पहली कमिटेड शाखा है। यह मामला है, लेकिन यह हमेशा ऐसा नहीं है। उपरोक्त ऑपरेशन के बाद सबसे पहले आपको या तो शाखा में आने से रोकना नहीं है। इसके अतिरिक्त, गिट टाइमस्टैम्प विश्वसनीय होने की गारंटी नहीं है। यह तब तक नहीं है जब तक आप दोनों के लिए प्रतिबद्ध नहीं हैं कि वे वास्तव में संरचनात्मक रूप से शाखाएं बन जाएं।

जबकि आरेखों में हम संख्या की अवधारणा करते हैं, git के पास अनुक्रम की कोई वास्तविक अवधारणा नहीं है जब प्रतिबद्ध पेड़ की शाखाएं। इस मामले में आप मान सकते हैं कि संख्याएँ (आदेश का संकेत) टाइमस्टैम्प द्वारा निर्धारित की जाती हैं (यह देखना मजेदार हो सकता है कि कैसे git UI चीजों को संभालती है जब आप सभी टाइमस्टैम्प को उसी पर सेट करते हैं)।

यह वैचारिक रूप से मानव की अपेक्षा है:

After branch:
       C1 (B1)
      /
    -
      \
       C1 (B2)
After first commit:
       C1 (B1)
      /
    - 
      \
       C1 - C2 (B2)

यह वही है जो आपको वास्तव में मिलता है:

After branch:
    - C1 (B1) (B2)
After first commit (human):
    - C1 (B1)
        \
         C2 (B2)
After first commit (real):
    - C1 (B1) - C2 (B2)

आप B1 को मूल शाखा मान लेंगे, लेकिन यह केवल एक मृत शाखा हो सकती है (किसी ने चेकआउट किया था, लेकिन इसके लिए प्रतिबद्ध नहीं था)। यह तब तक नहीं है जब तक आप दोनों के लिए प्रतिबद्ध नहीं हो जाते हैं कि आपको गिट के भीतर एक वैध शाखा संरचना मिल जाती है:

Either:
      / - C2 (B1)
    -- C1
      \ - C3 (B2)
Or:
      / - C3 (B1)
    -- C1
      \ - C2 (B2)

आप हमेशा से जानते हैं कि C1 C2 और C3 से पहले आया था, लेकिन आप कभी भी मज़बूती से नहीं जानते कि C2 C3 से पहले आया था या C3 C2 से पहले आया था (क्योंकि आप उदाहरण के लिए अपने वर्कस्टेशन पर समय सेट कर सकते हैं)। बी 1 और बी 2 भी भ्रामक है क्योंकि आप यह नहीं जान सकते कि कौन सी शाखा पहले आई थी। आप कई मामलों में इस पर बहुत अच्छा और आमतौर पर सटीक अनुमान लगा सकते हैं। यह रेस ट्रैक जैसा है। सभी चीजें आम तौर पर कारों के बराबर होती हैं तो आप यह मान सकते हैं कि एक कार जो एक गोद में आती है पीछे एक गोद शुरू हुई। हमारे पास ऐसे सम्मेलन भी हैं जो बहुत विश्वसनीय हैं, उदाहरण के लिए मास्टर लगभग हमेशा सबसे लंबे समय तक रहने वाली शाखाओं का प्रतिनिधित्व करेंगे, हालांकि दुख की बात है कि मैंने ऐसे मामले देखे हैं जहां यह मामला नहीं है।

यहाँ दिया गया उदाहरण एक इतिहास संरक्षण उदाहरण है:

Human:
    - X - A - B - C - D - F (B1)
           \     / \     /
            G - H ----- I - J (B2)
Real:
            B ----- C - D - F (B1)
           /       / \     /
    - X - A       /   \   /
           \     /     \ /
            G - H ----- I - J (B2)

यहां वास्तविक भी भ्रामक है क्योंकि हम मनुष्य इसे बाएं से दाएं पढ़ते हैं, जड़ से पत्ती (रेफ)। Git ऐसा नहीं करता है। जहाँ हम करते हैं (A-> B) हमारे सिर में git करता है (A <-B या B-> A)। यह इसे रेफ से रूट तक पढ़ता है। रेफरी कहीं भी हो सकते हैं लेकिन कम से कम सक्रिय शाखाओं के लिए, लीफ्स होते हैं। एक रेफरी एक कमिट की ओर इशारा करता है और कहता है कि उनके माता-पिता की तरह ही उनके बच्चों के लिए है। जब कोई कमिट मर्ज होता है तो उसके एक से अधिक माता-पिता होते हैं। पहला अभिभावक हमेशा मूल प्रतिबद्ध होता है जिसे विलय कर दिया गया था। अन्य माता-पिता हमेशा ऐसे होते हैं जो मूल प्रतिबद्ध में विलय कर दिए गए थे।

Paths:
    F->(D->(C->(B->(A->X)),(H->(G->(A->X))))),(I->(H->(G->(A->X))),(C->(B->(A->X)),(H->(G->(A->X)))))
    J->(I->(H->(G->(A->X))),(C->(B->(A->X)),(H->(G->(A->X)))))

यह बहुत कुशल प्रतिनिधित्व नहीं है, बल्कि सभी रास्तों की अभिव्यक्ति प्रत्येक रेफ (बी 1 और बी 2) से ले सकती है।

Git का आंतरिक संग्रहण इस तरह दिखता है (ऐसा नहीं है कि A माता-पिता के रूप में दो बार दिखाई देता है):

    F->D,I | D->C | C->B,H | B->A | A->X | J->I | I->H,C | H->G | G->A

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

Paths simplified:
    F->(D->C),I | J->I | I->H,C | C->(B->A),H | H->(G->A) | A->X
Paths first parents only:
    F->(D->(C->(B->(A->X)))) | F->D->C->B->A->X
    J->(I->(H->(G->(A->X))) | J->I->H->G->A->X
Or:
    F->D->C | J->I | I->H | C->B->A | H->G->A | A->X
Paths first parents only simplified:
    F->D->C->B->A | J->I->->G->A | A->X
Topological:
    - X - A - B - C - D - F (B1)
           \
            G - H - I - J (B2)

जब दोनों ए हिट करते हैं तो उनकी श्रृंखला समान होगी, इससे पहले उनकी श्रृंखला पूरी तरह से अलग होगी। पहली दो अन्य प्रतिबद्धताओं में सामान्य पूर्वज सामान्य पूर्वज हैं और वे किस स्थान से निकले हैं। वहाँ प्रतिबद्धताओं, शाखा और रेफ के बीच कुछ भ्रम हो सकता है। आप वास्तव में एक प्रतिबद्ध विलय कर सकते हैं। यह वही है जो वास्तव में विलय करता है। रेफरी बस एक कमिट की ओर इशारा करता है और ब्रांच। रेफरी / रेफ्स / हेड्स में रेफरी से ज्यादा कुछ नहीं होता है। फोल्डर लोकेशन यह निर्धारित करता है कि रेफ एक ब्रांच है बजाय टैग के कुछ और।

जहां आप इतिहास को खो देते हैं वह यह है कि मर्ज परिस्थितियों के आधार पर दो में से एक काम करेगा।

विचार करें:

      / - B (B1)
    - A
      \ - C (B2)

इस स्थिति में या तो दिशा में एक मर्ज पहले माता-पिता के साथ एक नई प्रतिबद्धता पैदा करेगा, क्योंकि वर्तमान चेक आउट शाखा द्वारा बताए गए कमिट के साथ और दूसरा माता-पिता उस शाखा के सिरे के रूप में जो आप अपनी वर्तमान शाखा में विलय कर चुके हैं। इसे एक नई प्रतिबद्धता बनानी होगी क्योंकि दोनों शाखाओं में अपने सामान्य पूर्वजों के साथ बदलाव होंगे जिन्हें संयुक्त होना चाहिए।

      / - B - D (B1)
    - A      /
      \ --- C (B2)

इस बिंदु पर डी (बी 1) में अब दोनों शाखाओं (स्वयं और बी 2) से परिवर्तन के सेट हैं। हालाँकि दूसरी शाखा में बी 1 से परिवर्तन नहीं है। यदि आप बी 1 से बी 2 में बदलावों को मर्ज करते हैं ताकि उन्हें समकालित किया जाए, तो आप कुछ इस तरह की उम्मीद कर सकते हैं (आप गिट मर्ज को इस तरह से करने के लिए बाध्य कर सकते हैं - हालांकि-एफएफ के साथ):

Expected:
      / - B - D (B1)
    - A      / \
      \ --- C - E (B2)
Reality:
      / - B - D (B1) (B2)
    - A      /
      \ --- C

आपको वह मिल जाएगा, भले ही बी 1 में अतिरिक्त कमिट हों। जब तक बी 2 में परिवर्तन नहीं होते हैं जो कि बी 1 के पास नहीं है, दोनों शाखाओं को मिला दिया जाएगा। यह एक तेज़ फ़ॉरवर्ड करता है जो एक रिबेस (विद्रोह भी खाता है या लीनियर हिस्ट्री) की तरह होता है, सिवाय एक रिबेज़ के विपरीत, क्योंकि केवल एक ब्रांच में बदलाव होता है, इसमें एक ब्रांच से दूसरे के ऊपर एक चेंजसेट अप्लाई नहीं करना पड़ता है।

From:
      / - B - D - E (B1)
    - A      /
      \ --- C (B2)
To:
      / - B - D - E (B1) (B2)
    - A      /
      \ --- C

यदि आप बी 1 पर काम करना बंद कर देते हैं तो लंबे समय में इतिहास को संरक्षित करने के लिए चीजें काफी हद तक ठीक हैं। केवल बी 1 (जो मास्टर हो सकता है) आमतौर पर बी 2 के इतिहास में बी 2 के स्थान को सफलतापूर्वक आगे बढ़ाएगा, यह उस बिंदु का सफलतापूर्वक प्रतिनिधित्व करता है जिसे इसे बी 1 में विलय कर दिया गया था। यह वह है जो आपको बी से ए की शाखा में करने की उम्मीद करता है, फिर आप ए को बी में विलय कर सकते हैं जैसे कि आप जैसे बदलाव जमा करते हैं, वैसे बी को ए में वापस विलय करते समय, यह उम्मीद नहीं है कि आप बी और आगे काम करेंगे। । यदि आप तेजी से आगे विलय करने के बाद अपनी शाखा पर काम कर रहे हैं, तो आप उस शाखा में काम कर रहे हैं जो आपके बी के पिछले इतिहास को हर बार मिटा रही है। आप वास्तव में तेजी से आगे स्रोत के लिए प्रतिबद्ध करने के बाद फिर शाखा के लिए हर बार एक नई शाखा बना रहे हैं।

         0   1   2   3   4 (B1)
        /-\ /-\ /-\ /-\ /
    ----   -   -   -   -
        \-/ \-/ \-/ \-/ \
         5   6   7   8   9 (B2)

1 से 3 और 5 से 8 संरचनात्मक शाखाएं हैं जो यदि आप 4 या 9 के लिए इतिहास का अनुसरण करते हैं तो दिखाते हैं। यह जानने का कोई तरीका नहीं है कि इस अनाम और अप्रकाशित संरचनात्मक शाखाओं में से कौन सी नाम और संदर्भ शाखाओं के साथ संबंधित हैं संरचना का अंत। आप इस ड्राइंग से मान सकते हैं कि 0 से 4 बी 1 से संबंधित है और 4 से 9 बी 2 से संबंधित है, लेकिन 4 और 9 के अलावा पता नहीं चल सकता है कि कौन सी शाखा किस शाखा से संबंधित है, मैंने इसे बस एक तरह से तैयार किया है जो देता है उस का भ्रम। 0 बी 2 से संबंधित हो सकता है और 5 बी 1 से संबंधित हो सकता है। इस मामले में 16 अलग-अलग कब्जे हैं जिनमें से प्रत्येक संरचनात्मक शाखा का नाम दिया गया है।

इस के आसपास काम करने वाली कई तरह की गिट स्ट्रेटेजी हैं। आप मर्ज मर्ज को कभी भी तेजी से आगे नहीं बढ़ने के लिए मजबूर कर सकते हैं और हमेशा मर्ज ब्रांच बना सकते हैं। शाखा इतिहास को संरक्षित करने का एक भयानक तरीका टैग और / या शाखाएं हैं (टैग वास्तव में अनुशंसित हैं) आपके चयन के कुछ सम्मेलन के अनुसार। जिस शाखा में आप विलय कर रहे हैं, मैं उस खाली डमी की सिफारिश नहीं करूंगा। एक बहुत ही आम सम्मेलन एक एकीकरण शाखा में विलय नहीं करना है जब तक आप अपनी शाखा को वास्तव में बंद नहीं करना चाहते हैं। यह एक ऐसी प्रथा है जिसका लोगों को पालन करने का प्रयास करना चाहिए अन्यथा आप शाखाओं के होने के बिंदु के आसपास काम कर रहे हैं। हालांकि वास्तविक दुनिया में आदर्श हमेशा व्यावहारिक नहीं होता है, सही काम करना हर स्थिति के लिए व्यवहार्य नहीं होता है। अगर तुम क्या हो '


"Git रेफरी इतिहास को संरक्षित नहीं करता है" यह करता है, लेकिन डिफ़ॉल्ट रूप से नहीं और व्यापक समय के लिए नहीं। man git-reflogतारीखों के बारे में देखें और भाग दें: "master@ellingone.week.ago" का अर्थ है "जहां मास्टर इस स्थानीय भंडार में एक सप्ताह पहले इंगित करता था" "। या पर चर्चा <refname>@{<date>}में man gitrevisions। और core.reflogExpireमें man git-config
पैट्रिक मेवज़ेक

2

प्रश्न का बहुत समाधान नहीं है, लेकिन मुझे लगा कि मैं उस दृष्टिकोण को ध्यान देने योग्य था जिसका उपयोग मैं लंबे समय से रहने वाली शाखा में करता हूं:

उसी समय मैं शाखा बनाता हूं, मैं उसी नाम के साथ एक टैग भी बनाता हूं, लेकिन -initप्रत्यय के साथ , उदाहरण के लिए feature-branchऔर feature-branch-init

(यह एक प्रकार का विचित्र है कि यह उत्तर देने के लिए इतना कठिन प्रश्न है!)


1
जब और जहाँ इसे बनाया गया था, तो किसी भी धारणा के बिना "शाखा" की अवधारणा को डिजाइन करने की सरासर मनमौजी मूर्खता को ध्यान में रखते हुए ... साथ ही अन्य सुझाए गए समाधानों की अपार जटिलताओं - इस तरह से बहुत स्मार्ट होने की कोशिश कर रहे लोगों द्वारा मुझे लगता है कि मैं आपके समाधान को पसंद करूंगा। केवल एक बार जब आप एक शाखा बनाते हैं, तो ऐसा करने के लिए REMEMBER की आवश्यकता पर एक बोझ पड़ता है - एक बात जो उपयोगकर्ताओं को बहुत बार हो रही है। इसके अलावा - मैंने कहीं पढ़ा कि 'टैग में' भारी 'होने का दंड है। फिर भी, मुझे लगता है कि मुझे लगता है कि मैं क्या करूँगा।
मोटी श्नोर

1

git log --graphविकल्प का उपयोग करने के लिए बस ब्रांचिंग पॉइंट को देखना आसान बनाने का एक आसान तरीका है --first-parent

उदाहरण के लिए, स्वीकार किए गए उत्तर से रेपो लें :

$ git log --all --oneline --decorate --graph

*   a9546a2 (HEAD -> master, origin/master, origin/HEAD) merge from topic back to master
|\  
| *   648ca35 (origin/topic) merging master onto topic
| |\  
| * | 132ee2a first commit on topic branch
* | | e7c863d commit on master after master was merged to topic
| |/  
|/|   
* | 37ad159 post-branch commit on master
|/  
* 6aafd7f second commit on master before branching
* 4112403 initial commit on master

अब जोड़ें --first-parent:

$ git log --all --oneline --decorate --graph --first-parent

* a9546a2 (HEAD -> master, origin/master, origin/HEAD) merge from topic back to master
| * 648ca35 (origin/topic) merging master onto topic
| * 132ee2a first commit on topic branch
* | e7c863d commit on master after master was merged to topic
* | 37ad159 post-branch commit on master
|/  
* 6aafd7f second commit on master before branching
* 4112403 initial commit on master

यह आसान बनाता है!

ध्यान दें कि रेपो में बहुत सी शाखाएँ हैं, जिनका उपयोग करने के बजाय आप जिन 2 शाखाओं की तुलना करना चाहते हैं, उन्हें निर्दिष्ट करना चाहते हैं --all:

$ git log --decorate --oneline --graph --first-parent master origin/topic

0

यह समस्या एक तरफ दोनों शाखाओं के बीच सबसे हालिया, एकल-प्रतिबद्ध कटौती और दूसरी ओर सबसे पहले सामान्य पूर्वज (संभवतः रेपो की प्रारंभिक प्रतिबद्धता) को खोजने के लिए प्रतीत होती है । यह मेरे अंतर्ज्ञान से मेल खाता है कि "ब्रांचिंग ऑफ" बिंदु क्या है।

यह ध्यान में रखते हुए, यह सामान्य गिट शेल कमांड के साथ गणना करने के लिए बिल्कुल आसान नहीं है, क्योंकि git rev-list- हमारा सबसे शक्तिशाली उपकरण - हमें उस पथ को प्रतिबंधित नहीं करने देता है जिसके द्वारा एक प्रतिबद्ध तक पहुंचा जाता है। निकटतम हमारे पास है git rev-list --boundary, जो हमें उन सभी कमिटों का एक सेट दे सकता है जो "हमारे रास्ते को अवरुद्ध करते हैं"। (ध्यान दें:git rev-list --ancestry-path दिलचस्प है, लेकिन मैं इसे यहां उपयोगी बनाने के लिए नहीं।)

यहाँ स्क्रिप्ट है: https://gist.github.com/abortz/d464c88923c520b79e3d । यह अपेक्षाकृत सरल है, लेकिन एक लूप के कारण यह एक जिस्ट को वारंट करने के लिए पर्याप्त जटिल है।

ध्यान दें कि यहां प्रस्तावित अधिकांश अन्य समाधान संभवत: एक सरल कारण के लिए सभी स्थितियों में काम नहीं कर सकते हैं: git rev-list --first-parent इतिहास को रैखिक बनाने में विश्वसनीय नहीं है क्योंकि आदेश देने के बाद भी विलय हो सकता है।

git rev-list --topo-orderदूसरी ओर, बहुत उपयोगी है - स्थलाकृतिक क्रम में चलने के लिए - लेकिन अंतर करना भंगुर है: किसी दिए गए ग्राफ़ के लिए कई संभावित स्थलाकृतिक क्रम हैं, इसलिए आप आदेशों की एक निश्चित स्थिरता पर निर्भर हैं। कहा कि, strongk7 का समाधान शायद ज्यादातर समय अच्छी तरह से काम करता है। हालांकि यह धीमी है कि मेरा रेपो के पूरे इतिहास को चलने के परिणामस्वरूप ... दो बार। :-)


0

निम्नलिखित कार्यान्वयन svn लॉग - स्टॉप-ऑन-कॉपी के बराबर हैं और इसका उपयोग शाखा मूल को खोजने के लिए भी किया जा सकता है।

पहुंच

  1. सभी शाखाओं के लिए सिर जाओ
  2. एक दूसरे की शाखा को लक्ष्य शाखा के लिए मर्जबेस इकट्ठा करें
  3. git.log और पुनरावृति
  4. पहले कमिट पर रुकें जो मर्जबेस लिस्ट में दिखाई देता है

जैसे सभी नदियाँ समुद्र तक चलती हैं, वैसे ही सभी शाखाएँ गुरु के पास चलती हैं और इसलिए हम असंबद्ध शाखाओं के बीच मर्ज-आधार पाते हैं। जैसा कि हम पूर्वजों के माध्यम से शाखा प्रमुख से वापस चलते हैं, हम पहले संभावित मर्ज बेस पर रोक सकते हैं क्योंकि सिद्धांत रूप में यह इस शाखा का मूल बिंदु होना चाहिए।

टिप्पणियाँ

  • मैंने इस दृष्टिकोण की कोशिश नहीं की है, जहां भाई-बहन और चचेरे भाई एक-दूसरे के बीच विलय हो गए।
  • मुझे पता है कि एक बेहतर समाधान होना चाहिए।

विवरण: https://stackoverflow.com/a/35353202/9950


-1

आप निम्नलिखित कमांड का उपयोग शाखा_ए में सबसे पुरानी प्रतिबद्धताओं को वापस करने के लिए कर सकते हैं, जो मास्टर से उपलब्ध नहीं है:

git rev-list branch_a ^master | tail -1

एक अतिरिक्त मानसिक स्वास्थ्य की जांच के साथ शायद कि इस बात का माता-पिता के लिए प्रतिबद्ध है वास्तव में गुरु से पहुंचा जा सकता ...


1
यह काम नहीं करता है। यदि ब्रांच_ए का एक बार मास्टर में विलय हो जाता है, और फिर जारी रहता है, तो उस मर्ज पर आने वाले को मास्टर का हिस्सा माना जाएगा, इसलिए वे ^ मास्टर में नहीं दिखाएंगे।
फेलिपक

-2

आप ब्रांच ए के रिफ्लॉग की जांच कर सकते हैं कि यह पता लगाने के लिए कि यह किसके द्वारा बनाया गया था, साथ ही साथ उस शाखा का पूरा इतिहास जिस पर इशारा किया गया था। रिफॉर्म्स में हैं .git/logs


2
मुझे नहीं लगता कि यह सामान्य रूप से काम करता है क्योंकि रिफ्लॉग को दूर किया जा सकता है। और मुझे नहीं लगता (!) रिफ्लक्स या तो धकेल दिए जाते हैं, इसलिए यह केवल एकल-रेपो स्थिति में काम करेगा।
गैरीओ

-2

मेरा मानना ​​है कि मुझे एक ऐसा रास्ता मिल गया है जो यहां वर्णित सभी कोने-मामलों से संबंधित है:

branch=branch_A
merge=$(git rev-list --min-parents=2 --grep="Merge.*$branch" --all | tail -1)
git merge-base $merge^1 $merge^2

चार्ल्स बेली काफी सही है कि पूर्वजों के आदेश के आधार पर समाधानों का केवल सीमित मूल्य है; दिन के अंत में आपको "यह वचन शाखा X से आया था" के कुछ प्रकार के रिकॉर्ड की आवश्यकता होती है, लेकिन ऐसा रिकॉर्ड पहले से मौजूद है; डिफ़ॉल्ट रूप से 'git मर्ज' एक प्रतिबद्ध संदेश जैसे "मर्ज शाखा 'Branch_A' का मास्टर में उपयोग करेगा", यह आपको बताता है कि दूसरे माता-पिता (प्रतिबद्ध ^ 2) के सभी कमिटियाँ 'Branch_A' से आए थे और पहले में विलय हो गए थे माता-पिता (प्रतिबद्ध ^ 1), जो 'मास्टर' है।

इस जानकारी से सशस्त्र आप 'ब्रांच_ए' का पहला मर्ज पा सकते हैं (जो कि 'ब्रांच_ ए' वास्तव में अस्तित्व में आया है), और मर्ज-बेस को खोजें, जो शाखा बिंदु होगा :)

मैंने मार्क बूथ और चार्ल्स बेली की रिपॉजिटरी के साथ कोशिश की है और समाधान काम करता है; यह कैसे नहीं हो सकता? एकमात्र तरीका यह काम नहीं करेगा यदि आपने मैन्युअल रूप से मर्ज के लिए डिफ़ॉल्ट प्रतिबद्ध संदेश को बदल दिया है ताकि शाखा जानकारी वास्तव में खो जाए।

उपयोगिता के लिए:

[alias]
    branch-point = !sh -c 'merge=$(git rev-list --min-parents=2 --grep="Merge.*$1" --all | tail -1) && git merge-base $merge^1 $merge^2'

तब आप ' git branch-point branch_A' कर सकते हैं ।

का आनंद लें ;)


4
माता-पिता के आदेश के बारे में परिकल्पना की तुलना में मर्ज संदेशों पर भरोसा करना अधिक नाजुक है। यह सिर्फ एक काल्पनिक स्थिति नहीं है; मैं अक्सर git merge -mयह कहने के लिए उपयोग करता हूं कि मैंने एक संभावित रूप से अल्पकालिक शाखा के नाम के बजाय क्या विलय किया है (उदाहरण के लिए "फ़ीचर xyz रिफ्लेक्टर में मर्ज को बदलता है")। मान लीजिए कि मैं -mअपने उदाहरण में मेरे साथ कम सहायक हो सकता हूं ? समस्या बस अपनी पूरी व्यापकता में घुलनशील नहीं है क्योंकि मैं एक या दो अस्थायी शाखाओं के साथ एक ही इतिहास बना सकता हूं और अंतर बताने का कोई तरीका नहीं है।
सीबी बेली

1
@CharlesBailey तब आपकी समस्या है। आपको उन पंक्तियों को प्रतिबद्ध संदेश से नहीं निकालना चाहिए, आपको मूल संदेश के नीचे शेष संदेश जोड़ना चाहिए । आजकल for git मर्ज ’स्वचालित रूप से आपके लिए एक एडिटर खोलता है जो आप चाहते हैं, और git के पुराने संस्करणों के लिए आप can git merge --edit’ कर सकते हैं। किसी भी तरह से, यदि आप वास्तव में चाहते हैं तो प्रत्येक प्रतिबद्ध के लिए "कमिटेड ऑन ब्रांच 'फू' को जोड़ने के लिए आप एक प्रतिबद्ध हुक का उपयोग कर सकते हैं। हालांकि, यह समाधान ज्यादातर लोगों के लिए काम करता है ।
फेलिपक

2
मेरे लिए काम नहीं किया। ब्रांच_ए को मास्टर से बाहर निकाल दिया गया था जिसमें पहले से ही बहुत सारे मर्ज थे। इस तर्क ने मुझे सटीक प्रतिबद्ध हैश नहीं दिया, जहां Branch_A बनाया गया था।
वेंकट कोटरा
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.