৭.৮ গিট টুলস – অ্যাডভান্স মার্জিং
অ্যাডভান্স মার্জিং
গিট এ মার্জ করা সাধারণত মোটামুটি সহজ। যেহেতু গিট অন্য ব্রাঞ্চকে একাধিকবার মার্জ করা সহজ করে তোলে, এর মানে হল যে আপনার অনেকক্ষণ ধরে টিকে আছে এমন একটি ব্রাঞ্চ থাকতে পারে তবে আপনি এটিকে আপ টু ডেট রাখতে পারেন, প্রায়শই ছোট কনফ্লিক্ট সমাধান করতে পারেন, বরং আপনি সিরিজের শেষে একটি বিশাল কনফ্লিক্ট দ্বারা অবাক হতে পারেন।
যাইহোক, কখনও কখনও ট্রিকি কনফ্লিক্ট ঘটে। অন্য কিছু ভার্সন কনট্রোল সিস্টেম এর মতো , গিট মার্জ , কনফ্লিক্ট রেজোলিউশন সম্পর্কে অত্যধিক কৌশলী হওয়ার চেষ্টা করে না। গিট-এর দর্শন হল একটি মার্জ রেজোলিউশন কখন স্পষ্ট – তা নির্ধারণ করার বিষয়ে স্মার্ট হওয়া। কিন্তু যদি কোন কনফ্লিক্ট হয়, এটি স্বয়ংক্রিয়ভাবে সেই কনফ্লিক্ট সমাধান করার বিষয়ে কৌশলী হওয়ার চেষ্টা করে না। অতএব, যদি আপনি দুটি ব্রাঞ্চকে মার্জ করার জন্য খুব বেশি অপেক্ষা করেন যা দ্রুত ডাইভার্জ হয়, তাহলে আপনি কিছু সমস্যায় পড়তে পারেন।
এই বিভাগে, আমরা এই সমস্যাগুলির মধ্যে কিছু কিছু সমস্যা কেমন হতে পারে এবং এরকম আরও জটিল পরিস্থিতিগুলি পরিচালনা করতে গিট আপনাকে কী সরঞ্জাম দেয় তা নিয়ে আলোচনা করব।
আমরা আপনি করতে পারেন এমন কিছু ভিন্ন ধরণের মার্জগুলিও কভার করব, সেইসাথে আপনি যে মার্জগুলি করেছেন তা থেকে কীভাবে ফিরে আসা যায় তাও দেখব৷
মার্জ কনফ্লিক্ট
যদিও Basic Merge Conflicts, এই টপিক থেকে , আমরা কনফ্লিক্ট মার্জের কিছু মৌলিক ধারণা পেয়েছি। কিন্তু, জটিল জটিল কনফ্লিক্ট মার্জের ক্ষেত্রে, আসলে কি কি ঘটে এবং আসলে ব্যাপারগুলোতে কি ঘটেছে সেই ব্যাপার গুলো হ্যান্ডেল করার জন্য গিট আমাদেরকে কিছু টুলস দিয়ে থাকে।
প্রথমত, যদি সম্ভব হয় তাহলে, কনফ্লিক্ট থাকতে পারে এমন একটি মার্জ করার আগে আপনার ওয়ার্কিং ডিরেক্টরিটি পরিষ্কার কিনা তা নিশ্চিত করার চেষ্টা করুন। আপনার বর্তমান কাজ গুলো , হয় এটি একটি অস্থায়ী ব্রাঞ্চে কমিট করুন বা এটিকে স্ট্যাশে রেখে দিন। যাতে করে, আপনি সহজেই আপনার বর্তমান কাজ গুলো পূর্বাবস্থায় নিয়ে যেতে পারেন। আপনার ওয়ার্কিং ডিরেক্টরিতে, যদি মার্জ করার সময় আনসেভ পরিবর্তন থেকে থাকে তাহলে এখানে কিছু টিপস জানবো যাতে করে এরকম সময়ে আমাদের হেল্প হতে পারে।
চলুন একটি খুব সহজ উদাহরণ-এর মাধ্যমে বিষয়টি দেখি. আমাদের কাছে একটি অতি সাধারণ Ruby ফাইল রয়েছে যা ‘hello world’ প্রিন্ট করে।
#! /usr/bin/env ruby
def hello
puts 'hello world'
end
একটি শাখায় আমরা “hello” শব্দটিকে “hola” তে পরিবর্তন করি, তারপরে অন্য শাখায় আমরা “world”কে “mundo” তে পরিবর্তন করি, ঠিক আগের মতো।
যখন আমরা দুটি branch-কে merge করি, তখন আমরা একটি merge conflict পাব:
$ git merge i18n-world
Auto-merging hello.rb
CONFLICT (content): Merge conflict in hello.rb
Recorded preimage for 'hello.rb'
Automatic merge failed; fix conflicts and then commit the result.
আপনার সেখানে FILE-এর জন্য নতুন লাইন রেকর্ড করা প্রিমেজ লক্ষ্য করবেন। অন্যথায় এটি একটি সাধারণ merge conflict-এর মতো দেখাবে। এই মুহুর্তে, rerere আমাদের কয়েকটি জিনিস বলতে পারে।
$ git status
# On branch master
# Unmerged paths:
# (use "git reset HEAD ..." to unstage)
# (use "git add ..." to mark resolution)
#
# both modified: hello.rb
#
যাইহোক, git rerere আপনাকে বলবে যে এটি git rerere স্ট্যাটাসের সাথে pre-merge অবস্থায় কী রেকর্ড করেছে:
$ git rerere status
hello.rb
এবং git rerere diff resolution-এর বর্তমান status দেখাবে —- আপনি কি সমাধান করতে শুরু করেছেন এবং আপনি এটির সমাধান করেছেন।
$ git rerere diff
--- a/hello.rb
+++ b/hello.rb
@@ -1,11 +1,11 @@
#! /usr/bin/env ruby
def hello
-<<<<<<<
- puts 'hello mundo'
-=======
+<<<<<<< HEAD
puts 'hola world'
->>>>>>>
+=======
+ puts 'hello mundo'
+>>>>>>> i18n-world
end
এছাড়াও (এবং এটি সত্যিই rerere এর সাথে সম্পর্কিত নয়), আপনি conflict-সহ ফাইলগুলি এবং আগের বাম এবং ডান সংস্করণগুলি দেখতে git ls-files -u ব্যবহার করতে পারেন:
$ git ls-files -u
100644 39804c942a9c1f2c03dc7c5ebcd7f3e3a6b97519 1 hello.rb
100644 a440db6e8d1fd76ad438a49025a9ad9ce746f581 2 hello.rb
100644 54336ba847c3758ab604876419607e9443848474 3 hello.rb
এখন আপনি এটিকে শুধু ‘hola mundo’ বলে সমাধান করতে পারেন এবং rerere কী মনে রাখবে তা দেখতে আপনি আবার git rerere diff চালাতে পারেন:
$ git rerere diff
--- a/hello.rb
+++ b/hello.rb
@@ -1,11 +1,7 @@
#! /usr/bin/env ruby
def hello
-<<<<<<<
- puts 'hello mundo'
-=======
- puts 'hola world'
->>>>>>>
+ puts 'hola mundo'
end
তাই এটি মূলত বলে, যখন git একটি hello.rb ফাইলে একটি hunk conflict দেখে যার একদিকে “hello mundo” এবং অন্যদিকে “hola world” রয়েছে, এটি “hello mundo” তে সমাধান করবে।
এখন আমরা এটিকে solved করা হিসাবে চিহ্নিত করতে পারি এবং এটি commit করতে পারি:
$ git ls-files -u
100755 ac51efdc3df4f4fd328d1a02ad05331d8e2c9111 1 hello.rb
100755 36c06c8752c78d2aff89571132f3bf7841a7b5c3 2 hello.rb
100755 e85207e04dfdd5eb0a1e9febbc67fd837c44a1cd 3 hello.rb
এই :1:hello.rb হল ব্লব SHA-1 দেখার জন্য একটি সংক্ষিপ্ত বিবরণ।
এখন যেহেতু আমাদের ওয়ার্কিং ডিরেক্টরিতে তিনটি stage-এর বিষয়বস্তু রয়েছে, আমরা হোয়াইটস্পেস সমস্যা সমাধানের জন্য ম্যানুয়ালি তাদের সমাধান করতে পারি এবং স্বল্প পরিচিত git merge-file কমান্ডের সাহায্যে ফাইলটিকে পুনরায় মার্জ করতে পারি।
$ git add hello.rb
$ git commit
Recorded resolution for 'hello.rb'.
[master 68e16e5] Merge branch 'i18n'
আপনি দেখতে পাচ্ছেন যে এটি “ফাইলের জন্য রেকর্ড করা resolution”।
এখন, সেই merge-টিকে redo করুন এবং তারপরে এটিকে আমাদের master branch-এর উপরে rebase করুন। আমরা git reset ব্যবহার করে আমাদের branch-কে ফিরিয়ে আনতে পারি যেমনটি আমরা Reset Demystified এ দেখেছি।
$ git reset --hard HEAD^
HEAD is now at ad63f15 i18n the hello
আমাদের merge redo করা হয়েছে৷ এখন একটি branch rebase করা যাক।
$ git checkout i18n-world
Switched to branch 'i18n-world'
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: i18n one word
Using index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
Auto-merging hello.rb
CONFLICT (content): Merge conflict in hello.rb
Resolved 'hello.rb' using previous resolution.
Failed to merge in the changes.
Patch failed at 0001 i18n one word
এখন, আমরা একই merge conflict পেয়েছি যেমনটি আমরা আশা করেছিলাম, তবে পূর্ববর্তী resolution লাইন ব্যবহার করে সমাধান করা ফাইলটি একবার দেখুন। আমরা যদি ফাইলটি দেখি, আমরা দেখতে পাব যে এটি ইতিমধ্যে সমাধান করা হয়েছে, এতে কোন merge conflict marker নেই।
#! /usr/bin/env ruby
def hello
puts 'hola mundo'
end
এছাড়াও, git diff আপনাকে দেখাবে কিভাবে এটি স্বয়ংক্রিয়ভাবে re-resolved করা হয়েছিল:
$ git diff
diff --cc hello.rb
index a440db6,54336ba..0000000
--- a/hello.rb
+++ b/hello.rb
@@@ -1,7 -1,7 +1,7 @@@
#! /usr/bin/env ruby
def hello
- puts 'hola world'
- puts 'hello mundo'
++ puts 'hola mundo'
end
আপনি git checkout-এর সাথে conflict-সহ ফাইলের status আবার merge করতে পারেন:
$ git checkout --conflict=merge hello.rb
$ cat hello.rb
#! /usr/bin/env ruby
def hello
<<<<<<< ours
puts 'hola world'
=======
puts 'hello mundo'
>>>>>>> theirs
end
আমরা Advanced Merging-এ এর একটি উদাহরণ দেখেছি। যদিও আপাতত, আবার git rerere-এ চালিয়ে এটিকে re-resolve করি:
$ git rerere
Resolved 'hello.rb' using previous resolution.
$ cat hello.rb
#! /usr/bin/env ruby
def hello
puts 'hola mundo'
end
আমরা rerere cache-এ resolution ব্যবহার করে ফাইলটি স্বয়ংক্রিয়ভাবে re-resolved করেছি। আপনি এখন এটি সম্পূর্ণ করতে rebase add করতে এবং চালিয়ে যেতে পারেন।
$ git add hello.rb
$ git rebase --continue
Applying: i18n one word
সুতরাং, আপনি যদি অনেকগুলি re-merge করেন, বা ton merge ছাড়াই একটি branch-কে আপনার master branch-এর সাথে আপ টু ডেট রাখতে চান, বা আপনি প্রায়শই rebase করতে চান, তবে আপনি আপনার কাজকে কিছুটা সহজ করার জন্য rerere ব্যাবহার করতে পারেন।