Vivasoft-logo

৭.৬ গিট টুলস – ইতিহাস পুনর্লিখন

ইতিহাস পুনর্লিখন

অনেক সময়, গিটের সাথে কাজ করার সময়, আপনি আপনার লোকাল কমিট ইতিহাস সংশোধন করতে চাইতে পারেন। গিট সম্পর্কে দুর্দান্ত জিনিসগুলির মধ্যে একটি হল এটি আপনাকে শেষ সম্ভাব্য মুহূর্তে সিদ্ধান্ত নিতে দেয়। স্টেজিং এরিয়ার সাথে কমিট করার আগে আপনি ঠিক করতে পারেন কোন ফাইলগুলি কোন কমিটে যাবে, আপনি সিদ্ধান্ত নিতে পারেন যে আপনি গিট স্ট্যাশ দিয়ে এখনও কিছুতে কাজ করতে চাননি, এবং আপনি ইতিমধ্যে ঘটে যাওয়া কমিটগুলি পুনরায় লিখতে পারেন যাতে সেগুলিকে অন্যভাবে ঘটেছে বলে মনে হয়। এতে কমিটের ক্রম পরিবর্তন করা, বার্তা পরিবর্তন করা বা একটি কমিট-এ ফাইলগুলি পরিবর্তন করা, একত্রে স্কোয়াশ করা বা কমিটগুলিকে আলাদা করা, অথবা অন্যদের সাথে আপনার কাজ ভাগ করার আগে সম্পূর্ণরূপে কমিটগুলি সরিয়ে ফেলা অন্তর্ভুক্ত থাকতে পারে। 

এই বিভাগে, আপনি এই কাজগুলি কীভাবে সম্পাদন করবেন তা দেখতে পাবেন যাতে আপনি অন্যদের সাথে ভাগ করার আগে আপনার কমিট ইতিহাসটিকে আপনার পছন্দ মতো দেখাতে পারেন।

নোট

যতক্ষণ না আপনি এতে খুশি না হন ততক্ষণ আপনার কাজকে পুশ দেবেন না 

 

গিটের মূল নিয়মগুলির মধ্যে একটি হল, যেহেতু আপনার ক্লোনের মধ্যে অনেক কাজ লোকাল, তাই লোকালভাবে আপনার ইতিহাস পুনর্লিখন করার জন্য আপনার প্রচুর স্বাধীনতা রয়েছে। যাইহোক, একবার আপনি আপনার কাজকে পুশ দিয়ে দিলে, এটি সম্পূর্ণ ভিন্ন গল্প, এবং আপনার পুশ দেওয়া কাজটিকে চূড়ান্ত হিসাবে বিবেচনা করা উচিত যদি না আপনার কাছে এটি পরিবর্তন করার উপযুক্ত কারণ থাকে। সংক্ষেপে, আপনার কাজকে পুশ দেওয়া এড়ানো উচিত যতক্ষণ না আপনি এতে খুশি হন এবং বাকি বিশ্বের সাথে এটি ভাগ করতে প্রস্তুত হন।

শেষ কমিট পরিবর্তন 

 

আপনার সাম্প্রতিক কমিট পরিবর্তন করা সম্ভবত ইতিহাসের সবচেয়ে সাধারণ পুনর্লিখন যা আপনি করবেন। আপনি প্রায়শই আপনার শেষ কমিট-এ দুটি মৌলিক জিনিস করতে চান: কেবল কমিট বার্তাটি পরিবর্তন করুন, বা ফাইলগুলি যোগ, অপসারণ এবং সংশোধন করে কমিট-এর প্রকৃত বিষয়বস্তু পরিবর্তন করুন। 

 

আপনি যদি আপনার শেষ কমিট বার্তাটি পরিবর্তন করতে চান তবে এটি সহযে করতে পারেন:

				
					$ git commit --amend
				
			

