सभी git को एक में स्क्वैश कैसे करें?


479

आप अपनी पूरी रिपॉजिटरी को पहले कमिट में कैसे स्क्वैश करते हैं?

मैं पहले कमिट को रिजेक्ट कर सकता हूं, लेकिन यह मुझे 2 कमिट्स के साथ छोड़ देगा। क्या पहले एक से पहले प्रतिबद्ध को संदर्भित करने का कोई तरीका है?


8
"पहले वाले से पहले का कमिटमेंट"?
innaM

31
@innaM - यह आदिकालीन प्रतिबद्ध है जो गिट को प्राप्त करता है । (होप्स ह्यूमर इंटरवेब के माध्यम से पर्याप्त रूप से गुजरता है)।
ripper234

11
इस प्रश्न के बाद आने वालों के लिए , अधिक आधुनिक उत्तर का उपयोग करना सुनिश्चित करें ।
दरोगाओं

1
संबंधित है, लेकिन नहीं एक नकली ( --rootवास्तव में कुचलने के लिए सबसे अच्छा समाधान नहीं है सब करता है तो वहाँ स्क्वैश के लिए उनमें से एक बहुत कुछ कर रहे हैं): एक Git भंडार के पहले दो करता कम्बाइन?

2
Imo: यह @MrTux: stackoverflow.com/questions/30236694/… से सर्वश्रेष्ठ है ।
J0hnG4lt

जवाबों:


130

शायद सबसे आसान तरीका काम की वर्तमान स्थिति के साथ एक नया भंडार बनाना है। यदि आप उन सभी प्रतिबद्ध संदेशों को रखना चाहते हैं जो आप पहले कर सकते हैं git log > original.logऔर फिर संपादित करें कि नए भंडार में अपने प्रारंभिक प्रतिबद्ध संदेश के लिए:

rm -rf .git
git init
git add .
git commit

या

git log > original.log
# edit original.log as desired
rm -rf .git
git init
git add .
git commit -F original.log

62
लेकिन आप इस विधि से शाखाएँ
खोले रहे हैं

150
यह उत्तर दिए जाने के बाद से गित विकसित हुई है। नहीं, एक सरल और बेहतर तरीका है git rebase -i --root:। देखें: stackoverflow.com/a/9254257/109618
डेविड जे।

5
यह कुछ मामलों के लिए काम कर सकता है, लेकिन यह अनिवार्य रूप से सवाल का जवाब नहीं है। इस नुस्खा के साथ, आप अपने सभी विन्यास और अन्य सभी शाखाओं को भी ढीला करते हैं।
19

3
यह एक भयानक समाधान है जो अनावश्यक रूप से विनाशकारी है। कृपया इसका उपयोग न करें।
डैनियल कामिल कोजार

5
तोड़फोड़ भी होगा। -1
क्रुम

693

1.6.2 git के रूप में , आप उपयोग कर सकते हैं git rebase --root -i

पहले को छोड़कर प्रत्येक कमिट के लिए, में परिवर्तन pickकरें squash


49
कृपया मूल प्रश्न का उत्तर देने वाला पूर्ण, कार्यशील उदाहरण जोड़ें।
जेक

29
काश मैं अपने पूरे भंडार को उड़ाने से पहले इसे पढ़ लेता, जैसे स्वीकृत उत्तर कहता है: /
माइक चेम्बरलेन

38
यह उत्तर ठीक है , लेकिन अगर आप संवादात्मक रूप से अधिक से अधिक रिबासिंग कर रहे हैं, तो कहते हैं, 20 कमिट करता है, इंटरएक्टिव रिबास संभवत: बहुत धीमा और अस्पष्ट होगा। आप शायद सैकड़ों या हजारों कमिट्स स्क्वैश करने की कोशिश कर रहे हैं। मैं एक नरम या मिश्रित रीसेट के साथ रूट कमिट में जाऊंगा, फिर उस मामले में फिर से मिलूंगा।

20
@Pred squashसभी आवागमन के लिए उपयोग न करें । बहुत पहले एक होने की जरूरत है pick
गीर्ट

14
यदि आपके पास बहुत से काम हैं, तो मैन्युअल रूप से 'स्क्वैश' को 'स्क्वैश' में बदलना मुश्किल है। का प्रयोग करें :% s / पिक / स्क्वैश / छ VIM कमांड लाइन में यह तेजी से करने के लिए।
ईलास

314

अपडेट करें

