अगर मैं पहले से ही रिबास शुरू कर दूं तो मैं दो कमिट्स को एक में कैसे मर्ज कर सकता हूं?


1157

मैं 1 में 2 कमिट्स को मर्ज करने की कोशिश कर रहा हूं, इसलिए मैंने "रेडिट के साथ स्क्वैशिंग कमिट्स" को तैयार किया

मैं भागा

git rebase --interactive HEAD~2

परिणामी संपादक में, मैं बदल pickजाता हूं squashऔर फिर बचत-छोड़ देता हूं , लेकिन त्रुटि के साथ रिबास विफल हो जाता है

एक पिछली प्रतिबद्धता के बिना 'स्क्वैश' नहीं कर सकता

अब जब मेरा कार्य वृक्ष इस अवस्था में पहुँच गया है, मुझे ठीक होने में परेशानी हो रही है।

आदेश git rebase --interactive HEAD~2विफल रहता है:

इंटरएक्टिव रिबास पहले ही शुरू हो गया

और के git rebase --continueसाथ विफल रहता है

एक पिछली प्रतिबद्धता के बिना 'स्क्वैश' नहीं कर सकता


22
मैंने यह भी मारा। मेरी गलती इस तथ्य के कारण हुई थी कि गिट रिबेस-आई, गिट लॉग के विपरीत क्रम में आने वाले कमिट को सूचीबद्ध करता है; नवीनतम प्रतिबद्धता तल पर है!
lmsurprenant


जवाबों:


1732

सारांश

त्रुटि संदेश

एक पिछली प्रतिबद्धता के बिना 'स्क्वैश' नहीं कर सकता

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

जोड़

पहले जहां आप के साथ शुरू किया था वहां वापस जाएं

$ git rebase --abort

कहो तुम्हारा इतिहास है

$ git log --pretty=oneline
a931ac7c808e2471b22b5bd20f0cad046b1c5d0d c
b76d157d507e819d7511132bdb5a80dd421d854f b
df239176e1a2ffac927d8b496ea00d5488481db5 a

यही है, एक पहले प्रतिबद्ध था, फिर बी, और अंत में सी। C करने के बाद हम b और c को एक साथ स्क्वैश करने का निर्णय लेते हैं:

(नोट: अधिकांश प्लेटफार्मों पर डिफ़ॉल्ट रूप से git log, अपने आउटपुट को पेजर में चला रहा lessहै। पेजर को छोड़ने और अपने कमांड प्रॉम्प्ट पर वापस जाने के लिए, qकुंजी दबाएं।)

रनिंग git rebase --interactive HEAD~2आपको एक संपादक देता है

pick b76d157 b
pick a931ac7 c

# Rebase df23917..a931ac7 onto df23917
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

(ध्यान दें कि यह टूडू सूची आउटपुट के साथ तुलना में रिवर्स ऑर्डर में है git log।)

ख के बदलने pickके लिए squashत्रुटि आपने देखा में परिणाम होगा, लेकिन अगर इसके बजाय आप ख में ग स्क्वैश (नए में प्रतिबद्ध पुराने या "ऊपर की ओर कुचलने") के लिए कार्यसूची बदलकर

pick   b76d157 b
squash a931ac7 c

और अपने संपादक को बचाने-छोड़ने, आपको एक और संपादक मिलेगा जिसकी सामग्री है

# This is a combination of 2 commits.
# The first commit's message is:

b

# This is the 2nd commit message:

c

जब आप सहेजते हैं और छोड़ते हैं, तो संपादित फ़ाइल की सामग्री नई संयुक्त प्रतिबद्ध का संदेश बन जाती है:

$ git log --pretty=oneline
18fd73d3ce748f2a58d1b566c03dd9dafe0b6b4f b and c
df239176e1a2ffac927d8b496ea00d5488481db5 a

इतिहास को फिर से लिखने के बारे में ध्यान दें

इंटरएक्टिव रिबेस इतिहास को फिर से लिखता है। पुराने इतिहास वाले रिमोट को धकेलने का प्रयास विफल हो जाएगा क्योंकि यह तेज़-फ़ॉरवर्ड नहीं है।

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

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

रिबासिंग (या पुनर्लेखन का कोई अन्य रूप) एक शाखा है जिस पर दूसरों का काम आधारित है, यह एक बुरा विचार है: इसके किसी भी व्यक्ति को अपने इतिहास को मैन्युअल रूप से ठीक करने के लिए मजबूर किया जाता है। यह खंड बताता है कि डाउनस्ट्रीम के दृष्टिकोण से कैसे ठीक किया जाए। हालांकि, वास्तविक सुधार, पहली जगह में अपस्ट्रीम को फिर से बनाने से बचना होगा। ...


