গিট-চেরি-পিক কীভাবে কেবলমাত্র নির্দিষ্ট ফাইলগুলিতে পরিবর্তন হয়?


586

যদি আমি একটি গিট শাখায় একত্রীকরণ করতে চাই তবে নির্দিষ্ট প্রতিশ্রুতিতে পরিবর্তিত কিছু ফাইলের মধ্যে পরিবর্তন হয়েছে যার মধ্যে একাধিক ফাইলের পরিবর্তন রয়েছে, এটি কীভাবে অর্জন করা যায়?

গীত ধরুন নামক কমিট stuffফাইলগুলিতে পরিবর্তন আছে A, B, C, এবং Dকিন্তু আমি শুধুমাত্র একত্রীকরণ করতে চান stuffফাইলগুলিতে এর পরিবর্তন Aএবং B। এটি একটি কাজের মতো শোনাচ্ছে git cherry-pickতবে cherry-pickকেবলমাত্র পুরো কমিটগুলি কীভাবে মার্জ করা যায় তা কেবল ফাইলের একটি উপসেট নয় knows

উত্তর:


688

আমি এটি cherry-pick -n( --no-commit) দিয়ে করব যা আপনাকে প্রতিশ্রুতি দেওয়ার আগে ফলাফলটি পরীক্ষা (এবং সংশোধন) করতে দেয়:

git cherry-pick -n <commit>

# unstage modifications you don't want to keep, and remove the
# modifications from the work tree as well.
# this does work recursively!
git checkout HEAD <path>

# commit; the message will have been stored for you by cherry-pick
git commit

যদি বিপুল সংখ্যক পরিবর্তনগুলি এমন জিনিস হয় যা আপনি চান না, পৃথক পাথ (মধ্য পদক্ষেপ) যাচাইয়ের পরিবর্তে, আপনি সমস্ত কিছু পুনরায় সেট করতে পারেন, তারপরে আপনি যা চান তাতে যুক্ত করুন:

# unstage everything
git reset HEAD

# stage the modifications you do want
git add <path>

# make the work tree match the index
# (do this from the top level of the repo)
git checkout .

10
উপরন্তু করতে git checkout .আমিও সুপারিশ করবে git clean -fপ্রবর্তন কোনো নতুন কিন্তু অবাঞ্ছিত ফাইল মুছে ফেলার জন্য চেরি-বাছাই করা কমিট।
rlat

4
পরবর্তী পদ্ধতির জন্য অতিরিক্ত নোট: আমি ব্যবহার করি git add -pযা আপনাকে ইন্টারেক্টিভভাবে সিদ্ধান্ত নিতে দেয় যে আপনি ফাইলের প্রতি
ম্যাথিউয়াস

6
এটি ক্ষেত্রে এতটা দুর্দান্ত নয় যে চেরি-বাছাই করা প্রতিশ্রুতি বর্তমান কার্যকরী অনুলিপিটির জন্য প্রযোজ্য নয় কারণ এটি এতটা আলাদা, তবে এটি একটি ফাইল পরিষ্কারভাবে প্রয়োগ করবে
সীমিত প্রায়শ্চিত্ত

3
আপনি এটির সাথে বাছাই করে স্টেস্টেজও করতে পারেন git reset -p HEAD। এটি সমতুল্য add -pতবে খুব কমই জানেন যে এটি বিদ্যমান।
প্যাট্রিক Schlüter

1
খুব দরকারী কৌশল। আমি একটি সারকথা ক্ষেত্রে কেউ একটি দ্রুত স্ক্রিপ্ট যেমন দরকার তা রেখেছি gist.github.com/PiDayDev/68c39b305ab9d61ed8bb2a1195ee1afc
Damiano

145

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

git show SHA -- file1.txt file2.txt | git apply -

এটি আসলে addফাইলগুলি বা কোনও প্রতিশ্রুতি দেয় না যাতে আপনার সাথে এটি অনুসরণ করার প্রয়োজন হতে পারে

git add file1.txt file2.txt
git commit -c SHA

অথবা আপনি যদি অ্যাডটি বাদ দিতে চান তবে --cachedযুক্তিটি ব্যবহার করতে পারেনgit apply

git show SHA -- file1.txt file2.txt | git apply --cached -