উপরের কমান্ডটি পূর্ববর্তী কমিট বার্তাটিকে একটি ইডিটর সেশনে লোড করে, যেখানে আপনি বার্তাটিকে পরিবর্তন করতে পারেন, সেই পরিবর্তনগুলি সংরক্ষণ এবং প্রস্থান করতে পারেন। আপনি যখন ইডিটরটিকে সংরক্ষণ এবং বন্ধ করেন, তখন ইডিটর সেই আপডেট করা কমিট বার্তা সহ একটি নতুন কমিট লিখে এবং এটিকে আপনার নতুন শেষ কমিট-এ পরিণত করে।

অন্যদিকে, আপনি যদি আপনার শেষ কমিটের প্রকৃত বিষয়বস্তু পরিবর্তন করতে চান, প্রক্রিয়াটি মূলত একইভাবে কাজ করে — প্রথমে আপনি যে পরিবর্তনগুলি ভুলে গেছেন বলে মনে করেন, সেই পরিবর্তনগুলি করুন, এবং পরবর্তী git commit –amend আপনার নতুন, উন্নত কমিট দিয়ে শেষ কমিট প্রতিস্থাপন করে দিবে।

আপনাকে এই কৌশলটির সাথে সতর্কতা অবলম্বন করতে হবে কারণ সংশোধন করা পদ্ধতিটি কমিটের SHA-1 পরিবর্তন করে। এটি একটি খুব ছোট রিবেসের মতো যদি আপনি ইতিমধ্যে এটিকে পুশ দিয়ে থাকেন তবে আপনার শেষ কমিটটি সংশোধন করবেন না।

নোট

একটি সংশোধিত কমিটে একটি সংশোধিত কমিট বার্তার প্রয়োজন হতে পারে  ( বা নাও হতে পারে )

 

আপনি যখন একটি কমিট সংশোধন করেন, তখন আপনার কাছে কমিট বার্তা এবং কমিটের বিষয়বস্তু উভয়ই পরিবর্তন করার সুযোগ থাকে। আপনি যদি কমিটের বিষয়বস্তুকে যথেষ্ট পরিমাণে সংশোধন করেন, তাহলে আপনার অবশ্যই সেই সংশোধিত বিষয়বস্তুকে প্রতিফলিত করার জন্য কমিট বার্তাটি আপডেট করা উচিত।

 

অন্যদিকে, যদি আপনার সংশোধনগুলি উপযুক্তভাবে তুচ্ছ হয়  ( যেমন: একটি নির্বোধ টাইপো ঠিক করা বা আপনি স্টেজে ভুলে গেছেন এমন একটি ফাইল যোগ করা ) পূর্বের কমিট বার্তাটি ঠিক রেখে, আপনি কেবল পরিবর্তনগুলি করতে পারেন, সেগুলি স্টেজ করতে পারেন এবং নিম্নলিখিত কমান্ড দিয়ে সম্পূর্ণরূপে অপ্রয়োজনীয় এডিটর সেশন এড়িয়ে চলুন:

 

$ git commit –amend –no-edit

একাধিক কমিট বার্তা পরিবর্তন করা

আপনার ইতিহাসে আরও পিছনে থাকা একটি কমিট পরিবর্তন করতে, আপনাকে অবশ্যই আরও জটিল টুলসগুলোয় যেতে হবে। গিট-এর কোনো পরিবর্তন-ইতিহাস টুল নেই, তবে তারা যেই HEAD এ মূলত বেইজ করা ছিল সেখানে রিবেজ করতে –আপনি গিট রিবেইজ টুল ব্যবহার করতে পারেন। ইন্টারেক্টিভ রিবেস টুলের সাহায্যে, আপনি প্রতিটি কমিট-এর পরে বার্তা পরিবর্তন করতে, ফাইল যোগ করতে বা যা খুশি করতে চান তা বন্ধ করতে পারেন। আপনি git rebase  কমান্ড-এ -i অপশন যোগ করে ইন্টারেক্টিভভাবে রিবেস চালাতে পারেন। কমান্ডটিতে কোন কমিটকে রিবেস করতে হবে তার মাধ্যমে আপনাকে অবশ্যই নির্দেশ করতে হবে যে আপনি কতটা পিছিয়ে কমিটগুলি পুনরায় লিখতে চান।

