বাশ স্ক্রিপ্ট ব্যবহার করে সমস্ত গিট শাখাগুলির মাধ্যমে কীভাবে পুনরাবৃত্তি করা যায়


105

ব্যাশ স্ক্রিপ্টটি ব্যবহার করে আমি কীভাবে আমার সংগ্রহস্থলের সমস্ত স্থানীয় শাখাগুলির মধ্য দিয়ে পুনরাবৃত্তি করতে পারি। আমাকে পুনরাবৃত্তি করতে হবে এবং শাখা এবং কিছু দূরবর্তী শাখাগুলির মধ্যে কোনও পার্থক্য আছে কিনা তা পরীক্ষা করে দেখার দরকার। প্রাক্তন

for branch in $(git branch); 
do
    git log --oneline $branch ^remotes/origin/master;
done

উপরে বর্ণিত মত আমার কিছু করা দরকার, তবে আমি যে সমস্যার মুখোমুখি হচ্ছি তা হ'ল g (গিট শাখা) আমাকে ভান্ডারটিতে উপস্থিত শাখাগুলির পাশাপাশি সংগ্রহস্থল ফোল্ডারের ভিতরে ফোল্ডার দেয় gives

এটি কি এই সমস্যাটি সমাধান করার সঠিক উপায়? নাকি এটি করার অন্য কোনও উপায় আছে?

ধন্যবাদ



1
@ পাইহেনট্যাগি এটি লিঙ্কিত প্রশ্নের আগে লেখা হয়েছিল।
কোডডাম

যেমন: -for b in "$(git branch)"; do git branch -D $b; done
Abhi

উত্তর:


156

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

আপনি যে নদীর গভীরতানির্ণয় আদেশটি চান তা হ'ল প্রতিটি-রেফের জন্য গিট :

git for-each-ref --shell \
  --format='git log --oneline %(refname) ^origin/master' \
  refs/heads/

দ্রষ্টব্য: গিটার -রেভ-পার্সের নির্দিষ্টকরণ সংশোধন বিভাগে রেফ নাম অনুসন্ধানের পথে একাধিক জায়গার সাথে মিলে যাওয়ার remotes/কারণ হিসাবে অন্যান্য রেফ না থাকলে আপনার রিমোট রেফের উপসর্গের প্রয়োজন হবে না origin/mastersee (1) )। আপনি explictly অস্পষ্টতা এড়ানোর চেষ্টা হয়, তাহলে পূর্ণ; ref name সঙ্গে যান: refs/remotes/origin/master

আপনি এভাবে আউটপুট পাবেন:

git log --oneline 'refs/heads/master' ^origin/master
git log --oneline 'refs/heads/other' ^origin/master
git log --oneline 'refs/heads/pu' ^origin/master

আপনি এই আউটপুট sh এ পাইপ করতে পারেন ।

আপনি শেল কোড তৈরী ধারণা পছন্দ না হয়, আপনি বলিষ্ঠতার একটি বিট আপ দিতে পারে * এবং এই একটি করুন:

for branch in $(git for-each-ref --format='%(refname)' refs/heads/); do
    git log --oneline "$branch" ^origin/master
done

* শেলের শব্দ বিভাজন থেকে রেফের নামগুলি নিরাপদ হওয়া উচিত ( গিট-চেক-রেফ-ফর্ম্যাট (1) )। ব্যক্তিগতভাবে আমি পূর্ববর্তী সংস্করণ (উত্পন্ন শেল কোড) দিয়ে থাকব; আমি আরও আত্মবিশ্বাসী যে এটির সাথে অনুপযুক্ত কিছুই ঘটতে পারে না।

যেহেতু আপনি বাশ নির্দিষ্ট করেছেন এবং এটি অ্যারেগুলিকে সমর্থন করে তাই আপনি সুরক্ষা বজায় রাখতে পারেন এবং তবুও আপনার লুপের সাহস তৈরি করতে এড়াতে পারেন:

branches=()
eval "$(git for-each-ref --shell --format='branches+=(%(refname))' refs/heads/)"
for branch in "${branches[@]}"; do
    # …
done

আপনি $@যদি অ্যারে সমর্থন করে এমন শেল ব্যবহার না করে ( উপাদান set --শুরু করতে এবং set -- "$@" %(refname)উপাদান যোগ করতে) ব্যবহার করেন তবে এর সাথে আপনিও তেমন কিছু করতে পারেন ।