अगर मैं एक कमिट स्क्वैश करने के लिए रिबेट का उपयोग करता हूं, तो एक नया "संयुक्त" कमेट बनाया जाता है जिसमें दो बदलाव होते हैं लेकिन हैश अलग होता है। मूल कमिट git द्वारा भी संरक्षित हैं?
फेबसेनेट

@fabsenet हां और नहीं। मूल कमिट्स अभी भी सुलभ हैं लेकिन संभवत: किसी भी रेफ (आपके इतिहास के विवरण के आधार पर) से अब उपलब्ध नहीं हैं। गैर-मान्यता प्राप्त आवागमन अंततः कचरा संग्रहण प्रक्रिया के माध्यम से समाप्त हो जाते हैं।
ग्रेग बेकन

मैं बस के आसपास खेल रहा था ... मैंने किया था git log hashoftheoldcommitऔर यह काम किया था, लेकिन मैं git log --graphइन सभी अगम्य
हिटों के

यह स्क्वैश धक्का देने से पहले कमिट को व्यवस्थित करने के लिए एक अच्छा उपकरण है, लेकिन अगर मैं एक कमिट को पुश करता हूं, तो मैं इसे स्क्वैश नहीं कर सकता? git का कहना है: सफलतापूर्वक विद्रोह किया और अद्यतन किया गया HEAD।
सेरियो

दूसरे उदाहरण पर संपादक को नहीं मिल रहा है, गिट बैश, कुछ प्रक्रिया में मुक्त हो गया लगता है। क्या करें?

411

यदि कई कमिट हैं, तो आप git rebase -iदो कमिट्स को एक में स्क्वैश करने के लिए उपयोग कर सकते हैं ।

यदि केवल दो कमिट हैं जिन्हें आप मर्ज करना चाहते हैं, और वे "सबसे हाल के दो" हैं, तो निम्नलिखित कमांड का उपयोग दो कमिट्स को एक में मिलाने के लिए किया जा सकता है:

git reset --soft "HEAD^"
git commit --amend

6
रिबास की तुलना में नकारात्मक पक्ष क्या है? मुझे एक का उपयोग करने के लिए बहुत आसान लगता है।
गुइलियुमोरी

17
आप अनियंत्रित क्रम में शामिल नहीं हो सकते हैं - केवल अंतिम दो काम करता है
dr0i

50
@ dr0i आप जितने चाहें उतने कमिट कर सकते हैं, जब तक कि वे अंतिम एक्स कमिट हैं, और बीच में कहीं नहीं हैं। बस चलाएं git reset --soft HEAD~10, जहां 10 वे कमिट हैं जो आप मर्ज करना चाहते हैं।
fregante

2
इसका उपयोग तब किया जा सकता है जब आपके पास एक दूरस्थ मूल सेट नहीं होता है, और आपके पास केवल दो आवागमन होते हैं।
आत्जाजा

8
तुम भी एक विशिष्ट करने के लिए रीसेट कर सकते हैं के लिए प्रतिबद्ध है, तो आप कितने वहाँ से कर रहे हैं गिनती नहीं चाहता HEADका उपयोग करके git reset --soft 47b5c5...जहां 47b5c5...प्रतिबद्ध के SHA1 आईडी है।
डेगू

112

Rebase: आपको इसकी आवश्यकता नहीं होगी:

सबसे लगातार परिदृश्य के लिए एक सरल तरीका है।

ज्यादातर मामलों में:

वास्तव में अगर आप चाहते हैं तो बस एक ही बार में कई हाल के कॉम्बिनेशन को मिला दें, लेकिन ज़रूरत नहीं है drop, rewordऔर अन्य रीबेस काम।

आप बस कर सकते हैं:

git reset --soft "HEAD~n"
  • मान लिया जाये कि ~nकरने के लिए प्रतिबद्ध की संख्या है धीरे अन-प्रतिबद्ध (यानी ~1, ~2, ...)

फिर, प्रतिबद्ध संदेश को संशोधित करने के लिए निम्न आदेश का उपयोग करें।

git commit --amend

जो की एक लंबी रेंज squashऔर एक के रूप में बहुत अधिक है pick

और यह n कमिट्स के लिए काम करता है, लेकिन ऊपर दिए गए उत्तर के अनुसार केवल दो कमिट नहीं।