আপনি পুরো ডিরেক্টরিগুলির জন্য একই জিনিস করতে পারেন

git show SHA -- dir1 dir2 | git apply -

2
আকর্ষণীয় পদ্ধতি, ধন্যবাদ। কিন্তু না show SHA -- file | applyমূলত হিসাবে একই কাজ checkout SHA -- fileহিসেবে মার্ক Longair এর উত্তর ?
টোবিয়াস কেইনজলার

4
নাহ, checkout SHA -- fileSHA- তে ঠিক সংস্করণটি চেকআউট করবে, যখন show SHA -- file | applyকেবল এসএইচএ-র পরিবর্তনগুলি প্রয়োগ করবে (ঠিক যেমন চেরি-পিক করে)। (ক) উত্স শাখায় প্রদত্ত ফাইলটি পরিবর্তনের জন্য একাধিক প্রতিশ্রুতিবদ্ধ হওয়া বা (খ) আপনার বর্তমান টার্গেট শাখায় ফাইলটি পরিবর্তন করার প্রতিশ্রুতি রয়েছে কিনা তা বিবেচ্য।
মাইকেল অ্যান্ডারসন

9
সবেমাত্র এর জন্য আরও দুর্দান্ত ব্যবহার খুঁজে পেয়েছি: বাছাই প্রত্যাবর্তন, যখন আপনি কেবল একটি ফাইল পুনরায় ফিরিয়ে আনতে চান (যেহেতু git revertসম্পূর্ণ প্রতিশ্রুতিটি পূর্বাবস্থায় ফিরে আসে )। git show -R SHA -- file1.txt file2.txt | git apply -
মাইকেল অ্যান্ডারসন

2
@ রোয়ি বাহুমির এর একদম আলাদা অর্থ রয়েছে। git diff SHA -- file1.txt file2.txt | git apply -মানে ফাইলের বর্তমান সংস্করণ এবং এসএইচএ-র সংস্করণকে বর্তমান সংস্করণে সমস্ত পার্থক্য প্রয়োগ করুন। সংক্ষেপে এটি হিসাবে একই git checkout SHA -- file1.txt file2.txtgit showসংস্করণটির চেয়ে কেন আলাদা এটির জন্য আমার আগের মন্তব্যটি দেখুন ।
মাইকেল অ্যান্ডারসন

5
যদি আপনি বিবাদগুলি সমাধান করতে git apply -3 -হয় , ন্যায়বিচারের পরিবর্তে ব্যবহার করুন git apply -, তবে যদি কোনও বিরোধ হয়, আপনি ব্যবহার সহ আপনার স্ট্যান্ডার্ড দ্বন্দ্ব সমাধানের কৌশলটি ব্যবহার করতে পারেন git mergetool
কিওয়ার্টজগুয়ে

87

আমি সাধারণত ব্যবহার করি -p অন্য শাখার একটি গিট চেকআউট সহ পতাকাটি যা আমি অন্যান্য বেশিরভাগ পদ্ধতির চেয়ে সহজ এবং বেশি দানাদার বলে মনে করি।

নীতিগতভাবে:

git checkout <other_branch_name> <files/to/grab in/list/separated/by/spaces> -p

উদাহরণ:

git checkout mybranch config/important.yml app/models/important.rb -p

তারপরে আপনি একটি সংলাপটি জিজ্ঞাসা করবেন যা আপনি "ব্লবস" এ পরিবর্তন করতে চান যা এই ধারাবাহিক কোড পরিবর্তনের প্রতিটি অংশকে কার্যকর করে দেয় যা আপনি কোডের প্রতিটি অংশের জন্য y(হ্যাঁ) n(না) ইত্যাদি সংকেত দিতে পারেন ।

-pঅথবা patchবিকল্প সহ Git কমান্ড বিভিন্ন জন্য কাজ করেgit stash save -p যা আপনি কি যদি আপনি আপনার বর্তমান কাজ থেকে লুকিয়ে রাখার জন্য চান তা চয়ন করতে পারবেন

