Удалить ветви отслеживания больше не на удаленном
есть ли простой способ удалить все ветви отслеживания, удаленный эквивалент которых больше не существует?
пример:
филиалы (локальные и удаленные)
- мастер
- origin/master
- origin / bug-fix-a
- origin / bug-fix-b
- origin / bug-fix-c
локально, у меня только ветку master. Теперь мне нужно работать над Исправлена ошибка-a, поэтому я проверяю его, работаю над ним и нажмите изменения на пульте ДУ. Затем я делаю то же самое с Исправлена ошибка-b.
филиалы (локальные и удаленные)
- мастер
- Исправлена ошибка-a
- Исправлена ошибка-b
- origin/master
- origin / bug-fix-a
- origin / bug-fix-b
- origin / bug-fix-c
теперь у меня есть местные отделения мастер, Исправлена ошибка-a, Исправлена ошибка-b. Христос сопровождающий филиала объединит мои изменения в мастер и удалите все ветви, которые он уже объединил.
таким образом, текущее состояние теперь:
филиалы (локальные и удаленные)
- мастер
- Исправлена ошибка-a
- Исправлена ошибка-b
- origin/master
- origin / bug-fix-c
теперь я хотел бы вызвать некоторую команду для удаления ветвей (в этом случае Исправлена ошибка-a, Исправлена ошибка-b), которые больше не представлены в удаленном репозитории.
это будет что-то вроде существующей команды git remote prune origin
, но больше нравится git local prune origin
.
25 ответов
git remote prune origin
чернослив ветки не на удаленном.
git branch --merged
перечисляет ветви, которые были объединены в текущую ветвь.
xargs git branch -d
удаляет ветви, перечисленные на стандартном входе.
будьте осторожны, удаляя ветви, перечисленные git branch --merged
. Список может включать master
или другие ветви, которые вы предпочитаете не удалять.
чтобы дать себе возможность редактировать список перед удалением ветвей, вы можете сделать следующее в одном строка:
git branch --merged >/tmp/merged-branches && vi /tmp/merged-branches && xargs git branch -d </tmp/merged-branches
после команды
git fetch -p
удаляет удаленные ссылки, при запуске
git branch -vv
он покажет "ушел" в качестве удаленного статуса. Например,
$ git branch -vv
master b900de9 [origin/master: behind 4] Fixed bug
release/v3.8 fdd2f4e [origin/release/v3.8: behind 2] Fixed bug
release/v3.9 0d680d0 [origin/release/v3.9: behind 2] Updated comments
bug/1234 57379e4 [origin/bug/1234: gone] Fixed bug
таким образом, вы можете написать простой скрипт для удаления локальных ветвей, которые ушли пультов:
git fetch -p && for branch in `git branch -vv | grep ': gone]' | awk '{print }'`; do git branch -D $branch; done
большинство из этих ответов на самом деле не ответить на исходный вопрос. Я сделал кучу рытья и этой было наилучшим решением, которое я нашел. Вот несколько более полная версия этого ответа:
- Проверьте ветку по умолчанию. Обычно
git checkout master
- Run
git fetch -p && git branch -vv | awk '/: gone]/{print }' | xargs git branch -d
объяснение:
работает, обрезая ветви отслеживания, а затем удаляя локальные, которые показывают, что они " ушли" в git branch -vv
.
Примечания:
если ваш язык установлен на что-то другое, чем английский, вам нужно будет изменить gone
соответствующее слово. Ветви, которые являются только локальными, не будут затронуты. Ветви, которые были удалены на удаленном, но не были объединены, будут показывать уведомление, но не будут удалены на локальном. Если вы хотите удалить их, а также изменить -d
до -D
.
Кажется, решение здесь -https://stackoverflow.com/a/1072178/133986
короче, git remote prune
делает волшебство
я нашел ответ здесь: Как удалить все ветви git, которые были объединены?
git branch --merged | grep -v "\*" | xargs -n 1 git branch -d
убедитесь, что мы держим master
вы можете гарантировать, что master
, или любая другая ветвь, если на то пошло, не удаляется путем добавления другого grep
после первого. В этом случае вы бы пошли:
git branch --merged | grep -v "\*" | grep -v "YOUR_BRANCH_TO_KEEP" | xargs -n 1 git branch -d
Итак, если бы мы хотели сохранить master
, develop
и staging
например, мы бы go:
git branch --merged | grep -v "\*" | grep -v "master" | grep -v "develop" | grep -v "staging" | xargs -n 1 git branch -d
сделайте это псевдонимом
поскольку это немного долго, вы можете добавить псевдоним в свой .zshrc
или .bashrc
. Мой называется gbpurge
(для git branches purge
):
alias gbpurge='git branch --merged | grep -v "\*" | grep -v "master" | grep -v "develop" | grep -v "staging" | xargs -n 1 git branch -d'
перезагрузите .bashrc
или .zshrc
:
. ~/.bashrc
или
. ~/.zshrc
обычно я не отвечаю на вопрос, на который уже есть 16 ответов, но все остальные ответы неверны, а правильный ответ настолько прост. В вопросе говорится: "есть ли простой способ удалить все ветви отслеживания, удаленный эквивалент которых больше не существует?"
если "простой" означает не хрупкий, не опасный, и без опоры на инструменты, которые не все читатели будут иметь, то правильный ответ: нет.
некоторые ответы просты, но они не делают того, что было спросил. Другие делают то, что было предложено, но не просто: все полагаются на синтаксический анализ вывода Git (и фарфоровый вывод для загрузки в большинстве случаев) с помощью команд обработки текста или языков сценариев, которые могут отсутствовать в каждой системе.
дальнейшее чтение:https://stackoverflow.com/a/20107184/587365 и https://stackoverflow.com/a/26152574/587365
если вы хотите сделать это безопасно, для случая использования в вопросе (сбор мусора отслеживание ветвей, которые были удалены на сервере, но все еще существуют как локальные ветви) и только с командами git высокого уровня, вы должны
-
git fetch --prune
(илиgit fetch -p
, который является псевдонимом, илиgit prune remote origin
который делает то же самое без выборки, и, наверное, не то, что вы хотите большую часть времени). - обратите внимание на удаленные ветви, которые считаются удаленными. Или, чтобы найти их позже,
git branch -v
(любая осиротевшая ветка отслеживания будет отмечена "[пропащий.)"] -
git branch -d [branch_name]
на каждой осиротевшей ветви отслеживания
объяснения
чтобы понять, что происходит, вам нужно понять, что в ситуации отслеживания ветвей у вас есть не одна ветвь, а три. (И иметь в виду, что" ветвь " - это метка для указателя на фиксацию.)
филиала feature/X
, удаленный репозиторий будет иметь эту ветку и называть ее feature/X
. Ваш локальный репозиторий имеет бранч remotes/origin/feature/X
что означает: "это то, что сервер сказал мне, что его ветвь feature/X была, в последний раз, когда мы говорили", и, наконец, локальный репозиторий имеет ветвь feature/X
который указывает на вашу последнюю фиксацию и настроен на "отслеживание" remotes/origin/feature/X
, что означает, что вы можете тянуть и толкать, чтобы сохранить три выровненных.
в какой-то момент, кто-то удалил feature/X
на сервере. С этого момента вы остаетесь со своим местным feature/X
(который вы, вероятно, больше не хотите, так как работа над функция X предположительно завершена), и ваш remotes/origin/feature/X
что, безусловно, бесполезно, потому что его единственной целью было запомнить состояние ветви сервера.
и Git позволит вам автоматически убирать лишние remotes/origin/feature/X
-- вот что такое git fetch --prune
делает -- но по какой-то причине, это не позволяет автоматически удалить свой собственный feature/X
... даже если ваш feature/X
по-прежнему содержит потерянную информацию отслеживания, поэтому он имеет информацию для идентификации бывших ветвей отслеживания они были полностью объединены. (В конце концов, он может дать вы информация, которая позволяет выполнять операцию вручную самостоятельно.)
удалите все ветви, которые были объединены в master, но не пытайтесь удалить master:
git checkout master && git pull origin master && git fetch -p && git branch -d $(git branch --merged | grep master -v)
или добавить псевдоним:
alias gitcleanlocal="git checkout master && git pull origin master && git fetch -p && git branch -d $(git branch --merged | grep master -v)"
объяснение:
git checkout master
checkout master branch
git pull origin master
убедитесь, что локальная ветвь имеет все удаленные изменения объединены
git fetch -p
удалить ссылки на удаленные ветки, которые были удалены
git branch -d $(git branch master --merged | grep master -v)
удалить все ветви, которые были слился в master, но не пытайтесь удалить master сам
может быть полезно для некоторых, простой одной строки, чтобы очистить все локальные ветви, кроме master и develop
git branch | grep -v "master" | grep -v "develop" | xargs git branch -D
Я не думаю, что для этого есть встроенная команда, но безопасно сделать следующее:
git checkout master
git branch -d bug-fix-a
при использовании -d
, git откажется удалить ветку, если она не будет полностью объединена в HEAD
или его восходящая ветвь удаленного отслеживания. Таким образом, вы всегда можете зациклиться на выходе git for-each-ref
и попробуйте удалить каждую ветку. Проблема с этим подходом заключается в том, что я подозреваю, что вы, наверное, не хочу!--5--> быть удаленным только потому, что origin/bug-fix-d
содержит его история. Вместо этого вы можете создать скрипт примерно следующего вида:
#!/bin/sh
git checkout master &&
for r in $(git for-each-ref refs/heads --format='%(refname:short)')
do
if [ x$(git merge-base master "$r") = x$(git rev-parse --verify "$r") ]
then
if [ "$r" != "master" ]
then
git branch -d "$r"
fi
fi
done
предупреждение: я не тестировал этот скрипт - использовать только с осторожностью...
это удалит все объединенные локальные разветвленные, кроме локальной главной ссылки и используемой в настоящее время:
git branch --merged | grep -v "*" | grep -v "master" | xargs git branch -d
и это удалит все ветви, которые уже были удалены из удаленного репозитория, на который ссылается "origin", но все еще локально доступны в "пульты дистанционного управления / origin".
git remote prune origin
Решение Для Windows
Для Microsoft Windows Powershell:
git checkout master; git remote update origin --prune; git branch -vv | Select-String -Pattern ": gone]" | % { $_.toString().Trim().Split(" ")[0]} | % {git branch -d $_}
объяснение
git checkout master
переключаемся на ветку master
git remote update origin --prune
чернослив с удаленными филиалами
git branch -vv
получает подробный вывод всех ветвей (ссылка git)
Select-String -Pattern ": gone]"
получает только записи, где они были удалены с удаленного.
% { $_.toString().Trim().Split(" ")[0]}
показать ветку имя
% {git branch -d $_}
удаляет филиала
сопоставление шаблонов для "ушел" в большинстве других решений было немного страшно для меня. Чтобы быть более безопасным, это использует --format
флаг, чтобы вытащить статус отслеживания каждой ветви вверх по течению.
мне нужна версия для Windows, поэтому она удаляет все ветви, которые перечислены как "ушли" с помощью Powershell:
git branch --list --format "%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)" |
? { $_ -ne "" } |
% { git branch -D $_ }
в первой строке отображается имя локальных ветвей, восходящая ветвь которых "исчезла". Следующая строка удаляет пустые строки (которые выводятся для ветвей это не "ушло"), затем имя ветви передается команде для удаления ветви.
основываясь на информации выше, это сработало для меня:
git br -d `git br -vv | grep ': gone] ' | awk '{print }' | xargs`
Он удаляет все локальные ветви с помощью are ': gone] '
на пульте дистанционного управления.
еще-другой-ответ для кучи, тяжело вытягивая из https://stackoverflow.com/a/48411554/2858703 (что мне нравится, потому что это, похоже, устраняет любую двусмысленность о том, где gone]
будет соответствовать в git branch
output) , но добавление * Nix bent:
git branch --list --format "%(if:equals=[gone])%(upstream:track)%(then)%(refname)%(end)" \
| sed 's,^refs/heads/,,;/^$/d' \
| xargs git branch -D
у меня это завернуто в git-gone
скрипт на моем пути:
#!/usr/bin/env bash
action() {
${DELETE} && xargs git branch -D || cat
}
get_gone() {
git branch --list --format "%(if:equals=[gone])%(upstream:track)%(then)%(refname)%(end)" \
| sed 's,^refs/heads/,,;/^$/d'
}
main() {
DELETE=false
while [ $# -gt 0 ] ; do
case "" in
(-[dD] | --delete) DELETE=true ;;
esac
shift
done
get_gone | action
}
main "${@}"
NB - опция --format кажется довольно новой; мне нужно было обновить git с 2.10.что-то 2.16.3, чтобы получить его.
grep gone <(git branch -v) | cut -d ' ' -f 3 | xargs git branch -d
вышеуказанная команда может использоваться для извлечения ветвей, которые объединяются и удаляются в remote, и удаляет локальную ветвь, которая больше не доступна в remote
ничего из этого не было действительно правильным для меня. Я хотел что-то, что очистило бы все локальные ветви, которые отслеживали удаленную ветвь, на origin
, где удалена удаленная ветвь (gone
). Я не хотел удалять локальные ветви, которые никогда не были настроены для отслеживания удаленной ветви (т. е. моих локальных ветвей dev). Также я хотел простой однострочный, который просто использует git
или другие простые инструменты CLI, а не написание пользовательских сценариев. Я закончил тем, что использовал немного grep
и awk
в сделайте эту простую команду.
это в конечном итоге то, что закончилось в моем ~/.gitconfig
:
[alias]
prune-branches = !git remote prune origin && git branch -vv | grep ': gone]' | awk '{print }' | xargs -r git branch -D
здесь git config --global ...
команда для простого добавления этого как git prune-branches
:
git config --global alias.prune-branches '!git remote prune origin && git branch -vv | grep '"'"': gone]'"'"' | awk '"'"'{print }'"'"' | xargs -r git branch -d'
примечание: в команде config я использую до git branch
, а не -D
, как и в моей реальной конфигурации. Я использую -D
потому что я не хочу слышать, как ГИТ жалуется на непогребенные ветви. Вы можете эту функцию. Если да, просто используйте -D
вместо из -d
в конце этой команды config.
Я придумал этот сценарий. Он всегда держит ветви develop
, qa
, master
.
git-clear() {
git pull -a > /dev/null
local branches=$(git branch --merged | grep -v 'develop' | grep -v 'master' | grep -v 'qa' | sed 's/^\s*//')
branches=(${branches//;/ })
if [ -z $branches ]; then
echo 'No branches to delete...'
return;
fi
echo $branches
echo 'Do you want to delete these merged branches? (y/n)'
read yn
case $yn in
[^Yy]* ) return;;
esac
echo 'Deleting...'
git remote prune origin
echo $branches | xargs git branch -d
git branch -vv
}
это сработало для меня:
git branch -r | awk '{print }' | egrep -v -f /dev/fd/0 <(git branch -vv | grep origin) | awk '{print }' | xargs git branch -d
Я не уверен, как долго, но я использую git-up сейчас, который заботится об этом.
Я git up
и он начинает отслеживать новые ветви и удаляет старые.
чтобы было ясно, это не команда git из коробки -https://github.com/aanand/git-up
BtW она также прячет грязное дерево и делает перебазирует еще с просто git up
.
надеюсь, это будет полезно для кого-то
вот решение, которое я использую для рыбы оболочки. Протестировано на Mac OS X 10.11.5
, fish 2.3.0
и git 2.8.3
.
function git_clean_branches
set base_branch develop
# work from our base branch
git checkout $base_branch
# remove local tracking branches where the remote branch is gone
git fetch -p
# find all local branches that have been merged into the base branch
# and delete any without a corresponding remote branch
set local
for f in (git branch --merged $base_branch | grep -v "\(master\|$base_branch\|\*\)" | awk '/\s*\w*\s*/ {print }')
set local $local $f
end
set remote
for f in (git branch -r | xargs basename)
set remote $remote $f
end
for f in $local
echo $remote | grep --quiet "\s$f\s"
if [ $status -gt 0 ]
git branch -d $f
end
end
end
несколько замечаний:
убедитесь, что установлен правильный base_branch
. В этом случае я использую develop
как базовая ветвь, но это может быть что угодно.
эта часть очень важна: grep -v "\(master\|$base_branch\|\*\)"
. Это гарантирует, что вы не удалите master или базовую ветвь.
я использую git branch -d <branch>
в качестве дополнительной меры предосторожности, чтобы не удалить ветку, которая имеет не был полностью слит с восходящей или текущей головкой.
самый простой способ проверить-заменить git branch -d $f
С echo "will delete $f"
.
полагаю, я также должен добавить: используйте на свой страх и риск!
Я использую короткий метод, чтобы сделать трюк, я рекомендую вам сделать то же самое, как это может сэкономить несколько часов и дать вам больше видимости
просто добавьте следующий фрагмент кода в ваш .bashrc следующее (.bashprofile на macos).
git-cleaner() { git fetch --all --prune && git branch --merged | grep -v -E "\bmaster|preprod|dmz\b" | xargs -n 1 git branch -d ;};
- извлечь все пульты
- получить только объединенные ветви от git
- удалить из этого списка "защищенные / важные" ветки
- удалить остальные (e.g, чистые и Объединенные ветви)
вам придется отредактировать регулярное выражение grep, чтобы соответствовать вашим потребностям (здесь он предотвращает удаление master, preprod и dmz)
на основе Git Tip: Удаление Старых Локальных Ветвей, который похож на Джейсон.решение я реализовал собственную команду для этой цели под названием git gone использование Bash:
$ git gone
usage: git gone [-pndD] [<branch>=origin]
OPTIONS
-p prune remote branch
-n dry run: list the gone branches
-d delete the gone branches
-D delete the gone branches forcefully
EXAMPLES
git gone -pn prune and dry run
git gone -d delete the gone branches
git gone -pn
объединяет обрезку и перечисление" исчезнувших " ветвей:
$ git gone -pn
bport/fix-server-broadcast b472d5d2b [origin/bport/fix-server-broadcast: gone] Bump modules
fport/rangepos 45c857d15 [origin/fport/rangepos: gone] Bump modules
затем вы можете нажать на курок, используя git gone -d
или git gone -D
.
Примечания
- регулярное выражение, которое я использовал
"$BRANCH/.*: gone]"
здесь$BRANCH
обычноorigin
. Это, вероятно,не будет работать, если ваш выход Git локализован на французский и т. д. - Себастьян Визнер также портировал его на Rust для пользователей Windows. Это тоже называется git gone.
Я использую этот метод, чтобы иметь больше контроля.
git branch -D $(git branch | grep -v "master" | grep -v "develop")
это удалить любые ветви, не названные:master
или develop
.
это удалит все удаленные ветви, которые не присутствуют локально (в ruby):
bs = `git branch`.split; bs2 = `git branch -r | grep origin`.split.reject { |b| bs.include?(b.split('/')[1..-1].join('/')) }; bs2.each { |b| puts `git push origin --delete #{b.split('/')[1..-1].join('/')}` }
пояснил:
# local branches
bs = `git branch`.split
# remote branches
bs2 = `git branch -r | grep origin`.split
# reject the branches that are present locally (removes origin/ in front)
bs2.reject! { |b| bs.include?(b.split('/')[1..-1].join('/')) }
# deletes the branches (removes origin/ in front)
bs2.each { |b| puts `git push origin --delete #{b.split('/')[1..-1].join('/')}` }