3
यह अच्छा है यदि आप कुछ अतिरिक्त सफाई करना चाहते हैं, इसके अलावा बस कमिट्स को स्क्वैश करना चाहते हैं, जैसे कि बीच में 1 कमिट निकालना या कोड की एक लाइन को बदलना।
स्टाइल जूल

1
मान लिया जाये कि ~nधीरे अन-प्रतिबद्ध (यानी के लिए प्रतिबद्ध की संख्या है ~1, ~2, ...)
रे

1
क्या होगा अगर मैं nपिछले कमिट्स को मर्ज नहीं करना चाहता , लेकिन nबीच में करता है? क्या मैं ऐसा आसानी से कर सकता हूं?
चुमाकॉफ

1
फिर git rebase -iआपको squashकाम करने की क्या जरूरत है । @chumakoff
pambda

3
तो nसबसे हाल ही में एक में शामिल होने के लिए , पहले का उपयोग करें git reset --soft @~m, जहांm = n - 1
Rajukasz Rajchel

55

पहले आपको यह देखना चाहिए कि आपके पास कितने कमिट हैं:

git log

दो स्थिति हैं:

एक यह है कि केवल दो आवागमन हैं:

उदाहरण के लिए:

commit A
commit B

(इस मामले में, आप करने के लिए git rebase का उपयोग नहीं कर सकते हैं) आपको निम्नलिखित करने की आवश्यकता है।

$ git reset --soft HEAD^1

$ git commit --amend

एक और यह है कि दो से अधिक आवागमन हैं; आप कमिट C और D को मर्ज करना चाहते हैं।

उदाहरण के लिए:

commit A
commit B
commit C
commit D

(इस शर्त के तहत, आप गिट रीबेस का उपयोग कर सकते हैं)

git rebase -i B

और करने के लिए "स्क्वैश" का उपयोग करें। बाकी थिन्स बहुत आसान है। यदि आप अभी भी नहीं जानते हैं, तो कृपया http://zerodie.github.io/blog/2012/01/19/git-rebase-i/ पढ़ें


रीसेट --soft और कमिट --amend एकमात्र तरीका है जो काम करता है यदि आपके पास पहले से ही प्रगति में एक रिबेस है (और इस कमिट के लिए 'स्क्वैश' के बजाय 'एडिट' चुना)। +1
Jacek Lach

1
पहले और केवल दो को मिलाने से एक रिपॉजिटरी में प्रवेश होता है, बिलकुल मेरे किनारे का मामला :-)
क्रिस हुआंग-लीवर

1
कृपया जोड़ दें कि git push -f origin masterयह neccesary हो सकता है।
ऋषभ अग्रहरी

33

मान लें कि आप अपनी विषय शाखा में थे। यदि आप अंतिम 2 मर्जों को एक में मिलाना चाहते हैं और एक नायक की तरह दिखते हैं, तो पिछले दो कमिट करने से ठीक पहले कमिट को शाखा दें।

git checkout -b temp_branch HEAD^2

फिर स्क्वाश इस नई शाखा में दूसरी शाखा करें:

git merge branch_with_two_commits --squash

यह बदलाव लाएगा लेकिन उन्हें प्रतिबद्ध नहीं करेगा। तो बस उन्हें प्रतिबद्ध और आप कर रहे हैं।

git commit -m "my message"

अब आप इस नई विषय शाखा को अपनी मुख्य शाखा में वापस मर्ज कर सकते हैं।


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

इसके लिए धन्यवाद! यह है कि मैं कैसे कर सकता हूँ कि मैं अपने सिर में स्क्वैश कैसे मारता हूँ!
मार्जन वेनेमा

आश्चर्यजनक उत्तर, विकल्प की तुलना में बहुत सरल

जाहिर है, यह जवाब मामले के लिए उपयुक्त नहीं है जब aऔर cएक साथ विलय और रखने के लिए आवश्यक है कि bके रूप में यह है।
तल्हा अशरफ

2
हाल के संस्करणों में कुछ बदल गया है? जब मैं git checkout -b combine-last-two-commits "HEAD^2"git संस्करण 2.17 में पहली कमांड ( ) का प्रयास करता हूं, तो मुझे एक त्रुटि मिलती है:fatal: 'HEAD^2' is not a commit and a branch 'combine-last-two-commits' cannot be created from it
mhucka

23

आप के साथ छूट रद्द कर सकते हैं

git rebase --abort