আমি অনেক সময় এই কৌশলটি ব্যবহার করি যখন আমি অনেক কাজ করেছি এবং এটিকে আলাদা করে এবং আরও প্রতিটি বিষয় ভিত্তিক প্রতিশ্রুতিবদ্ধ ব্যবহার git add -pকরতে এবং প্রতিটি প্রতিশ্রুতিবদ্ধতার জন্য আমি যা চাই তা বেছে নিতে চাই :)


3
আমি নিয়মিত ব্যবহার git-add -p, কিন্তু আমি জানতাম না git-checkoutএকটি হয়েছে -pপতাকা - না ঠিক মার্জ সমস্যার অ- -pউত্তর আছে?
টোবিয়াস কেইনজ্লার

1
কমপক্ষে -pএই জাতীয় বিরোধী বিভাগের জন্য একটি ম্যানুয়াল সম্পাদনা করার অনুমতি দেবে, cherry-pickএটি সম্ভবত যেভাবে উপার্জন করবে। আমি পরের বার যখন এটির প্রয়োজন হবে তা পরীক্ষা করব, অবশ্যই একটি আকর্ষণীয় পন্থা
টোবিয়াস কিয়েঞ্জার

2
দুটি সেরা উত্তরের মধ্যে একটি যা শাখাগুলিতে একযোগে পরিবর্তনগুলি হত্যা করে না।
akostadinov

1
কোনটি কুকুর প্রয়োগ করতে হবে তা নির্বাচন করার জন্য এই উত্তরটি দেখুন: stackoverflow.com/a/10605465/4816250 বিশেষত 'এর' বিকল্পটি খুব সহায়ক ছিল।
jvd10

1
git reset -p HEADমঞ্জুরি দেয় -pযখন আপনি শুধুমাত্র সূচক থেকে কিছু প্যাচ সরাতে চান যা কুশলী প্রস্থান করা যেতে পারে।
প্যাট্রিক Schlüter

42

জেফ্রুমির উত্তরের চেয়ে এই পদ্ধতির সুবিধাটি হ'ল গিট রিসেটের কোন আচরণটি সঠিক তা আপনার মনে রাখতে হবে না :)

 # Create a branch to throw away, on which we'll do the cherry-pick:
 git checkout -b to-discard

 # Do the cherry-pick:
 git cherry-pick stuff

 # Switch back to the branch you were previously on:
 git checkout -

 # Update the working tree and the index with the versions of A and B
 # from the to-discard branch:
 git checkout to-discard -- A B

 # Commit those changes:
 git commit -m "Cherry-picked changes to A and B from [stuff]"

 # Delete the temporary branch:
 git branch -D to-discard

2
আপনার উত্তরের জন্য ধন্যবাদ. এখন এটি আমাকে ভাবতে অনুপ্রাণিত করেছিল, কেন cherry-pickসরাসরি এড়িয়ে চলবে না git checkout stuff -- A B? এবং git commit -C stuffপ্রতিশ্রুতি বার্তাটি একই থাকবে
টোবিয়াস কেইনজলার

8
@Tobias: তা কাজ করবে শুধুমাত্র যদি উপর পরিবর্তিত ফাইল stuffআপনার বর্তমান ডালে অথবা সাধারণ পূর্বপুরুষ মধ্যে যে কোন জায়গায় পরিবর্তন করা হয়েছে HEADএবং stuffএবং ডগা stuff। যদি সেগুলি থাকে, তবে cherry-pickসঠিক ফলাফলটি তৈরি করা হবে (মূলত একীকরণের ফলাফল), যখন আপনার পদ্ধতিটি বর্তমান শাখায় পরিবর্তনগুলি ফেলে দেবে এবং সাধারণ পূর্বপুরুষের থেকে সমস্ত পরিবর্তন আপ stuffরাখবে - কেবল তার মধ্যে থাকাগুলিই নয় একক প্রতিশ্রুতি
ক্যাসাবেল

2
@ তোবিয়াস কেইনজলার: আমি ধরেই নিয়েছিলাম যে আপনার শুরুর পয়েন্টটি stuffচেরি বাছাইয়ের ফলাফলটি ছেড়ে দেবে Aএবং প্রতিশ্রুতিবদ্ধভাবে Bতাদের বিষয়বস্তু থেকে আলাদা সামগ্রী সহ তার পিতামাতার চেয়ে যথেষ্ট আলাদা ছিল stuff। তবে, যদি এটি ঠিক একই হয় তবে আপনি ঠিক বলেছেন - আপনি যেমন বলেছিলেন তেমন করতে পারতেন।
লংগায়ার

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