39
সিরিয়াসলি। এটি করার সহজ উপায় নেই?
জিম ফেল

4
তবে আমি যদি গিট শাখার ফিল্টারিং বিকল্পগুলির মধ্যে একটির মতো ব্যবহার করতে চাই --merged, তবে কি আমাকে গিট শাখায় যুক্তিটি নকল করতে হবে? এটি করার আরও ভাল উপায় থাকতে হবে।
থায়নে

3
Simplier সংস্করণ:git for-each-ref refs/heads | cut -d/ -f3-
Wid

4
@ উইড: বা, সহজভাবেgit for-each-ref refs/heads --format='%(refname)'
জন গীটজেন

5
@Thayne: এই প্রশ্ন পুরানো, কিন্তু গীত ভাবেন পরিশেষে সমস্যা সুরাহা হয়েছে: for-each-refএখন মত সব শাখা নির্বাচকরা সমর্থন --mergedএবং git branchএবং git tagএখন আসলে পরিপ্রেক্ষিতে বাস্তবায়িত git for-each-refতালিকা বিদ্যমান ক্ষেত্রে, নিজেই অন্তত। (নতুন শাখা এবং ট্যাগ তৈরি করা এর অংশ নয়, এবং হওয়া উচিত নয় for-each-ref)
টেরিক

50

এটি কারণ git branchএকটি নক্ষত্রের সাথে বর্তমান শাখা চিহ্নিত করে যেমন:

$ git branch
* master
  mybranch
$ 

সুতরাং $(git branch)উদাহরণস্বরূপ প্রসারিত হয় * master mybranchএবং তারপরে *বর্তমান ডিরেক্টরিতে ফাইলগুলির তালিকায় প্রসারিত হয়।

আমি প্রথমে নক্ষত্রটি প্রিন্ট না করার জন্য একটি সুস্পষ্ট বিকল্প দেখতে পাচ্ছি না; তবে আপনি এটি কেটে ফেলতে পারেন:

$(git branch | cut -c 3-)

