git - स्क्वाश मेरा आखिरी एक्स गिट का उपयोग करके एक साथ काम करता है




squash git-squash (20)

मैं अपने आखिरी एक्स को गिट का उपयोग करके एक प्रतिबद्धता में एक साथ कैसे कर सकता हूं?


⚠️ चेतावनी: "मेरा आखिरी एक्स काम करता है" संदिग्ध हो सकता है।

  (MASTER)  
Fleetwood Mac            Fritz
      ║                    ║
  Add Danny  Lindsey     Stevie       
    Kirwan  Buckingham    Nicks                                              
      ║         ╚═══╦══════╝     
Add Christine       ║          
   Perfect      Buckingham
      ║           Nicks            
    LA1974══════════╝                                    
      ║                  
      ║                  
    Bill <══════ YOU ARE EDITING HERE
  Clinton        (CHECKED OUT, CURRENT WORKING DIRECTORY)              

https://github.com/fleetwood-mac भंडार के इस संक्षिप्त संक्षेप में आपने बिल क्लिंटन को मूल ( MASTER ) फ्लीटवुड मैक प्रतिबद्धता में प्रतिबद्ध करने के लिए एक पुल अनुरोध खोला है।

आपने एक पुल अनुरोध खोला और गिटहब पर आप इसे देखते हैं:

चार काम करता है:

  • डैनी किरण जोड़ें
  • क्रिस्टीन परफेक्ट जोड़ें
  • LA1974
  • बील क्लिंटन

यह सोचकर कि कोई भी पूर्ण भंडार इतिहास को पढ़ने की परवाह नहीं करेगा। (वास्तव में एक भंडार है, उपरोक्त लिंक पर क्लिक करें!) आप इन प्रतिबद्धताओं को स्क्वैश करने का निर्णय लेते हैं। तो आप git reset --soft HEAD~4 && git commit । फिर आप अपने पीआर को साफ करने के लिए इसे git push --force पर git push --force करें।

और क्या होता है? आपने सिर्फ एक ही प्रतिबद्धता बनाई है जो फ़्रिट्ज़ से बिल क्लिंटन तक पहुंचती है। क्योंकि आप कल भूल जाते हैं कि आप इस परियोजना के बकिंघम निक्स संस्करण पर काम कर रहे थे। और git log जो आप गिटहब पर देखते हैं उससे मेल नहीं खाता है।

कहानी के मोरल

  1. अपनी इच्छित सटीक फ़ाइलों को ढूंढें, और git checkoutउन्हें
  2. इतिहास में रखना चाहते हैं कि सटीक पूर्व प्रतिबद्धता खोजें, और git reset --softवह
  3. git commitउस युद्ध को सीधे से लेकर तक तक बनाओ

1) कम शश हैश की पहचान करें

# git log --pretty=oneline --abbrev-commit
abcd1234 Update to Fix for issue B
cdababcd Fix issue B
deab3412 Fix issue A
....

यहाँ भी git log --oneline उपयोग शॉर्ट हैश प्राप्त करने के लिए भी किया जा सकता है।

2) यदि आप पिछले दो प्रतिबद्धताओं को स्क्वैश (विलय) करना चाहते हैं

# git rebase -i deab3412 

3) यह विलय के लिए एक nano संपादक खोलता है। और यह नीचे जैसा दिखता है

....
pick cdababcd Fix issue B
pick abcd1234 Update to Fix for issue B
....

4) शब्द को squash बदलें जो abcd1234 से पहले मौजूद है। नाम बदलने के बाद यह नीचे की तरह होना चाहिए।

....
pick cdababcd Fix issue B
squash abcd1234 Update to Fix for issue B
....

5) अब nano संपादक को सेव और बंद करें। ctrl + o दबाएं और सहेजने के लिए Enter दबाएं। और फिर संपादक से बाहर निकलने के लिए ctrl + x दबाएं।

6) फिर nano संपादक फिर से टिप्पणियों को अपडेट करने के लिए खुलता है, यदि आवश्यक हो तो इसे अपडेट करें।

7) अब यह सफलतापूर्वक squashed है, आप लॉग की जांच करके इसे सत्यापित कर सकते हैं।

# git log --pretty=oneline --abbrev-commit
1122abcd Fix issue B
deab3412 Fix issue A
....

8) अब रेपो करने के लिए धक्का। शाखा नाम से पहले + चिह्न जोड़ने के लिए नोट करें। इसका मतलब है मजबूर धक्का।

# git push origin +master