উদাহরণস্বরূপ, আপনি যদি শেষ তিনটি কমিট বার্তা পরিবর্তন করতে চান, বা সেই গ্রুপের যেকোনও কমিট বার্তা পরিবর্তন করতে চান, তাহলে আপনি git rebase -i-এর জন্য একটি আর্গুমেন্ট হিসাবে আপনি যে শেষ কমিট সম্পাদনা করতে চান তার প্যারেন্ট সরবরাহ করেন, যা HEAD~2^ বা HEAD~3~3 মনে রাখা সহজ হতে পারে কারণ আপনি শেষ তিনটি কমিট এডিট করার চেষ্টা করছেন, কিন্তু মনে রাখবেন যে আপনি আসলে চারটি কমিট আগে নির্ধারণ করছেন, শেষ কমিটের প্যারেন্ট যা আপনি সম্পাদনা করতে চান:

				
					$ git rebase -i HEAD~3
				
			

আবার মনে রাখবেন যে এটি একটি রিবেসিং কমান্ড — HEAD~3..HEAD পরিসরের প্রতিটি কমিট একটি পরিবর্তিত বার্তা সহ লিখা হবে এবং এর সমস্ত উত্তরসূরিকে পুনরায় লেখা হবে৷ এমন কোনো কমিট অন্তর্ভুক্ত করবেন না যা আপনি ইতিমধ্যেই একটি কেন্দ্রীয় সার্ভারে পুশ করে দিয়েছেন — এটি করার মাধ্যমে, আপনি একই পরিবর্তনের পরিবর্তিত সংস্করণ প্রদান করে অন্যান্য ডেভেলপারদের বিভ্রান্ত করবেন।

 

এই কমান্ডটি আপনাকে আপনার টেক্সট এডিটরে কমিটের একটি তালিকা দেয়, যা দেখতে এরকম হতে পারে:

				
					pick f7f3f6d Change my name a bit
pick 310154e Update README formatting and add blame
pick a5f4a0d Add cat-file

# Rebase 710f0f8..a5f4a0d onto 710f0f8
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
				
			

সাধারণ log কমান্ড ব্যবহার করে আপনি যেই রেজাল্ট দেখতে পারেন , এই কমান্ড চালিয়ে আপনি দেখবেন , রেজাল্ট এর লিস্টটি log কমান্ড-এর লিস্ট এর বিপরীত আকারে প্রদর্শিত হচ্ছে। আপনি যদি একটি log চালান, আপনি এরকম কিছু দেখতে পারবেন:

				
					$ git log --pretty=format:"%h %s" HEAD~3..HEAD
a5f4a0d Add cat-file
310154e Update README formatting and add blame
f7f3f6d Change my name a bit
				
			

বিপরীত ক্রম লক্ষ্য করুন৷ ইন্টারেক্টিভ রিবেস আপনাকে একটি স্ক্রিপ্ট দেয় যা এটি রান হতে চলেছে। এটি কমান্ড লাইনে  ( HEAD~3 ) আপনার নির্দিষ্ট করা কমিট থেকে শুরু হবে এবং এই প্রতিটি কমিটে প্রবর্তিত পরিবর্তনগুলি উপরে থেকে নীচে পর্যন্ত পুনরায় চালাবে। এটি নতুনটির পরিবর্তে সবচেয়ে পুরানোটিকে শীর্ষে তালিকাভুক্ত করে, কারণ এটিই প্রথমটি পুনঃপ্রদর্শন করবে৷ 

