Список всех локальных веток без удаленного

Проблема: я хочу удалить все локальные ветки, которые не имеют пульта. Достаточно просто передать имена ветвей в 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 тогда и только тогда, когда вы уверены, что хотите удалить неразделенные ветки