4
আপনি যদি ডাবল-কোটে চারপাশে থাকেন তবে আপনি বাশকে নক্ষত্রটি প্রসারিত করা থেকে বিরত রাখতে পারেন - যদিও আপনি এখনও এটিকে আউটপুট থেকে সরাতে চাইবেন। যে কোনও বিন্দু থেকে একটি তারকাচিহ্ন সরানোর আরও শক্তিশালী উপায় হবে $(git branch | sed -e s/\\*//g)
নিক

2
সুন্দর, আমি আপনার 3-সমাধানটি সত্যিই পছন্দ করি ।
আন্দ্রে-নিকুলি পেট্রে

1
সামান্য সরল $(git branch | sed 's/^..//')
সেড

5
কিছুটা সহজ টিআর সংস্করণ:$(git branch | tr -d " *")
সিসিপিজ্জা

13

বাশ বিল্টিন, mapfileএই জন্য নির্মিত

সমস্ত গিট শাখা: git branch --all --format='%(refname:short)'

সমস্ত স্থানীয় গিট শাখা: git branch --format='%(refname:short)'

সমস্ত দূরবর্তী গিট শাখা: git branch --remotes --format='%(refname:short)'

সমস্ত গিট শাখা দিয়ে পুনরাবৃত্তি: mapfile -t -C my_callback -c 1 < <( get_branches )

উদাহরণ:

my_callback () {
  INDEX=${1}
  BRANCH=${2}
  echo "${INDEX} ${BRANCH}"
}
get_branches () {
  git branch --all --format='%(refname:short)'
}
# mapfile -t -C my_callback -c 1 BRANCHES < <( get_branches ) # if you want the branches that were sent to mapfile in a new array as well
# echo "${BRANCHES[@]}"
mapfile -t -C my_callback -c 1 < <( get_branches )

ওপি'র নির্দিষ্ট পরিস্থিতির জন্য:

#!/usr/bin/env bash


_map () {
  ARRAY=${1?}
  CALLBACK=${2?}
  mapfile -t -C "${CALLBACK}" -c 1 <<< "${ARRAY[@]}"
}


get_history_differences () {
  REF1=${1?}
  REF2=${2?}
  shift
  shift
  git log --oneline "${REF1}" ^"${REF2}" "${@}"
}


has_different_history () {
  REF1=${1?}
  REF2=${2?}
  HIST_DIFF=$( get_history_differences "${REF1}" "${REF2}" )
  return $( test -n "${HIST_DIFF}" )
}


print_different_branches () {
  read -r -a ARGS <<< "${@}"
  LOCAL=${ARGS[-1]?}
  for REMOTE in "${SOME_REMOTE_BRANCHES[@]}"; do
    if has_different_history "${LOCAL}" "${REMOTE}"; then
      # { echo; echo; get_history_differences "${LOCAL}" "${REMOTE}" --color=always; } # show differences
      echo local branch "${LOCAL}" is different than remote branch "${REMOTE}";
    fi
  done
}


get_local_branches () {
  git branch --format='%(refname:short)'
}


get_different_branches () {
  _map "$( get_local_branches )" print_different_branches
}


# read -r -a SOME_REMOTE_BRANCHES <<< "${@}" # use this instead for command line input
declare -a SOME_REMOTE_BRANCHES
SOME_REMOTE_BRANCHES=( origin/master remotes/origin/another-branch another-remote/another-interesting-branch )
DIFFERENT_BRANCHES=$( get_different_branches )

echo "${DIFFERENT_BRANCHES}"

উত্স: সমস্ত স্থানীয় গিট শাখা একটি তারকাচিহ্ন ছাড়াই তালিকাভুক্ত করুন


5

আমি উদাহরণ হিসাবে এটি পুনরাবৃত্তি:

for BRANCH in `git branch --list|sed 's/\*//g'`;
  do 
    git checkout $BRANCH
    git fetch
    git branch --set-upstream-to=origin/$BRANCH $BRANCH
  done
git checkout master;

4

আমি পরামর্শ দেব $(git branch|grep -o "[0-9A-Za-z]\+")যদি আপনার স্থানীয় শাখাগুলির নাম কেবল ডিজিট, অ্যাজ এবং / অথবা এজেড অক্ষর দ্বারা করা হয়


4

গৃহীত উত্তরটি সঠিক এবং সত্যই ব্যবহার হওয়া পদ্ধতির হওয়া উচিত, তবে শ্যাশগুলি কীভাবে কাজ করে তা বোঝার ক্ষেত্রে ব্যাশের সমস্যা সমাধান করা একটি দুর্দান্ত অনুশীলন। অতিরিক্ত টেক্সট ম্যানিপুলেশন না করে বাশ ব্যবহার করে এটি করার কৌশলটি শিট দ্বারা সম্পাদিত আদেশের অংশ হিসাবে গিট শাখার আউটপুট কখনই প্রসারিত না হয় তা নিশ্চিত করা। বাধা দেয় কি কখনো শেল সম্প্রসারণের (8 পদক্ষেপ) ফাইলের নাম সম্প্রসারণ মধ্যে বিস্তৃত হওয়া থেকে তারকাচিহ্ন (দেখুন http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_04.html )

গিট ব্রাঞ্চ আউটপুটকে লাইনে কাটাতে একটি রিড কমান্ড দিয়ে নির্মাণের সময় ব্যাশ ব্যবহার করুন । '*' আক্ষরিক চরিত্র হিসাবে পড়তে হবে। এটি মিলানোর জন্য কেস স্টেটমেন্টটি ব্যবহার করুন, মিলের প্যাটার্নগুলিতে বিশেষ মনোযোগ দিন।

git branch | while read line ; do                                                                                                        
    case $line in
        \*\ *) branch=${line#\*\ } ;;  # match the current branch
        *) branch=$line ;;             # match all the other branches
    esac
    git log --oneline $branch ^remotes/origin/master
done

বাশ কেস কনস্ট্রাক্ট এবং প্যারামিটার প্রতিস্থাপনের উভয় গ্রাহকের নক্ষত্রকে প্যাটার্ন মেলানো অক্ষর হিসাবে ব্যাখ্যা করে শেল প্রতিরোধ করতে ব্যাকস্ল্যাশগুলি সহ পালাতে হবে। স্পেসগুলিও পালিয়ে গেছে (টোকনাইজেশন প্রতিরোধের জন্য) কারণ আপনি আক্ষরিক '*' এর সাথে মিল করছেন।


4

আমার মতে মনে রাখার সবচেয়ে সহজ বিকল্প:

git branch | grep "[^* ]+" -Eo

আউটপুট:

bamboo
develop
master

গ্রেপ-এর বিকল্প (- শুধুমাত্র-মিলিয়ে) আউটপুটটিকে কেবল ইনপুটটির সাথে মিলে যায় to