আমি মনে করি এই অন্যান্য থ্রেডে আমার উত্তরটি আপনার পরে যা হতে পারে।
আয়ান

30

চেরি পিক হ'ল নির্দিষ্ট "কমিট" থেকে পরিবর্তনগুলি বেছে নেওয়া। সবচেয়ে সহজ সমাধানটি হ'ল নির্দিষ্ট ফাইলগুলির সমস্ত পরিবর্তন ব্যবহার করা is

 git checkout source_branch <paths>...

উদাহরণে:

$ git branch
* master
  twitter_integration
$ git checkout twitter_integration app/models/avatar.rb db/migrate/20090223104419_create_avatars.rb test/unit/models/avatar_test.rb test/functional/models/avatar_test.rb
$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   new file:   app/models/avatar.rb
#   new file:   db/migrate/20090223104419_create_avatars.rb
#   new file:   test/functional/models/avatar_test.rb
#   new file:   test/unit/models/avatar_test.rb
#
$ git commit -m "'Merge' avatar code from 'twitter_integration' branch"
[master]: created 4d3e37b: "'Merge' avatar code from 'twitter_integration' branch"
4 files changed, 72 insertions(+), 0 deletions(-)
create mode 100644 app/models/avatar.rb
create mode 100644 db/migrate/20090223104419_create_avatars.rb
create mode 100644 test/functional/models/avatar_test.rb
create mode 100644 test/unit/models/avatar_test.rb

উত্স এবং সম্পূর্ণ ব্যাখ্যা http://jasonrudolph.com/blog/2009/02/25/git-tip-how-to- विसর-specific-files-from-another-branch/

হালনাগাদ:

এই পদ্ধতিতে, গিট ফাইলটি মার্জ করবে না, এটি গন্তব্য শাখায় করা অন্য কোনও পরিবর্তনকে ওভাররাইড করবে। আপনাকে পরিবর্তনগুলি ম্যানুয়ালি মার্জ করতে হবে:

it গিট ডিফার হেড ফাইলের নাম


5
আমিও এটি ভেবেছিলাম , তবে ফাইলগুলি যদি উভয় শাখায় পরিবর্তিত হয় তবে এটি আপনার বর্তমান শাখার পরিবর্তনগুলি
অস্বীকার করে

আপনি ঠিক বলেছেন, এই বিষয়টি নিশ্চিত করা দরকার যে এইভাবে গিটটি মার্জ হয় না, এটি কেবল ওভাররাইড করে। তারপরে কী পরিবর্তন হয়েছে এবং ম্যানুয়ালি একত্রীকরণটি করতে আপনি "গিট ডিফার্ড হেড ফাইলের নাম" করতে পারেন।
cminatti

17

পরিস্থিতি:

আপনি আপনার শাখায় রয়েছেন, আসুন বলুন masterএবং অন্য কোনও শাখায় আপনার প্রতিশ্রুতিবদ্ধ। আপনাকে সেই নির্দিষ্ট কমিট থেকে কেবল একটি ফাইল বেছে নিতে হবে to

অভিগমন:

পদক্ষেপ 1: প্রয়োজনীয় শাখায় চেকআউট করুন।

git checkout master

পদক্ষেপ 2: নিশ্চিত হয়ে নিন যে আপনি প্রয়োজনীয় কমিট হ্যাশটি অনুলিপি করেছেন।

git checkout commit_hash path\to\file

পদক্ষেপ 3: আপনার এখন আপনার পছন্দসই শাখায় প্রয়োজনীয় ফাইলের পরিবর্তন রয়েছে। আপনার কেবল তাদের যুক্ত করতে এবং প্রতিশ্রুতিবদ্ধ হওয়া দরকার।

git add path\to\file
git commit -m "Your commit message"

1
অসাধারণ! আমার জন্য \ পথ \ থেকে \ ডিরেক্টরি \ সহ একটি ডিরেক্টরিতে সমস্ত পরিবর্তনের জন্যও কাজ করেছেন
zaggi

12