नोट: यह ubuntu खोल पर गिट का उपयोग करने पर आधारित है। यदि आप अलग-अलग ओएस ( Windows या Mac ) का उपयोग कर रहे हैं तो उपरोक्त आदेश संपादक को छोड़कर समान हैं। आपको अलग संपादक मिल सकते हैं।


आप git rebase या git merge --squash बिना इसे काफी आसानी से कर सकते हैं। इस उदाहरण में, हम पिछले 3 कामों को स्क्वैश करेंगे।

यदि आप स्क्रैच से नया प्रतिबद्ध संदेश लिखना चाहते हैं, तो यह पर्याप्त है:

git reset --soft HEAD~3 &&
git commit

यदि आप मौजूदा प्रतिबद्ध संदेशों के एक संयोजन के साथ नया प्रतिबद्ध संदेश संपादित करना प्रारंभ करना चाहते हैं (यानी एक पिक / स्क्वैश / स्क्वैश / ... / स्क्वैश git rebase -i निर्देश सूची आपको किस प्रकार शुरू करेगी), तो आपको निकालने की आवश्यकता है उन संदेशों को और उन्हें git commit लिए पास:

git reset --soft HEAD~3 && 
git commit --edit -m"$(git log --format=%B --reverse [email protected]{1})"

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


आप इसके लिए git merge --squash उपयोग कर सकते हैं, जो कि git rebase -i से थोड़ा अधिक सुरुचिपूर्ण है। मान लें कि आप मास्टर पर हैं और आप पिछले 12 में से एक को स्क्वैश करना चाहते हैं।

चेतावनी: सबसे पहले सुनिश्चित करें कि आप अपना कार्य-जांच करते हैं कि git status साफ है (चूंकि git reset --hard हार्ड चरणबद्ध और अस्थिर परिवर्तनों को फेंक देगा)

फिर:

# Reset the current branch to the commit just before the last 12:
git reset --hard HEAD~12

# [email protected]{1} is where the branch was just before the previous command.
# This command sets the state of the index to be as it would just
# after a merge from that commit:
git merge --squash [email protected]{1}

# Commit those squashed changes.  The commit message will be helpfully
# prepopulated with the commit messages of all the squashed commits:
git commit

git merge लिए प्रलेखन - --squash विकल्प का विस्तार अधिक विस्तार से करता है।

अपडेट करें: सरल git reset --soft HEAD~12 && git commit पर इस विधि का एकमात्र वास्तविक लाभ - क्रिस जॉनसन द्वारा सुझाए गए git reset --soft HEAD~12 && git commit यह है कि आपको स्वेशिंग के हर प्रतिबद्ध संदेश के साथ प्रतिबद्ध संदेश प्राप्त होता है।


इस तरह के वर्कफ़्लो से संबंधित प्रश्न के उत्तर के बारे में क्या?

  1. कई स्थानीय काम, मास्टर से कई विलय के साथ मिश्रित ,
  2. अंत में रिमोट के लिए एक धक्का,
  3. पीआर और समीक्षक द्वारा मास्टर करने के लिए विलय। (हां, पीआर के बाद डेवलपर को merge --squash करना आसान होगा, लेकिन टीम ने सोचा कि प्रक्रिया को धीमा कर देगा।)

मैंने इस पृष्ठ पर वर्कफ़्लो नहीं देखा है। (यह मेरी आंखें हो सकती है।) अगर मैं सही ढंग से rebase समझता हूं, तो कई विलयों को कई संघर्ष संकल्पों की आवश्यकता होगी। मैं इसके बारे में भी सोचना नहीं चाहता!

तो, यह हमारे लिए काम करता प्रतीत होता है।

  1. git pull master
  2. git checkout -b new-branch
  3. git checkout -b new-branch-temp
  4. बहुत स्थानीय रूप से संपादित करें और प्रतिबद्ध करें, नियमित रूप से मास्टर मर्ज करें
  5. git checkout new-branch
  6. git merge --squash new-branch-temp // चरण में सभी परिवर्तन डालता है
  7. git commit 'one message to rule them all'
  8. git push
  9. समीक्षाकर्ता पीआर करता है और मास्टर के लिए विलीन हो जाता है।

ऐसा करने का एक और तरीका यदि आपके पास काम करने का एक टन है तो स्क्वैश करना है git rebase -i <hashbeforeyouwanttosquash> जैसे प्रतिबद्धता के git rebase -i <hashbeforeyouwanttosquash>

यह आपके संपादक को सामान्य की तरह चुनने / स्क्वैश करने के लिए खोल देगा।