যেহেতু স্থান বা * দুটিই গিট শাখার নামগুলিতে বৈধ নয়, এটি অতিরিক্ত অক্ষর ছাড়াই শাখাগুলির তালিকা প্রদান করে।

সম্পাদনা: আপনি যদি 'বিচ্ছিন্ন মাথা' অবস্থায় থাকেন তবে আপনাকে বর্তমান এন্ট্রি ফিল্টার করতে হবে:

git branch --list | grep -v "HEAD detached" | grep "[^* ]+" -oE


3

আমি কী করে শেষ করেছি, আপনার প্রশ্নের ক্ষেত্রে প্রয়োগ হয়েছে (এবং সিসিপিজার উল্লেখ দ্বারা অনুপ্রাণিত tr):

git branch | tr -d ' *' | while IFS='' read -r line; do git log --oneline "$line" ^remotes/origin/master; done

(আমি অনেকগুলি লুপ করার সময় ব্যবহার করি particular নির্দিষ্ট জিনিসের জন্য আপনি অবশ্যই একটি নির্দিষ্ট পয়েন্ট পরিবর্তনশীল নাম ["ব্রাঞ্চ" উদাহরণস্বরূপ ব্যবহার করতে চাইবেন), বেশিরভাগ সময় আমি কেবল ইনপুটটির প্রতিটি লাইন দিয়ে কিছু করার জন্য উদ্বিগ্ন Using 'শাখা' এর পরিবর্তে এখানে 'লাইন' পুনঃব্যবহারযোগ্যতা / পেশী মেমরি / দক্ষতার একটি মঞ্জুরি)


1

@ ফিনের উত্তর থেকে ধন্যবাদ (আপনাকে ধন্যবাদ!), নিম্নলিখিতগুলি আপনাকে একটি শাখা স্ক্রিপ্ট তৈরি না করে শাখাগুলির উপরে পুনরাবৃত্তি করতে দেবে। এটি যথেষ্ট শক্তিশালী, যতক্ষণ না শাখার নামে কোনও নতুন লাইন নেই :)

git for-each-ref --format='%(refname)' refs/heads  | while read x ; do echo === $x === ; done

লুপটি একটি সাব-শেলের মধ্যে চলতে থাকে, যা আপনি বর্তমান শেলটিতে অ্যাক্সেস করতে চান এমন শেল ভেরিয়েবল সেট না করেই সাধারণত ভাল থাকে। সেক্ষেত্রে আপনি পাইপের বিপরীতে প্রক্রিয়া বিকল্প ব্যবহার করুন:

while read x ; do echo === $x === ; done < <( git for-each-ref --format='%(refname)' refs/heads )

1

আপনি যদি এই অবস্থায় থাকেন:

git branch -a

* master

  remotes/origin/HEAD -> origin/master

  remotes/origin/branch1

  remotes/origin/branch2

  remotes/origin/branch3

  remotes/origin/master

এবং আপনি এই কোডটি চালান:

git branch -a | grep remotes/origin/*

for BRANCH in `git branch -a | grep remotes/origin/*` ;

do
    A="$(cut -d'/' -f3 <<<"$BRANCH")"
    echo $A

done        

আপনি এই ফলাফল পাবেন:

branch1

branch2

branch3

master

এটি আমার কাছে কম জটিল সমাধান দেখায় +1
অভি

এটি আমার পক্ষেও কাজ করেছিল:for b in "$(git branch)"; do git branch -D $b; done
অভি

1

সহজবোধ্য রাখো

ব্যাশ স্ক্রিপ্ট ব্যবহার করে লুপে শাখার নাম পাওয়ার সহজ উপায়।

#!/bin/bash

for branch in $(git for-each-ref --format='%(refname)' refs/heads/); do
    echo "${branch/'refs/heads/'/''}" 
done

আউটপুট:

master
other

1

Googlian এর উত্তর কিন্তু ব্যবহার না করেই জন্য

git for-each-ref --format='%(refname:lstrip=-1)' refs/heads/

1
শাখাগুলির মধ্যে যেমন একটি স্ল্যাশ রয়েছে তেমন এটি নামগতির শাখার নামগুলির জন্য কাজ করে না। এর অর্থ হ'ল ডিলেটাবোট দ্বারা নির্মিত শাখাগুলি, যা "dependabot / npm_and_yarn / typcript-3.9.5" এর মতো কিছু দেখায়, পরিবর্তে "টাইপসক্রিপ -3.9" হিসাবে উপস্থিত হবে।
ecbrodie

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