আপনাকে স্ক্রিপ্টটি সম্পাদনা করতে হবে যাতে এটি আপনি সম্পাদনা করতে চান এমন কমিটে থামে। এটি করার জন্য, আপনি স্ক্রিপ্টটি বন্ধ করতে চান এমন প্রতিটি কমিটের জন্য “pick” শব্দটিকে “edit” শব্দে পরিবর্তন করুন। উদাহরণস্বরূপ, শুধুমাত্র তৃতীয় কমিট বার্তাটি সংশোধন করতে, আপনি ফাইলটিকে এইরকম দেখতে পরিবর্তন করুন:

				
					edit f7f3f6d Change my name a bit
pick 310154e Update README formatting and add blame
pick a5f4a0d Add cat-file
				
			

আপনি যখন সম্পাদকটি সংরক্ষণ করেন এবং প্রস্থান করেন, গিট আপনাকে সেই তালিকার শেষ কমিটে  ফিরিয়ে দেয় এবং নিম্নলিখিত বার্তা সহ আপনাকে কমান্ড লাইনে রেখে দেয়:

				
					$ git rebase -i HEAD~3
Stopped at f7f3f6d... Change my name a bit
You can amend the commit now, with

       git commit --amend

Once you're satisfied with your changes, run

       git rebase --continue
				
			

এই নির্দেশাবলী আপনাকে ঠিক কি করতে হবে তা বলে।  টাইপ করুন:

				
					$ git commit --amend
				
			

এই কমান্ডটি অন্য দুটি কমিট স্বয়ংক্রিয়ভাবে প্রয়োগ করবে এবং তারপরে আপনার কাজ সম্পন্ন হবে। আপনি যদি আরও লাইনে সম্পাদনা করতে pick পরিবর্তন করেন, আপনি সম্পাদনার জন্য পরিবর্তন করা প্রতিটি কমিটর জন্য এই পদক্ষেপগুলি পুনরাবৃত্তি করতে পারেন। প্রতিবার, গিট থামবে, আপনাকে কমিট সংশোধন করতে দেবে এবং আপনার কাজ শেষ হয়ে গেলে, চালিয়ে যাবে।

কমিট পুনর্বিন্যাস করা

আপনি সম্পূর্ণরূপে কমিট পুনর্বিন্যাস বা অপসারণ করতে ইন্টারেক্টিভ রিবেস ব্যবহার করতে পারেন। আপনি যদি “Add cat-file” – কমিটটি সরাতে চান এবং অন্য দুটি কমিট যে ক্রমানুসারে চালু করা হয়েছে তা পরিবর্তন করতে চান, আপনি রিবেস স্ক্রিপ্ট

এটি থেকে —

				
					pick f7f3f6d Change my name a bit
pick 310154e Update README formatting and add blame
pick a5f4a0d Add cat-file
				
			

এরূপে পরিবর্তন করতে পারেন–

				
					pick 310154e Update README formatting and add blame
pick f7f3f6d Change my name a bit
				
			

আপনি যখন এডিটর-এ সেভ করেন এবং প্রস্থান করেন, তখন গিট আপনার ব্রাঞ্চকে এই কমিটগুলির প্যারেন্টের কাছে আবার গুটিয়ে নিয়ে যায়, প্রথমে 310154e এবং তারপরে f7f3f6d প্রয়োগ করে এবং তারপরে থামে। আপনি কার্যকরভাবে সেই কমিটগুলির ক্রম পরিবর্তন করুন এবং Add cat-file” কমিট সম্পূর্ণভাবে সরিয়ে ফেলুন।

কমিট স্কোয়াশিং করা

ইন্টারেক্টিভ রিবেসিং টুলের সাহায্যে একাধিক কমিট নেওয়া এবং সেগুলিকে একটি একক কমিটতে স্কোয়াশ করাও সম্ভব। স্ক্রিপ্টটি রিবেস বার্তায় সহায়ক নির্দেশাবলী প্রদর্শন করে:

				
					#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
				
			