मैंने एक उपनाम बनाया है git squash-all
उदाहरण उपयोग : git squash-all "a brand new start"

[alias]
  squash-all = "!f(){ git reset $(git commit-tree HEAD^{tree} -m \"${1:-A new start}\");};f"

कैविएट : एक टिप्पणी प्रदान करना याद रखें, अन्यथा डिफ़ॉल्ट प्रतिबद्ध संदेश "एक नई शुरुआत" का उपयोग किया जाएगा।

या आप निम्नलिखित आदेश के साथ उपनाम बना सकते हैं:

git config --global alias.squash-all '!f(){ git reset $(git commit-tree HEAD^{tree} -m "${1:-A new start}");};f'

एक लाइन

git reset $(git commit-tree HEAD^{tree} -m "A new start")

नोट : यहाँ " A new start" केवल एक उदाहरण है, अपनी भाषा का उपयोग करने के लिए स्वतंत्र महसूस करें।

टी एल; डॉ

स्क्वैश करने की आवश्यकता नहीं है, git commit-treeएक अनाथ प्रतिबद्ध बनाने के लिए उपयोग करें और इसके साथ जाएं।

समझाना

  1. के माध्यम से एक ही प्रतिबद्ध बनाएँ git commit-tree

    क्या git commit-tree HEAD^{tree} -m "A new start"है:

    प्रदान की गई ट्री ऑब्जेक्ट के आधार पर एक नई कमिट ऑब्जेक्ट बनाता है और स्टडआउट पर नई कमिट ऑब्जेक्ट आईडी का उत्सर्जन करता है। लॉग संदेश मानक इनपुट से पढ़ा जाता है, जब तक -m या -F विकल्प नहीं दिए जाते।

    अभिव्यक्ति का HEAD^{tree}अर्थ है पेड़ की वस्तु HEAD, जो आपकी वर्तमान शाखा की नोक से संबंधित है। देख ट्री-वस्तुओं और प्रतिबद्ध-वस्तुओं

  2. नई शाखा के लिए वर्तमान शाखा रीसेट करें

    फिर git resetबस नई बनाई गई वस्तु के लिए वर्तमान शाखा को रीसेट करें।

इस तरह, कार्यक्षेत्र में कुछ भी छुआ नहीं है, और न ही रिबास / स्क्वैश की आवश्यकता है, जो इसे वास्तव में तेज़ बनाता है। और आवश्यक समय भंडार आकार या इतिहास की गहराई के लिए अप्रासंगिक है।

विविधता: एक परियोजना टेम्पलेट से नई रेपो

यह टेम्प्लेट / आर्कटाइप / बीज / कंकाल के रूप में एक अन्य रिपॉजिटरी का उपयोग करके एक नई परियोजना में "प्रारंभिक प्रतिबद्ध" बनाने के लिए उपयोगी है। उदाहरण के लिए:

cd my-new-project
git init
git fetch --depth=1 -n https://github.com/toolbear/panda.git
git reset --hard $(git commit-tree FETCH_HEAD^{tree} -m "initial commit")

यह टेम्प्लेट रेपो को रिमोट ( originया अन्यथा) के रूप में जोड़ने से बचता है और टेम्प्लेट रेपो के इतिहास को आपकी प्रारंभिक प्रतिबद्ध में ढह जाता है।


6
जीआईटी रिविजन सिंटैक्स (HEAD ^ {ट्री}) सिंटैक्स की व्याख्या यहाँ की गई है जब कोई और सोच रहा था: jk.gs/gitrevisions.html
कॉलिन बोवरन

1
क्या यह स्थानीय और दूरस्थ रिपॉजिटरी, या उनमें से केवल एक को रीसेट करता है?
एलेक्लेरसन

4
@aleclarson, यह केवल स्थानीय रिपॉजिटरी में वर्तमान शाखा को रीसेट करता है, git push -fप्रचार के लिए उपयोग करता है।
रीनस

2
प्रोजेक्ट टेम्पलेट रिपॉजिटरी से एक नई परियोजना शुरू करने के तरीके की तलाश के दौरान मुझे यह उत्तर मिला, जिसमें शामिल नहीं था git clone। यदि आप इसमें जोड़ते --hardहैं git resetऔर स्विच HEADकरते FETCH_HEADहैं तो git commit-treeआप टेम्पलेट रेपो लाने के बाद एक प्रारंभिक प्रतिबद्धता बना सकते हैं। मैंने इसका प्रदर्शन करते हुए अंत में एक अनुभाग के साथ उत्तर संपादित किया है।
टूलबार 19