Https://git-scm.com/docs/git-rebase#_interactive_mode देखें


जब भी संभव हो तो मैं git reset से बचने की सलाह देता हूं - खासकर गिट-नौसिखियों के लिए। जब तक आपको वास्तव में कई कामों के आधार पर प्रक्रिया को स्वचालित करने की आवश्यकता नहीं है, वहां एक कम विदेशी तरीका है ...

  1. एक कार्यरत शाखा (यदि वे पहले से नहीं हैं) पर टू-स्क्वैश किए गए काम करते हैं - इसके लिए गिटक का उपयोग करें
  2. लक्ष्य शाखा देखें (उदाहरण के लिए 'मास्टर')
  3. git merge --squash (working branch name)
  4. git commit

स्क्वैश के आधार पर प्रतिबद्ध संदेश प्रीपेप्लेट किया जाएगा।


पिछले 10 स्क्वैश को 1 सिंगल प्रतिबद्धता में स्क्वैश करने के लिए:

git reset --soft HEAD~10 && git commit -m "squashed commit"

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

git push -f

मुझे लगता है कि एक और सामान्य समाधान 'एन' को निर्दिष्ट नहीं करना है, बल्कि शाखा / प्रतिबद्ध-आईडी जिसे आप शीर्ष पर स्क्वैश करना चाहते हैं। यह एक विशिष्ट प्रतिबद्धता के लिए प्रतिबद्ध होने की गणना करने से कम त्रुटि-प्रवण है-बस सीधे टैग निर्दिष्ट करें, या यदि आप वास्तव में गिनना चाहते हैं तो आप HEAD ~ N निर्दिष्ट कर सकते हैं।

मेरे वर्कफ़्लो में, मैं एक शाखा शुरू करता हूं, और उस शाखा पर मेरी पहली प्रतिबद्धता लक्ष्य को सारांशित करती है (यानी यह आमतौर पर मैं सार्वजनिक भंडार के लिए 'अंतिम' संदेश के रूप में धक्का दूंगा।) तो जब मैं करूँ, तो सब कुछ मैं git squash master को पहले संदेश पर वापस करना चाहता हूं और फिर मैं धक्का देने के लिए तैयार हूं।

मैं उपनाम का उपयोग करता हूं:

squash = !EDITOR="\"_() { sed -n 's/^pick //p' \"\\$1\"; sed -i .tmp '2,\\$s/^pick/f/' \"\\$1\"; }; _\"" git rebase -i

यह इतिहास को पहले ऐसा करने से पहले डंप कर देगा - इससे आपको कंसोल से पुरानी प्रतिबद्ध आईडी को पकड़कर पुनर्प्राप्त करने का मौका मिलता है यदि आप वापस करना चाहते हैं। (सोलारिस उपयोगकर्ता नोट करते हैं कि यह जीएनयू sed -i विकल्प का उपयोग करता है, मैक और लिनक्स उपयोगकर्ताओं को इसके साथ ठीक होना चाहिए।)


मुझे लगता है कि ऐसा करने का सबसे आसान तरीका मास्टर की एक नई शाखा बनाना और फीचर शाखा का विलय करना है।

git reset d43e15
git commit -am 'new commit name'

फिर आपके पास प्रतिबद्ध करने के लिए तैयार सभी बदलाव हैं।


यदि आप प्रत्येक प्रतिबद्धता को एक ही प्रतिबद्धता में squish करना चाहते हैं (उदाहरण के लिए पहली बार सार्वजनिक रूप से एक परियोजना जारी करते समय), कोशिश करें:

git checkout --orphan <new-branch>
git commit

यदि आप TortoiseGit का उपयोग करते हैं, तो आप फ़ंक्शन Combine to one commit :

  1. ओपन TortoiseGit संदर्भ मेनू
  2. Show Log चयन करें
  3. लॉग दृश्य में प्रासंगिक कामों को चिह्नित करें
  4. संदर्भ मेनू से Combine to one commit चयन करें

यह फ़ंक्शन स्वचालित रूप से सभी आवश्यक सिंगल गिट चरणों को निष्पादित करता है। दुर्भाग्य से केवल विंडोज के लिए उपलब्ध है।


यह सुपर-डुप्लिक क्लेडी है, लेकिन एक तरह से शांत तरीके से, इसलिए मैं इसे अंगूठी में फेंक दूंगा:

GIT_EDITOR='f() { if [ "$(basename $1)" = "git-rebase-todo" ]; then sed -i "2,\$s/pick/squash/" $1; else vim $1; fi }; f' git rebase -i foo~5 foo

अनुवाद: गिट के लिए एक नया "संपादक" प्रदान करें, यदि फ़ाइल नाम संपादित किया गया है तो git-rebase-todo (इंटरैक्टिव रीबेज प्रॉम्प्ट) पहले "पिक" को "स्क्वैश" में बदल देता है, और अन्यथा vim spawns - ताकि जब आपको स्क्वैश किए गए प्रतिबद्ध संदेश को संपादित करने के लिए कहा जाता है, तो आप विम प्राप्त करते हैं। (और जाहिर है कि मैं शाखा फू पर आखिरी पांच कामों को खत्म कर रहा था, लेकिन आप इसे बदल सकते हैं हालांकि आपको पसंद है।)

मैं संभवतः मार्क लॉन्गैयर का सुझाव देता हूं , हालांकि।


वास्तव में क्या सुविधाजनक हो सकता है:
d43e15 कहें, उस शीर्ष पर हैश जिसे आप शीर्ष पर स्क्वैश करना चाहते हैं उसे d43e15

अब उपयोग करें

git checkout master
git checkout -b feature_branch_squashed
git merge --squash feature_branch

सबसे पहले मुझे अपनी फीचर शाखा और वर्तमान मास्टर शाखा के बीच काम करने की संख्या पता है

git checkout master
git rev-list master.. --count

फिर, मैं अपनी फीचर शाखा के आधार पर एक और शाखा बनाता हूं, my-feature शाखा को बिना छूटे रखता my-feature

आखिरकार, मैं दौड़ता हूं

git checkout my-feature
git checkout -b my-rebased-feature
git checkout master
git checkout my-rebased-feature
git rebase master
git rebase head^x -i
// fixup/pick/rewrite
git push origin my-rebased-feature -f // force, if my-rebased-feature was ever pushed, otherwise no need for -f flag
// make a PR with clean history, delete both my-feature and my-rebased-feature after merge

उम्मीद है कि यह मदद करता है, धन्यवाद।


सवाल में यह अस्पष्ट हो सकता है कि "आखिरी" क्या है।

उदाहरण के लिए git log --graph निम्नलिखित (सरलीकृत) आउटपुट करता है:

* commit H0
|
* merge
|\
| * commit B0
| |
| * commit B1
| | 
* | commit H1
| |
* | commit H2
|/
|

फिर आखिरी बार एच 0, विलय, बी 0 होता है। उन्हें स्क्वैश करने के लिए आपको अपनी विलय वाली शाखा को एच 1 प्रतिबद्ध करने पर पुनर्भुगतान करना होगा।

समस्या यह है कि एच 0 में एच 1 और एच 2 होता है (और आम तौर पर मर्ज करने और ब्रांचिंग के बाद अधिक होता है) जबकि बी 0 नहीं होता है। तो आपको कम से कम H0, मर्ज, एच 1, एच 2, बी 0 से परिवर्तनों को प्रबंधित करना होगा।

रीबेस का उपयोग करना संभव है लेकिन अलग-अलग तरीकों से अन्य लोगों ने उत्तर दिया:

rebase -i HEAD~2

यह आपको पसंद विकल्प दिखाएगा (जैसा कि अन्य उत्तरों में उल्लिखित है):

pick B1
pick B0
pick H0

H0 को चुनने के बजाय स्क्वैश रखें:

pick B1
pick B0
s H0

सहेजने और निकास के बाद एच 1 के बाद बदले में लागू होगा। इसका मतलब यह है कि यह आपको फिर से संघर्षों को हल करने के लिए कहेंगे (जहां सिर पहले एच 1 होगा और फिर लागू होने के साथ ही जमा हो जाएगा)।

रिबेस समाप्त होने के बाद आप squashed H0 और B0 के लिए संदेश चुन सकते हैं:

* commit squashed H0 and B0
|
* commit B1
| 
* commit H1
|
* commit H2
|