और जब आप संवादात्मक रिबेस कमांड फिर से 'स्क्वैश' चलाते हैं; लिस्ट में कमिट कमिटमेंट कमिटेड होना चाहिए


16

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

commit ac72a4308ba70cc42aace47509a5e
Author: <me@me.com>
Date:   Tue Jun 11 10:23:07 2013 +0500

    Added algorithms for Cosine-similarity

commit 77df2a40e53136c7a2d58fd847372
Author: <me@me.com>
Date:   Tue Jun 11 13:02:14 2013 -0700

    Set stage for similar objects

commit 249cf9392da197573a17c8426c282
Author: Ralph <ralph@me.com>
Date:   Thu Jun 13 16:44:12 2013 -0700

    Fixed a bug in space world automation

यदि मैं एक में दो कमिट्स को मर्ज करना चाहता हूं, तो सबसे पहले मैं उपयोग करता हूं:

git reset --mixed 249cf9392da197573a17c8426c282

"249cf9392da197573a17c8426c282" तीसरा संस्करण था, आपके विलय से पहले आपका आधार संस्करण भी है, उसके बाद, मैं एक नई प्रतिबद्धता बनाता हूं:

git add .
git commit -m 'some commit message'

यह सब है, आशा हर किसी के लिए एक और तरीका है।

FYI करें, से git reset --help:

 --mixed
     Resets the index but not the working tree (i.e., the changed files are
     preserved but not marked for commit) and reports what has not been
     updated. This is the default action.

मैंने '--mixed' के लिए डॉक्स नहीं पढ़े हैं, लेकिन मुझे यकीन है कि अन्य लोगों ने पोस्ट पढ़ी थी और एक ही बात सोचा था: --mixed का उपयोग करने का क्या फायदा है? मैन पेज के स्निपेट को शामिल करने के लिए अपनी पोस्ट में सुधार कर सकते हैं।
बजे

@funroll मुझे नहीं पता था - यह जवाब लिखने से पहले मैंने बहुत कुछ बताया, अपने अनुभव के अनुसार, मिश्रित ऑपरेशन निर्दिष्ट संस्करण को बदल देगा , जिसे मैं रिपॉजिटरी HEAD संस्करण के रूप में तर्क के रूप में पास करता हूं, और उस संस्करण के बाद कुछ भी नहीं खो सकता है, इसलिए हम अभी भी उन परिवर्तनों को संभाल सकते हैं।
विन्ससट्लिंग

14

$ git rebase --abort

इस कोड को किसी भी समय चलाएं यदि आप गिट रिबास को पूर्ववत करना चाहते हैं

$ git rebase -i HEAD~2

पिछले दो कमियों को फिर से लागू करने के लिए। उपरोक्त कमांड एक कोड एडिटर खोलेगा

  • [ नवीनतम प्रतिबद्धता सबसे नीचे होगी ]। स्क्वैश के लिए अंतिम प्रतिबद्ध बदलें। चूंकि स्क्वैश पिछली प्रतिबद्धताओं के साथ पिघल जाएगा।
  • फिर एस्क कुंजी दबाएं और सहेजें और बंद करने के लिए टाइप करें

के बाद: wq आप सक्रिय रिबेस मोड में होंगे

नोट : यदि आपको कोई चेतावनी / त्रुटि संदेश मिलता है, तो आपको एक और संपादक मिलेगा, अगर कोई त्रुटि है या चेतावनी एक अन्य संपादक नहीं दिखाएगा,$ git rebase --abortतो आप रनिंगको रद्द कर सकते हैं यदि आप एक त्रुटि देखते हैं या चेतावनी देते हैं तो बस चलाते रहें$ git rebase --continue

आपको अपना 2 प्रतिबद्ध संदेश दिखाई देगा। एक चुनें या अपना खुद का संदेश लिखें, बचाएं और छोड़ें [: ​​wq]

नोट 2: यदि आप रीबेस कमांड चलाते हैं, तो आपको अपने परिवर्तनों को रिमोट रेपो में धकेलने के लिए मजबूर करना पड़ सकता है

$ git push -f

$ git push -f origin master


1
नोट 2: git push -f origin/masterअन्य उत्तर क्या गायब हैं। +1
ऋषभ अग्रहरी

2

चूंकि मैं git cherry-pickहर चीज के बारे में इस्तेमाल करता हूं, इसलिए मेरे लिए यहां तक ​​ऐसा करना स्वाभाविक है।