4
आप उस "कैविएट" से छुटकारा पा सकते हैं, लेकिन सिर्फ उपयोग कर रहे हैं${1?Please enter a message}
इलियट कैमरन

172

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

git rebase --interactive --root

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

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

वैकल्पिक समाधान # 1: अनाथ शाखाएं

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

git checkout --orphan new-master master
git commit -m "Enter commit message for your new initial commit"

# Overwrite the old master branch reference with the new one
git branch -M new-master master

प्रलेखन:

वैकल्पिक समाधान # 2: सॉफ्ट रीसेट

एक अन्य कुशल उपाय यह है कि रूट कमिट में मिश्रित या सॉफ्ट रिसेट का उपयोग करें <root>:

git branch beforeReset

git reset --soft <root>
git commit --amend

# Verify that the new amended root is no different
# from the previous branch state
git diff beforeReset

प्रलेखन:


22
वैकल्पिक समाधान # 1: अनाथ शाखाएं - चट्टानें!
थॉमस

8
वैकल्पिक समाधान # 1 FTW। बस जोड़ने के लिए, यदि आप अपने परिवर्तनों को रिमोट पर धकेलना चाहते हैं, तो करें git push origin master --force
एडी वर्ब्रुगन

1
नहीं भूलना चाहिएgit push --force
NecipAllef