पीएस यदि आप बस बीओ को कुछ रीसेट करते हैं: (उदाहरण के लिए, reset --mixed का उपयोग करके इसे यहां विस्तार से समझाया गया है https://.com/a/18690845/2405850 ):

git reset --mixed hash_of_commit_B0
git add .
git commit -m 'some commit message'

तो आप H0, H1, H2 के B0 परिवर्तनों में स्क्वैश करते हैं (ब्रांचिंग के बाद और मर्ज करने से पहले परिवर्तनों के लिए पूरी तरह से हार जाते हैं।


इस आसान ब्लॉग पोस्ट के लिए धन्यवाद मैंने पाया कि आप पिछले 3 कामों को स्क्वैश करने के लिए इस कमांड का उपयोग कर सकते हैं:

git rebase -i HEAD~3

यह आसान है क्योंकि यह तब भी काम करता है जब आप स्थानीय शाखा में होते हैं, जिसमें कोई ट्रैकिंग जानकारी / रिमोट रेपो नहीं होती है।

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

इंटरैक्टिव रीबेस संपादक का उपयोग करना:

इंटरैक्टिव रीबेस संपादक पिछले तीन काम करता है। यह बाधा HEAD~3 द्वारा निर्धारित की गई थी जब कमांड git rebase -i HEAD~3 चला रहा था।

सबसे हालिया प्रतिबद्धता, HEAD , पहले पंक्ति 1 पर प्रदर्शित होती है। # शुरू होने वाली रेखाएं टिप्पणियां / दस्तावेज़ीकरण हैं।

प्रदर्शित दस्तावेज बहुत स्पष्ट है। किसी दिए गए लाइन पर आप कमांड को अपनी पसंद के कमांड से बदल सकते हैं।

मैं कमांड fixup का उपयोग करना पसंद करता हूं क्योंकि यह ऊपर की रेखा पर प्रतिबद्धता में बदलाव के परिवर्तन को "squashes" करता है और प्रतिबद्धता संदेश को त्याग देता है।

चूंकि लाइन 1 पर प्रतिबद्धता HEAD , ज्यादातर मामलों में आप इसे pick रूप में छोड़ देंगे। आप squash या fixup उपयोग नहीं कर सकते क्योंकि प्रतिबद्धता को स्क्वैश करने के लिए कोई अन्य प्रतिबद्धता नहीं है।


git rebase -i <after-this-commit> और मैन्युअल में वर्णित अनुसार "स्क्वैश" या "फ़िक्सअप" के साथ दूसरे पर "पिक" को प्रतिस्थापित करें और बाद में करें

इस उदाहरण में, <after-this-commit> या तो SHA1 हैश या वर्तमान शाखा के HEAD से संबंधित स्थान है, जिससे रीबेज कमांड के लिए विश्लेषण किया जाता है। उदाहरण के लिए, यदि उपयोगकर्ता अतीत में मौजूदा हेड से 5 काम देखना चाहता है तो कमांड git rebase -i HEAD~5


क्रिस जॉनसन के जवाब के आधार पर,

बैश से वैश्विक "स्क्वैश" उपनाम जोड़ें: (या विंडोज़ पर गिट बैश)

git config --global alias.squash '!f(){ git reset --soft HEAD~${1} && git commit --edit -m"$(git log --format=%B --reverse [email protected]{1})"; };f'

... या विंडोज 'कमांड प्रॉम्प्ट का उपयोग कर:

git config --global alias.squash "!f(){ git reset --soft HEAD~${1} && git commit --edit -m\"$(git log --format=%B --reverse [email protected]{1})\"; };f"


आपके ~/.gitconfig अब यह उपनाम होना चाहिए:

[alias]
    squash = "!f(){ git reset --soft HEAD~${1} && git commit --edit -m\"$(git log --format=%B --reverse [email protected]{1})\"; };f"


उपयोग:

git squash N

... जो स्वचालित रूप से अंतिम N प्रतिबद्धताओं को एक साथ जोड़ता है, समावेशी।

नोट: परिणामी प्रतिबद्ध संदेश क्रमशः सभी squashed प्रतिबद्धताओं का संयोजन है। यदि आप इससे नाखुश हैं, तो आप इसे मैन्युअल रूप से संशोधित करने के लिए git commit --amend कर सकते हैं। (या, अपने स्वाद से मेल खाने के लिए उपनाम संपादित करें।)


मास्टर शाखा में स्विच करें और सुनिश्चित करें कि आप अद्यतित हैं:

sh git checkout master && git fetch && git pull

अपनी फीचर शाखा को स्थानीय शाखा में स्थानीय रूप से मर्ज करें:

sh git merge feature_branch

मूल मास्टर शाखा को मूल स्थिति में रीसेट करें:

sh git reset origin/master

अब आपके सभी परिवर्तनों को अस्थिर रूप में बदला जाता है। आप उन्हें एक या अधिक कामों में मंच और प्रतिबद्ध कर सकते हैं।

sh git add . --all git commit







git-squash