যদি, “pick” বা “edit” এর পরিবর্তে, আপনি “squash” নির্দিষ্ট করেন, গিট সেই পরিবর্তন এবং পরিবর্তনটি,  উভয়ই সরাসরি তার আগে প্রয়োগ করে এবং আপনার কমিট বার্তাগুলিকে মার্জ করে। সুতরাং, আপনি যদি এই তিনটি কমিট থেকে একটি একক কমিট তৈরি করতে চান তবে আপনি স্ক্রিপ্টটিকে এইরকম দেখান:



				
					pick f7f3f6d Change my name a bit
squash 310154e Update README formatting and add blame
squash a5f4a0d Add cat-file
				
			

আপনি যখন সম্পাদককে সেভ করেন এবং প্রস্থান করেন, গিট তিনটি পরিবর্তন প্রয়োগ করে এবং তারপরে তিনটি কমিট বার্তা মার্জ করতে আপনাকে সম্পাদকে ফিরিয়ে দেয়:

				
					# This is a combination of 3 commits.
# The first commit's message is:
Change my name a bit

# This is the 2nd commit message:

Update README formatting and add blame

# This is the 3rd commit message:

Add cat-file


				
			

 আপনি যখন এটি সংরক্ষণ করেন, তখন আপনার কাছে একটি একক কমিট থাকে যা পূর্ববর্তী তিনটি কমিটের পরিবর্তনগুলি উপস্থাপিত করে।

একটি কমিট বিভক্ত করা

একটি কমিট বিভক্ত করার ফলে, কমিটকে পূর্বাবস্থায় ফিরিয়ে  আনে এবং তারপর আংশিকভাবে স্টেজ করে এবং আপনি যতবার কমিট করতে চান ততবার কমিট করে। উদাহরণস্বরূপ, ধরুন আপনি আপনার তিনটি কমিটের মধ্যবর্তী কমিটকে বিভক্ত করতে চান। “Update README formatting and add blame” এর পরিবর্তে, আপনি এটিকে দুটি কমিট-এ বিভক্ত করতে চান: প্রথমটির জন্য “Update README formatting”  এবং দ্বিতীয়টির জন্য “Add blame” ৷ আপনি “edit” এ বিভক্ত করতে চান এমন কমিট-এর নির্দেশনা পরিবর্তন করে rebase -i স্ক্রিপ্টে এটি করতে পারেন ৷

				
					pick f7f3f6d Change my name a bit
edit 310154e Update README formatting and add blame
pick a5f4a0d Add cat-file
				
			

তারপর, যখন স্ক্রিপ্টটি আপনাকে কমান্ড লাইনে নিয়ে যায়, আপনি সেই কমিটটি পুনরায় সেট করেন, পুনরায় সেট করা পরিবর্তনগুলি গ্রহণ করেন এবং সেগুলির মধ্যে একাধিক কমিট তৈরি করেন। আপনি যখন সম্পাদকটি সংরক্ষণ করেন এবং প্রস্থান করেন, তখন গিট আপনার তালিকার প্রথম কমিটের প্যারেন্টের কাছে রিওয়াইন্ড করে, প্রথম কমিট (f7f3f6d) প্রয়োগ করে, দ্বিতীয়টি (310154e) প্রয়োগ করে এবং আপনাকে কনসোলে নিয়ে যায়। সেখানে, আপনি git reset HEAD^ এর সাথে সেই কমিটের একটি মিশ্র রিসেট করতে পারেন, যা কার্যকরভাবে সেই কমিটটিকে পূর্বাবস্থায় ফিরিয়ে আনে এবং পরিবর্তিত ফাইলগুলিকে স্টেজ ছাড়াই রেখে দেয়। এখন আপনি ফাইলগুলি স্টেজ এবং কমিট করতে পারেন যতক্ষণ না আপনার কাছে বেশ কয়েকটি কমিট না থাকে এবং আপনার কাজ শেষ হলে git rebase –continue চালান:

				
					$ git reset HEAD^
$ git add README
$ git commit -m 'Update README formatting'
$ git add lib/simplegit.rb
$ git commit -m 'Add blame'
$ git rebase --continue
				
			