कोड पर एक अनाथ शाखा मत करो (यानी वैकल्पिक समाधान # 1 ऊपर मत करो) यदि आप एक खुले गितुब पुल अनुरोध पर जोर देने वाले हैं! Github आपके PR को बंद कर देगा क्योंकि वर्तमान सिर संग्रहीत सिर sha का वंशज नहीं है
एंड्रयू मैके

वैकल्पिक समाधान # 1 भी मर्ज संघर्ष से बचा जाता है जो
स्क्वैशिंग के

52
echo "message" | git commit-tree HEAD^{tree}

यह HEAD के पेड़ के साथ एक अनाथ प्रतिबद्ध बना देगा, और इसे स्टडआउट पर नाम (SHA-1) आउटपुट देता है। फिर बस अपनी शाखा को वहां रीसेट करें।

git reset SHA-1

27
git reset $(git commit-tree HEAD^{tree} -m "commit message")इससे आसानी होगी।
रेनस

4
^ यह! - एक उत्तर होना चाहिए। पूरी तरह से यकीन नहीं है कि यह लेखक का इरादा था, लेकिन मेरा था (एक प्रतिबद्ध के साथ एक प्राचीन रेपो की जरूरत थी, और यह काम पूरा हो गया)।
चेस्टरबर

@ryenus, आपके समाधान ने वही किया जो मैं देख रहा था। यदि आप उत्तर के रूप में अपनी टिप्पणी जोड़ते हैं, तो मैं इसे स्वीकार करूंगा।
tldr

2
इसका कारण यह है कि मैंने स्वयं उप-संस्करण का सुझाव नहीं दिया है, यह है कि यह विंडोज में cmd.exe पर काम नहीं करेगा।
कुसमा

विंडोज संकेतों में, आपको अंतिम पैरामीटर उद्धृत करना पड़ सकता है: echo "message" | git commit-tree "HEAD^{tree}"
बर्नार्ड

41

यहां बताया गया है कि मैंने ऐसा करना समाप्त कर दिया, बस किसी और के लिए काम करने की स्थिति में:

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

लॉग इन करके शुरू करें

git log --oneline

पहली प्रतिबद्ध करने के लिए स्क्रॉल करें, SHA की प्रतिलिपि बनाएँ

git reset --soft <#sha#>

<#sha#>W / SHA को लॉग से कॉपी किया गया बदलें

git status

सुनिश्चित करें कि सब कुछ हरा है, अन्यथा चलाएं git add -A

git commit --amend

वर्तमान पहले बदलाव के लिए सभी वर्तमान परिवर्तनों को संशोधित करें

अब बल को इस शाखा को धक्का दें और यह वहां क्या है अधिलेखित कर देगा।


1
बहुत बढ़िया विकल्प! वास्तव में सरल।
बजकर

1
यह शानदार से अधिक है! धन्यवाद!
मैट कोमर्निकि

1
ध्यान दें कि यह वास्तव में इतिहास को छोड़ देता है। आप इसे अनाथ करेंगे, लेकिन यह अभी भी है।
ब्रैड

बहुत उपयोगी उत्तर ... लेकिन आपको इस बात की जानकारी होनी चाहिए कि संशोधन आदेश के बाद आप अपने विशेष सिंटैक्स के साथ अपने आप को विम एडिटर में पाएंगे। ESC, ENTER,: x आपका मित्र है।
एरिक कुएस्टर

बहुत बढ़िया विकल्प!
डेनिविकारियो

36

मैंने ग्राफ्ट का उपयोग करने के बारे में कुछ पढ़ा है लेकिन कभी भी इसकी जांच नहीं की।

वैसे भी, आप पिछले 2 उन लोगों के साथ मैन्युअल रूप से स्क्वैश कर सकते हैं:

git reset HEAD~1
git add -A
git commit --amend

4
यह वास्तव में वह उत्तर है जिसकी मुझे तलाश थी, काश यह स्वीकार किया जाता!
जय

यह एक ऐसा अद्भुत उत्तर है
मास्टर योदा

36

सबसे आसान तरीका update-refवर्तमान शाखा को हटाने के लिए 'प्लंबिंग' कमांड का उपयोग करना है ।

आप git branch -Dवर्तमान शाखा को हटाने से रोकने के लिए सुरक्षा वाल्व के रूप में उपयोग नहीं कर सकते ।

यह आपको 'प्रारंभिक प्रतिबद्ध' स्थिति में वापस लाता है जहां आप एक नए सिरे से आरंभ कर सकते हैं।

git update-ref -d refs/heads/master
git commit -m "New initial commit"

16

सबसे पहले, अपने सभी कमिट्स का उपयोग करके एक ही कमिट में स्क्वैश करें git rebase --interactive। अब आप स्क्वाश करने के लिए दो कमिट के साथ बचे हैं। ऐसा करने के लिए, किसी भी पढ़ें


15

6 शब्दों की एक पंक्ति में

git checkout --orphan new_root_branch  &&  git commit

@AlexanderMills, आप के git help checkoutबारे में पढ़ना चाहिए--orphan
kyb

क्या आप इसके लिए डॉक्स से लिंक कर सकते हैं, ताकि जो कोई भी इसे पढ़ता है, उसे मैन्युअल रूप से इसके लिए खोज न करनी पड़े?
अलेक्जेंडर मिल्स

1
आसान। यहाँ यह हैgit help checkout --orphan
kyb

8

एक बैकअप बनाएं

git branch backup

निर्दिष्ट प्रतिबद्ध करने के लिए रीसेट करें

git reset --soft <#root>

फिर सभी फ़ाइलों को जोड़कर देखें

git add .

संदेश को अद्यतन किए बिना प्रतिबद्ध

git commit --amend --no-edit

नई शाखा के साथ धराशायी करना रेपो को धक्का देता है

git push -f

क्या यह पिछले प्रतिबद्ध संदेशों को संरक्षित करेगा?
not2qubit

1
@ not2qubit नहीं, यह पिछले प्रतिबद्ध संदेशों को संरक्षित नहीं करेगा, # 1 के बजाय, # 2, # 3 प्रतिबद्ध करें, आपको उन सभी परिवर्तनों का एक ही कमिट # 1 में पैक करके मिल जाएगा। कमेटी # 1 <root>आपके द्वारा वापस रीसेट किए जाने वाली प्रतिबद्धता होगी । git commit --amend --no-editवर्तमान कमिट में वे सभी बदलाव करेंगे जो <root>कमिट किए गए संदेश को संपादित करने की आवश्यकता के बिना है।
डेविड मॉर्टन

5

ग्राफ्ट का उपयोग करके स्क्वैश करना

एक फ़ाइल जोड़ें .git/info/grafts, वहाँ आप अपने मूल बनना चाहते हैं प्रतिबद्ध हैश डाल दिया

git log अब उस कमिट से शुरू करेंगे

इसे 'असली' चलाने के लिए git filter-branch


1

यह उत्तर ऊपर के एक जोड़े पर सुधार करता है (कृपया उन्हें वोट दें), यह मानते हुए कि एक कमिट (नो-पेरेंट्स नो-हिस्ट्री) बनाने के अलावा, आप उस कमिट के सभी डेटा को भी बनाए रखना चाहते हैं:

  • लेखक (नाम और ईमेल)
  • लेखक की तारीख
  • कमेटी (नाम और ईमेल)
  • प्रतिबद्ध तारीख
  • लॉग संदेश भेजें

बेशक नई / एकल कमिट का कमिटमेंट-SHA बदल जाएगा, क्योंकि यह एक नया (गैर-) इतिहास का प्रतिनिधित्व करता है, जो पेरेंटलेस / रूट-कमिट बन जाता है।

इसे पढ़कर किया जा सकता है git log लिए कुछ चरों को और सेटgit commit-tree । यह मानते हुए कि आप masterएक नई शाखा से एक सिंगल कमिट बनाना चाहते हैं one-commit, ऊपर दिए गए कमिटमेंट को बरकरार रखते हुए:

git checkout -b one-commit master ## create new branch to reset
git reset --hard \
$(eval "$(git log master -n1 --format='\
COMMIT_MESSAGE="%B" \
GIT_AUTHOR_NAME="%an" \
GIT_AUTHOR_EMAIL="%ae" \
GIT_AUTHOR_DATE="%ad" \
GIT_COMMITTER_NAME="%cn" \
GIT_COMMITTER_EMAIL="%ce" \
GIT_COMMITTER_DATE="%cd"')" 'git commit-tree master^{tree} <<COMMITMESSAGE
$COMMIT_MESSAGE
COMMITMESSAGE
')

1

ऐसा करने के लिए, आप पहले प्रतिबद्ध हैशटैग के लिए आपको स्थानीय गिट रिपॉजिटरी रीसेट कर सकते हैं, इसलिए उस प्रतिबद्ध के बाद आपके सभी परिवर्तन अस्थिर होंगे, फिर आप --amend विकल्प के साथ प्रतिबद्ध कर सकते हैं।

git reset your-first-commit-hashtag
git add .
git commit --amend

और फिर जरूरत पड़ने पर पहले कमिट को एडिट करें और फाइल को सेव करें।


1

मेरे लिए यह इस तरह से काम करता है: मेरे पास कुल 4 कमिट थे, और इंटरेक्टिव रिबेस का इस्तेमाल किया:

git rebase -i HEAD~3

बहुत पहली प्रतिबद्ध बनी हुई है और मैंने 3 नवीनतम कमिट किए।

यदि आप संपादक में फंस गए हैं, जो आगे दिखाई देता है, तो आपको smth दिखाई देता है:

pick fda59df commit 1
pick x536897 commit 2
pick c01a668 commit 3

आपको पहले कमिटमेंट लेना होगा और दूसरों को इस पर स्क्वैश करना होगा। आपके पास क्या होना चाहिए:

pick fda59df commit 1
squash x536897 commit 2
squash c01a668 commit 3

इसके लिए 'इन्सर्ट' और 'एडिट' मोड को बदलने के लिए INSERT कुंजी का उपयोग करें।

संपादक के उपयोग को सहेजने और बाहर निकलने के लिए :wq। यदि आपका कर्सर उन प्रतिबद्ध लाइनों के बीच है या कहीं और ईएससी को धक्का देता है और फिर से प्रयास करें।

नतीजतन मेरे पास दो कमिट थे: बहुत पहले जो बने रहे और दूसरा मैसेज "यह 3 कमिट्स का संयोजन है।"

विवरण के लिए यहां देखें: https://makandracards.com/makandra/527-squash-several-git-commits-into-a-single-commit


0

मैं आमतौर पर इसे इस तरह से करता हूं:

  • सुनिश्चित करें कि सब कुछ प्रतिबद्ध है, और कुछ गलत हो जाने पर, या फिर बैकअप के रूप में एक अलग शाखा बनाने के मामले में नवीनतम प्रतिबद्ध आईडी लिखें

  • भागो git reset --soft `git rev-list --max-parents=0 --abbrev-commit HEAD`पहले करने के लिए अपने सिर को रीसेट प्रतिबद्ध है, लेकिन अपने सूचकांक अपरिवर्तित रखने के लिए। पहले प्रतिबद्ध के बाद से सभी परिवर्तन अब प्रतिबद्ध होने के लिए तैयार दिखाई देंगे।

  • git commit --amend -m "initial commit"पहले कमिट में अपनी कमिटमेंट में संशोधन करने के लिए रन करें और कमिट मैसेज को बदलें, या यदि आप मौजूदा कमिट मैसेज को रखना चाहते हैं, तो आप चला सकते हैंgit commit --amend --no-edit

  • भागो git push -fबल पर अपने परिवर्तन धक्का

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