আমি কেবল চেরি-বাছাই করব, তারপর এটি করুন:

git reset --soft HEAD^

তারপরে আমি যে পরিবর্তনগুলি চাই না তা প্রত্যাবর্তন করব এবং তারপরে একটি নতুন অঙ্গীকারবদ্ধ।


11

এটি ব্যবহার git merge --squash branch_nameকরে অন্য শাখা থেকে সমস্ত পরিবর্তন আসবে এবং আপনার জন্য একটি প্রতিশ্রুতি প্রস্তুত করবে। এখন সমস্ত অপ্রয়োজনীয় পরিবর্তনগুলি সরিয়ে ফেলুন এবং আপনি যা চান তা ত্যাগ করুন এবং গিট জানতে পারবে না যে সেখানে একত্রীকরণ হয়েছিল।


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

4

আমি আরেকটি উপায় খুঁজে পেয়েছি যা চেরি-বাছাইয়ের ক্ষেত্রে কোনও বিবাদমান সংযোজন রোধ করে যা আইএমও মনে রাখা এবং বুঝতে একরকম সহজ। যেহেতু আপনি সত্যিকার অর্থে প্রতিশ্রুতিবদ্ধভাবে চেরি-বাছাই করছেন না, তবে এটির একটি অংশ, আপনাকে প্রথমে এটি বিভক্ত করতে হবে এবং তারপরে একটি প্রতিশ্রুতি তৈরি করতে হবে যা আপনার প্রয়োজন অনুসারে এবং চেরি-বাছাই করবে।

প্রথমে আপনি বিভক্ত করতে চান এমন প্রতিশ্রুতি থেকে একটি শাখা তৈরি করুন এবং এটি চেকআউট করুন:

$ git checkout COMMIT-TO-SPLIT-SHA -b temp

তারপরে পূর্ববর্তী প্রতিশ্রুতি পুনরায় করুন

$ git reset HEAD~1

তারপরে আপনি চেরি-বাছাই করতে চান এমন ফাইল / পরিবর্তনগুলি যুক্ত করুন:

$ git add FILE

এবং এটি প্রতিশ্রুতিবদ্ধ:

$ git commit -m "pick me"

প্রতিশ্রুতিবদ্ধ হ্যাশটি নোট করুন, আসুন এটিকে পিক-এসএএ কল করুন এবং আপনার মূল শাখায় ফিরে যাই, উদাহরণস্বরূপ চেকআউট জোর করে:

$ git checkout -f master

এবং চেরি বাছাই প্রতিশ্রুতি:

$ git cherry-pick PICK-SHA

এখন আপনি অস্থায়ী শাখা মুছতে পারেন:

$ git branch -d temp -f

2

নতুন একটি (স্কোয়াশ) তে একটি শাখা মার্জ করুন এবং প্রয়োজনীয় ফাইলগুলি সরান:

git checkout master
git checkout -b <branch>
git merge --squash <source-branch-with-many-commits>
git reset HEAD <not-needed-file-1>
git checkout -- <not-needed-file-1>
git reset HEAD <not-needed-file-2>
git checkout -- <not-needed-file-2>
git commit

2

সম্পূর্ণতার জন্য, আমার পক্ষে সবচেয়ে ভাল কাজ করে তা হ'ল:

git show YOURHASH --no-color -- file1.txt file2.txt dir3 dir4 | git apply -3 --index -

git status

এটি ওপি যা চায় তাই করে। এটি যখন প্রয়োজন বিরোধের সমাধান করে, একইভাবে mergeএটি কীভাবে করে। এটি করে addকিন্তু commitআপনার নতুন পরিবর্তনগুলি নয়।


1

তুমি ব্যবহার করতে পার:

git diff <commit>^ <commit> -- <path> | git apply

স্বরলিপিটি <commit>^এর (প্রথম) পিতামাতার নির্দিষ্ট করে <commit>। অত: পর, এই পরিবর্তন কমান্ড করা পরিবর্তনগুলি পছন্দ <path>কমিট মধ্যে<commit>

মনে রাখবেন যে এটি এখনও কিছু করে না (যেমন git cherry-pickকরে)। সুতরাং আপনি যদি এটি চান তবে আপনাকে যা করতে হবে:

git add <path>
git commit
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.