গিট স্ক্রিপ্টে শেষ কমিট (a5f4a0d) প্রয়োগ করে এবং আপনার ইতিহাস এইরকম দেখায়:

				
					$ git log -4 --pretty=format:"%h %s"
1c002dd Add cat-file
9b29157 Add blame
35cfb2b Update README formatting
f7f3f6d Change my name a bit
				
			

এটি আপনার তালিকার তিনটি সাম্প্রতিক কমিটগুলির মধ্যে SHA-1 গুলিকে পরিবর্তন করে, তাই নিশ্চিত করুন যে কোনও পরিবর্তিত কমিট সেই তালিকায় দেখা যাচ্ছে না যা আপনি ইতিমধ্যে একটি শেয়ারড রিপোজিটরিতে পুশ করেছেন৷ লক্ষ্য করুন যে তালিকার শেষ কমিট (f7f3f6d) অপরিবর্তিত। এই কমিটটি স্ক্রিপ্টে দেখানো সত্ত্বেও, গিট কমিটটিকে অপরিবর্তিত রেখে দেয়, কারণ এটিকে “pick” হিসাবে চিহ্নিত করা হয়েছিল এবং যেকোন রিবেস পরিবর্তনের আগে প্রয়োগ করা হয়েছিল৷ 

একটি কমিট মুছে ফেলা

আপনি যদি একটি কমিট থেকে পরিত্রাণ পেতে চান, rebase -i স্ক্রিপ্ট ব্যবহার করে আপনি এটি মুছে ফেলতে পারেন। কমিটগুলির তালিকায়, আপনি যে কমিটটি মুছতে চান তার আগে “ড্রপ” শব্দটি রাখুন (বা রিবেস স্ক্রিপ্ট থেকে সেই লাইনটি মুছে দিন):

				
					pick 461cb2a This commit is OK
drop 5aecc10 This commit is broken
				
			

গিট যেভাবে কমিট অবজেক্ট তৈরি করে তার কারণে, একটি কমিট মুছে ফেলা বা পরিবর্তন করার ফলে এটি অনুসরণ করা সমস্ত কমিটের পুনর্লিখন করে। আপনার রিপো’র ইতিহাসে আপনি যত বেশি ফিরে যাবেন, তত বেশি কমিট পুনরায় তৈরি করতে হবে। আপনার যদি পরবর্তীতে অনেকগুলি কমিট থাকে যা আপনার মুছে ফেলা কমিটটির উপর নির্ভর করে, তাহলে এটি অনেকগুলি মার্জ কনফ্লিক্টের কারণ হতে পারে।

 

আপনি যদি এইরকম একটি রিবেসের মধ্য দিয়ে কিছুটা পথ পান এবং সিদ্ধান্ত নেন যে এটি একটি ভাল ধারণা নয়, আপনি সর্বদা থামতে পারেন। টাইপ করুন git rebase –abort, এবং আপনার রিপো রিবেস শুরু করার আগের অবস্থায় ফিরে যাবে।

আপনি যদি একটি রিবেস শেষ করেন এবং সিদ্ধান্ত নেন যে এটি আপনি যা চান তা নয়, আপনি আপনার ব্রাঞ্চের পূর্ববর্তী সংস্করণ পুনরুদ্ধার করতে git reflog ব্যবহার করতে পারেন। reflog কমান্ড সম্পর্কে আরও তথ্যের জন্য “ডেটা রিকভারি” বিষয়টি দেখুন।

নোট

Drew DeVault কিভাবে গিট রিবেস ব্যবহার করতে হয় তা শিখতে অনুশীলনসহ একটি ব্যবহারিক হ্যান্ডস-অন গাইড তৈরি করেছেন । আপনি এটি এখানে খুঁজে পেতে পারেন: https://git-rebase.io/

নিউক্লীয় অপশন: ব্রাঞ্চ ফিল্টার করা

