Список всех локальных веток без удаленного
Проблема: я хочу удалить все локальные ветки, которые не имеют пульта. Достаточно просто передать имена ветвей в git branch -D {branch_name}
, но как мне получить этот список в первую очередь?
Например:
Я создаю новую ветку без пульта:
$ git co -b no_upstream
Я перечисляю все мои ветки, там только 1 с удаленным
$ git branch -a
master
* no_upstream
remotes/origin/HEAD -> origin/master
remotes/origin/master
Какую команду я могу запустить, чтобы получить no_upstream
в качестве ответа?
Я могу запустить git rev-parse --abbrev-ref --symbolic-full-name @{u}
, и это покажет, что у него нет пульта:
$ git rev-parse --abbrev-ref --symbolic-full-name @{u}
error: No upstream configured for branch 'no_upstream'
error: No upstream configured for branch 'no_upstream'
fatal: ambiguous argument '@{u}': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'
Но так как это ошибка, я не могу использовать ее или передавать другим командам. Я собираюсь использовать это как псевдоним сценария оболочки для git-delete-unbranched
или, возможно, сделать супер простой Gem вроде git-branch-delete-orphans
Ответы
Ответ 1
Недавно я обнаружил git branch -vv
, который является "очень многословной" версией команды git branch
.
Он выводит ветки вместе с удаленными ветвями, если они существуют, в следующем формате:
25-timeout-error-with-many-targets 206a5fa WIP: batch insert
31-target-suggestions f5bdce6 [origin/31-target-suggestions] Create target suggestion for team and list on save
* 54-feedback-link b98e97c [origin/54-feedback-link] WIP: Feedback link in mail
65-digest-double-publish 2de4150 WIP: publishing-state
Как только у вас есть этот отформатированный вывод, он так же прост, как проложить его через cut
и awk
, чтобы получить список:
git branch -vv | cut -c 3- | awk '$3 !~/\[/ { print $1 }'
Результаты в следующем выпуске:
25-timeout-error-with-many-targets
65-digest-double-publish
Часть cut
просто нормализует данные, удаляя первые два символа (включая *
) из вывода, прежде чем передать его на awk
.
Часть awk
печатает первый столбец, если в третьем столбце нет квадратной скобки.
Бонус: создайте псевдоним
Упростите выполнение, создав псевдоним в глобальном файле .gitconfig
(или везде):
[alias]
local-branches = !git branch -vv | cut -c 3- | awk '$3 !~/\\[/ { print $1 }'
Важно: обратная косая черта должна быть экранирована в псевдониме, иначе у вас будет недопустимый файл gitconfig.
Бонус: удаленная фильтрация
Если по какой-то причине у вас несколько пулов отслеживания для разных ветвей, достаточно просто указать, с какого пульта вы хотите проверить. Просто добавьте удаленное имя в шаблон awk. В моем случае это origin
, поэтому я могу это сделать:
git branch -vv | cut -c 3- | awk '$3 !~/\[origin/ { print $1 }'
Ответ 2
git branch
(без каких-либо параметров) перечислены только локальные ветки, но вы не знаете, отслеживают ли они удаленное отделение или нет.
Обычно эти локальные ветки должны быть удалены после объединения в master
(как показано в этой проблеме git -sweep):
git branch --merged master | grep -v master | xargs git branch -d
Это не так полно, как вы хотите, но это начало.
С --merged
будут перечислены только ветки, объединенные в именованный фиксатор (т.е. ветки, чьи концы достигают достижимости от именованного коммита).
Ответ 3
У меня похожая проблема. Я хочу удалить все локальные ветки, которые отслеживали удаленные ветки, которые теперь удалены. Я обнаружил, что git remote prune origin
было недостаточно, чтобы удалить ветки, которые я хочу уйти. Как только удаленный удален, я хочу, чтобы локальный также ушел. Вот что сработало для меня:
Из моего ~/.gitconfig
:
[alias]
prune-branches = !git remote prune origin && git branch -vv | grep ': gone]' | awk '{print $1}' | xargs -r git branch -d
EDIT:
В соответствии с запросом, здесь есть команда git config --global ...
для простого добавления этого как git prune-branches
:
git config --global alias.prune-branches '!git remote prune origin && git branch -vv | grep '"'"': gone]'"'"' | awk '"'"'{print $1}'"'"' | xargs -r git branch -d'
ПРИМЕЧАНИЕ: я изменил -d
на -D
в моей реальной конфигурации, потому что я не хочу, чтобы Git жаловался на неразделенные ветки. Вы можете также хотеть эту функциональность. Если это так, просто используйте -D
вместо -d
в конце этой команды.
Кроме того, FWIW, ваш глобальный конфигурационный файл почти всегда будет ~/.gitconfig
.
ОБНОВЛЕНИЕ: (исправление OSX)
Как написано, это не работает в OSX из-за использования xargs -r
(спасибо, Корни).
-r
запрещает xargs
запускать git branch -d
без имени ветки, что приведет к сообщению об ошибке "fatal: branch name required
". Если вы не возражаете против сообщения об ошибке, вы можете просто удалить аргумент -r
для xargs
и все готово.
Однако, если вы не хотите видеть сообщение об ошибке (и действительно, кто может вас винить), вам понадобится что-то еще, что проверяет наличие пустого канала. Если вы можете использовать ifne из moreutils. Вы вставите ifne
перед xargs
, что остановит запуск xargs
с пустыми данными. ПРИМЕЧАНИЕ: ifne
считает, что что-нибудь не является пустым, это включает пустые строки, поэтому вы все равно можете увидеть это сообщение об ошибке. Я не проверял это на OSX.
Вот эта строка git config
с ifne
:
git config --global alias.prune-branches '!git remote prune origin && git branch -vv | grep '"'"': gone]'"'"' | awk '"'"'{print $1}'"'"' | ifne xargs git branch -d'
Ответ 4
Позднее редактирование: лучше
git for-each-ref --format='%(refname:short) %(upstream)' refs/heads \
| awk '$2 !~/^refs\/remotes/'
в GNU/anything
for b in `git branch|sed s,..,,`; do
git config --get branch.$b.remote|sed Q1 && echo git branch -D $b
done
Если бы было больше, чем несколько ветвей, было бы лучше, используя comm -23
на выходе git branch|sed|sort
и git config -l|sed|sort
.
Ответ 5
Это работает для меня:
git branch -vv | grep -v origin
(если ваш пульт называется чем-то другим, кроме источника, замените это).
В этом списке перечислены все ветки, которые не отслеживают удаленный, что похоже на то, что вы ищете.
Ответ 6
Неверная реализация powershell: (если источник - ваш единственный удаленный)
@($branches = git br -r; git branch | %{ echo $_ | sed 's/..//' }) `
| %{ if (($branches | ss "origin/$_") -eq $null) { `
echo "git branch -D $_" `
} `
}
Ответ 7
Вот что я использовал в PowerShell с комментариями, чтобы объяснить, что он делает. В попытке прояснить, что происходит, я не использовал сокращенные команды PS. Не стесняйтесь сжимать его до желаемого уровня загадочности :)
$verboseList = @(git br -vv)
foreach ($line in $verboseList)
{
#get the branch name
$branch = [regex]::Match($line, "\s(\S+)\s").Captures.Groups[1].Value
#check if the line contains text to indicate if the remote is deleted
$remoteGone = $line.Contains(": gone]")
#check if the line does not contain text to indicate it is a tracking branch (i.e., it local)
$isLocal = !($line.Contains("[origin/"))
if ($remoteGone -or $isLocal)
{
#print the branch name
$branch
}
}
Ответ 8
Я синтезирую свою собственную команду git, чтобы получить ветки origin/***: gone
:
git remote prune origin && git branch -vv | cut -c 3- | grep ': gone]' | awk '{print $1}' | xargs -n1 -r echo git branch -d
git remote prune origin && git branch -vv
будет печатать ветки в подробном режиме
cut -c 3-
удалит самые первые символы
grep ': gone]'
будет печатать только удаленные ветки
awk '{print $1}'
напечатает название ветки
xargs -n1 -r echo git branch -d
напечатает команду git branch -d
для удаления ветвей (-n1 будет управлять одной командой за раз, -r, чтобы избежать выдачи команды, если ветки нет)
СОВЕТ: удалите команду "echo" для запуска команд вместо печати, я оставил это в команде, чтобы проверять команды перед выдачей в git.
СОВЕТ 2: выдайте git branch -D
тогда и только тогда, когда вы уверены, что хотите удалить неразделенные ветки