यह देखते हुए कि मैंने branchXजाँच की है और इसके सिरे पर दो कमिट हैं, जिनमें से मैं उनकी सामग्री को मिलाकर एक कमिट बनाना चाहता हूँ, मैं यह करता हूँ:

git checkout HEAD^ // Checkout the privious commit
git cherry-pick --no-commit branchX // Cherry pick the content of the second commit
git commit --amend // Create a new commit with their combined content

अगर मैं भी अपडेट करना चाहता branchXहूं (और मुझे लगता है कि यह इस विधि का सबसे नीचे का हिस्सा है) मुझे भी यह करना होगा:

git checkout branchX
git reset --hard <the_new_commit>

1

यदि आपकी मास्टर ब्रांच git logकुछ इस प्रकार है:

commit ac72a4308ba70cc42aace47509a5e
Author: <me@me.com>
Date:   Tue Jun 11 10:23:07 2013 +0500

    Added algorithms for Cosine-similarity

commit 77df2a40e53136c7a2d58fd847372
Author: <me@me.com>
Date:   Tue Jun 11 13:02:14 2013 -0700

    Set stage for similar objects

commit 249cf9392da197573a17c8426c282
Author: Ralph <ralph@me.com>
Date:   Thu Jun 13 16:44:12 2013 -0700

    Fixed a bug in space world automation

और आप केवल दो आसान चरणों का पालन करते हुए शीर्ष दो मर्ज करना चाहते हैं:

  1. पहली बार सुरक्षित पक्ष पर चेकआउट करने के लिए दूसरी अंतिम प्रतिबद्ध एक अलग शाखा में। आप शाखा को कुछ भी नाम दे सकते हैं।git checkout 77df2a40e53136c7a2d58fd847372 -b merged-commits
  2. अब, बस चेरी लेने पिछले से अपने परिवर्तनों के रूप में इस नई शाखा में प्रतिबद्ध: git cherry-pick -n -x ac72a4308ba70cc42aace47509a5e। (यदि कोई विवाद हो तो हल करें)
  3. तो अब, आपकी अंतिम प्रतिबद्धताओं में आपके दूसरे अंतिम प्रतिबद्ध में परिवर्तन हैं। लेकिन आपको अभी भी प्रतिबद्ध होना है, इसलिए पहले बदलावों को जोड़ें जो आप सिर्फ चेरी-उठाया और फिर निष्पादित करें git commit --amend

बस। यदि आप चाहें तो आप इस मर्ज किए गए संस्करण को शाखा "मर्ज-कमिट" में धकेल सकते हैं।

इसके अलावा, अब आप अपनी मास्टर शाखा में बैक-टू-बैक दो कमिट्स को छोड़ सकते हैं। बस अपनी मास्टर शाखा को अपडेट करें:

git checkout master
git reset --hard origin/master (CAUTION: This command will remove any local changes to your master branch)
git pull

0

यदि आप दो सबसे हाल के कॉम्बीनेशन को संयोजित करना चाहते हैं और बस पुराने कमिट के संदेश का उपयोग करना चाहते हैं, तो आप उपयोग करके प्रक्रिया को स्वचालित कर सकते हैं expect

मै मानता हूँ:

  • आप vi को अपने संपादक के रूप में उपयोग कर रहे हैं
  • आपके कमिट प्रत्येक एक-पंक्ति हैं

मैंने परीक्षण किया git version 2.14.3 (Apple Git-98)


#!/usr/bin/env expect
spawn git rebase -i HEAD~2

# change the second "pick" to "squash"
# down, delete word, insert 's' (for squash), Escape, save and quit
send "jdwis \033:wq\r"

expect "# This is a"

# skip past first commit message (assumed to be one line), delete rest of file
# down 4, delete remaining lines, save and quit
send "4jdG\r:wq\r"

interact

यह स्पष्ट नहीं है कि आपकी स्क्रिप्ट क्या करती है।
buhtz

@buhtz मैंने कुछ और टिप्पणियां जोड़ीं। मुझे पता है अगर आप अभी भी इसे भ्रामक पाते हैं, और यदि हां, तो कौन सा हिस्सा।
इरवामन

यह अभी भी स्पष्ट नहीं है कि आपका स्क्रिप क्या करता है। इसके अलावा expectअवांछनीय है।
buhtz

@buhtz कौन सा हिस्सा अस्पष्ट है? मैंने एक पृष्ठ के लिए अधिक प्रलेखन के लिए एक लिंक प्रदान किया expect
इरवामन

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