আরেকটি ইতিহাস-পুনরায় লেখার অপশন আছে যা আপনি ব্যবহার করতে পারেন যদি কিছু স্ক্রিপ্টেবল উপায়ে বৃহত্তর সংখ্যক কমিট পুনরায় লেখার প্রয়োজন হয় — উদাহরণস্বরূপ, গ্লোবালি আপনার ইমেইল এড্রেস পরিবর্তন করা বা প্রতিটি কমিট থেকে একটি ফাইল মুছে ফেলা। কমান্ডটি হল filter-branch, এবং এটি আপনার ইতিহাসের বিশাল অংশ পূনর্লিখন করতে পারে, তাই আপনার সম্ভবত এটি ব্যবহার করা উচিত নয় যদি না আপনার প্রজেক্টটি এখনও পাবলিক না হয় এবং অন্যান্য লোকেরা আপনি যে কমিটগুলি পুনর্লিখন করতে চলেছেন তার উপর ভিত্তি করে কাজ না করে। যাইহোক, এটা খুব দরকারী হতে পারে। আপনি কয়েকটি সাধারণ ব্যবহার শিখবেন যাতে এটি করতে সক্ষম এমন কিছু জিনিস সম্পর্কে আপনি ধারণা পেতে পারেন।

সতর্কতা

git filter-branch কমান্ডটির অনেক সমস্যা আছে, এবং ইতিহাস পুনর্লিখনের জন্য এটি আর প্রস্তাবিত উপায় নয়। এর পরিবর্তে, git-filter-repo কমান্ডটি ব্যবহার করার কথা বিবেচনা করুন, যা একটি পাইথন স্ক্রিপ্ট যা বেশিরভাগ অ্যাপ্লিকেশনের জন্য ভাল কাজ করে যেখানে আপনি সাধারণত filter-branch কমান্ডে যেতে পারেন। এর ডকুমেন্টেশন এবং সোর্স কোড https://github.com/newren/git-filter-repo এই লিংকটিতে পাওয়া যাবে।

প্রতিটি কমিট থেকে একটি ফাইল সরানো

 

এটি মোটামুটি সাধারণভাবে ঘটে। কেউ ঘটনাক্রমে একটি চিন্তাহীন git add . সহ একটি বিশাল বাইনারি ফাইল কমিট করে এবং আপনি এটিকে সবজায়গা থেকে সরাতে চান। সম্ভবত আপনি দুর্ঘটনাক্রমে একটি পাসওয়ার্ড ধারণকারী একটি ফাইল কমিট করেছেন, এবং আপনি আপনার প্রজেক্ট ওপেন সোর্স করতে চান। ফিল্টার-ব্রাঞ্চ হল সেই টুল যা আপনি সম্ভবত আপনার সমগ্র ইতিহাস স্ক্রাব করতে ব্যবহার করতে চান। আপনার সম্পূর্ণ ইতিহাস থেকে passwords.txt নামের একটি ফাইল মুছে ফেলতে, আপনি –tree-filter অপশনটি filter-branch  কমান্ড-এর সাথে ব্যবহার করতে পারেন:

				
					$ git filter-branch --tree-filter 'rm -f passwords.txt' HEAD
Rewrite 6b9b3cf04e7c5686a9cb838c3f36a8cb6a0fc2bd (21/21)
Ref 'refs/heads/master' was rewritten
				
			

–tree-filter অপশনটি প্রজেক্টের প্রতিটি চেকআউটের পরে নির্দিষ্ট কমান্ড চালায় এবং তারপর ফলাফলগুলি পুনরায় কমিট করে। এই ক্ষেত্রে, আপনি প্রতিটি স্ন্যাপশট থেকে passwords.txt নামক একটি ফাইল সরিয়ে ফেলবেন, সেটি বিদ্যমান থাকুক বা না থাকুক। আপনি যদি দুর্ঘটনাক্রমে ইতোমধ্যে কমিট হওয়া সম্পাদকের ব্যাকআপ ফাইলগুলি সরাতে চান তবে আপনি git filter-branch –tree-filter ‘rm -f *~’ HEAD এর মতো কমান্ডটি চালাতে পারেন।

আপনি Git rewriting trees এবং কমিটগুলো দেখতে সক্ষম হবেন এবং তারপর ব্রাঞ্চ পয়েন্টারটি শেষে সরাতে পারবেন। সাধারণত পরীক্ষামূলক ব্রাঞ্চে এটি করা একটি ভাল ধারণা এবং তারপরে আপনি যে ফলাফলটি চান তা নির্ধারণ করার পরে আপনার master ব্রাঞ্চকে হার্ড-রিসেট করুন। আপনার সমস্ত ব্রাঞ্চে filter-branch চালানোর জন্য, আপনি –all কমান্ডে পাস করতে পারেন।

 

একটি সাবডিরেক্টরি নতুন রুট বানানো

ধরুন আপনি অন্য সোর্স কন্ট্রোল সিস্টেম থেকে একটি ইম্পোর্ট করেছেন এবং এমন সাবডিরেক্টরি আছে যার কোন মানে নেই (trunk, tags, এবং অন্যান্য)। আপনি যদি প্রতিটি কমিটের জন্য trunk সাবডিরেক্টরিটিকে নতুন প্রজেক্ট রুট করতে চান, –tree-filter আপনাকে এটি করতেও সাহায্য করতে পারে:

				
					$ git filter-branch --subdirectory-filter trunk HEAD
Rewrite 856f0bf61e41a27326cdae8f09fe708d679f596f (12/12)
Ref 'refs/heads/master' was rewritten
				
			

এখন আপনার নতুন প্রজেক্ট রুট যা প্রতিবার trunk সাবডিরেক্টরিতে ছিল। Git স্বয়ংক্রিয়ভাবে এমন কমিটগুলিও সরিয়ে দেবে যা সাবডিরেক্টরিকে প্রভাবিত করে না।

গ্লোবালি ইমেইল এড্রেস পরিবর্তন

আরেকটি সাধারণ ঘটনা হল যে আপনি কাজ শুরু করার আগে আপনার নাম এবং ইমেইল এড্রেস সেট করার জন্য  git config কমান্ডটি চালাতে ভুলে গেছেন, অথবা সম্ভবত আপনি কর্মক্ষেত্রে একটি প্রজেক্ট খুলতে চান এবং আপনার সমস্ত কাজের ইমেইল এড্রেসগুলি আপনার ব্যক্তিগত এড্রেসে পরিবর্তন করতে চান। যাই হোক না কেন, আপনি filter-branch কমান্ডের সাহায্যে একটি ব্যাচে একাধিক কমিটেও ইমেইল এড্রেস পরিবর্তন করতে পারেন। শুধুমাত্র আপনার ইমেইল এড্রেসগুলি পরিবর্তন করতে আপনাকে সতর্কতা অবলম্বন করতে হবে, তাই আপনি –commit-filter অপশনটি  ব্যবহার করুন:

				
					$ git filter-branch --commit-filter '
        if [ "$GIT_AUTHOR_EMAIL" = "schacon@localhost" ];
        then
                GIT_AUTHOR_NAME="Scott Chacon";
                GIT_AUTHOR_EMAIL="schacon@example.com";
                git commit-tree "$@";
        else
                git commit-tree "$@";
        fi' HEAD


				
			

এটি চলতে থাকে এবং আপনার ইমেইল এড্রেস এর জন্য প্রতিটি কমিট পূনর্লিখন করে।  যেহেতু কমিটগুলিতে তাদের প্যারেন্ট SHA-1-র মান রয়েছে, তাই এই কমান্ডটি আপনার ইতিহাসের প্রতিটি কমিট SHA-1 পরিবর্তন করে, শুধুমাত্র যেগুলোর একই ইমেইল এড্রেস রয়েছে সেগুলো পূনর্লিখন করে না।