Очистка старых удаленных веток git


696

Я работаю с двух разных компьютеров (A и B) и храню обычный git remote в каталоге dropbox.

Допустим, у меня есть две ветви: master и devel. Оба отслеживают свои удаленные аналоги origin / master и origin / devel.

Теперь, находясь на компьютере A, я удаляю ветку devel, на локальном и удаленном.

git push origin :heads/devel
git branch -d devel

Запустив git branch -aна компьютере А, я получаю следующий список веток.

  • мастер
  • Происхождение / HEAD
  • Происхождение / мастер

Работая git fetchна компьютере B, я могу удалить локальную ветку devel git branch -d devel, но не могу удалить удаленную ветку devel.

git push origin :heads/devel возвращает следующие сообщения об ошибках.

ошибка: невозможно отправить в неквалифицированное место назначения: возглавляет / proxy3d
Назначение ссылки refspec не соответствует существующему ref на удаленном сервере и не начинается с refs /, и мы не можем угадать префикс на основе исходного ref.
фатальный: удаленный конец неожиданно завис

git branch -a все еще перечисляет origin / devel в удаленных ветках.

Как я могу очистить удаленные ветви с компьютера B?


4
Один из тех, кто попробовал это, сказал мне, что репозитории git в папках Dropbox немного хрупки (но без дополнительных подробностей).
Торбьерн Равн Андерсен

5
@ ThorbjørnRavnAndersen, вероятно, потому, что вам нужно подождать, чтобы обеспечить его полную синхронизацию при фиксации, прежде чем вы сможете быть уверенным, что его можно безопасно использовать на другом компьютере (и даже тогда потребуется другая синхронизация).
13

Ответы:


1241

Во-первых, каков результат git branch -aна машине B?

Во- вторых, вы уже удалены heads/develна origin, так вот почему вы не можете удалить его из машины B.

Пытаться

git branch -r -d origin/devel

или

git remote prune origin

или

git fetch origin --prune

и не стесняйтесь добавлять --dry-runв конец своего gitутверждения, чтобы увидеть результат его выполнения без его фактического выполнения.

Документы для git remote pruneа git branch.


50
git remote prune originработал для меня => * [pruned] origin/my-old-branch
Хари Карам Сингх

126
git remote prune origin --dry-runпоказывает, что было бы удалено без этого.
Вольфрам Арнольд

31
git fetch origin --pruneбыло идеально, чтобы удалить удаленные ветви
Себастьян Барбьери

10
Если у вас есть локальная ветка, которая отслеживает удаленный удаленный компьютер, это ничего не удалит. Для тех, кто, кажется, git branch -vvследует, git branch -D branchnameи, наконец, чернослив является лучшим способом.
Роман Старков

7
Вы можете настроить автоматическое обрезание при извлечении / извлечении, установив следующую опцию:git config remote.origin.prune true
Патрик Джеймс МакДугл

101

Рассмотрим для запуска:

git fetch --prune

Регулярно в каждом репо удалять локальные ветви, которые отслеживали удаленную ветку, которая удалена (больше не существует в удаленном репозитории GIT).

Это может быть дополнительно упрощено

git config remote.origin.prune true

это per-repoнастройка, которая в будущем git fetch or git pullавтоматически обрезает любое будущее .

Чтобы настроить это для своего пользователя, вы также можете отредактировать глобальный .gitconfig и добавить

[fetch]
    prune = true

Тем не менее, рекомендуется сделать это с помощью следующей команды:

git config --global fetch.prune true

или применять его в масштабе всей системы (не только для пользователя)

git config --system fetch.prune true

14

Вот скрипт bash, который может сделать это за вас. Это модифицированная версия http://snippets.freerobby.com/post/491644841/remove-merged-branches-in-git скрипта. Моя модификация позволяет ему поддерживать различные удаленные местоположения.

#!/bin/bash

current_branch=$(git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/')
if [ "$current_branch" != "master" ]; then
  echo "WARNING: You are on branch $current_branch, NOT master."
fi
echo -e "Fetching merged branches...\n"

git remote update --prune
remote_branches=$(git branch -r --merged | grep -v '/master$' | grep -v "/$current_branch$")
local_branches=$(git branch --merged | grep -v 'master$' | grep -v "$current_branch$")
if [ -z "$remote_branches" ] && [ -z "$local_branches" ]; then
  echo "No existing branches have been merged into $current_branch."
else
  echo "This will remove the following branches:"
  if [ -n "$remote_branches" ]; then
echo "$remote_branches"
  fi
  if [ -n "$local_branches" ]; then
echo "$local_branches"
  fi
  read -p "Continue? (y/n): " -n 1 choice
  echo
  if [ "$choice" == "y" ] || [ "$choice" == "Y" ]; then
    remotes=`echo "$remote_branches" | sed 's/\(.*\)\/\(.*\)/\1/g' | sort -u`
# Remove remote branches
for remote in $remotes
do
        branches=`echo "$remote_branches" | grep "$remote/" | sed 's/\(.*\)\/\(.*\)/:\2 /g' | tr -d '\n'`
        git push $remote $branches 
done

# Remove local branches
git branch -d `git branch --merged | grep -v 'master$' | grep -v "$current_branch$" | sed 's/origin\///g' | tr -d '\n'`
  else
echo "No branches removed."
  fi
fi

1
Это сломалось на ветке под названием "origin / feature / mybranch", я не знаю почему.
Ставрос Корокитакис

Проблема в двух sedс. Заменить sed 's/\(.*\)\/\(.*\)/\1/g'наsed 's/\([^/]*\)\/\(.*\)/\1/g'
Benoît Latinier

14

Эта команда "пробный запуск" удалит все удаленные ( origin) объединенные ветви, кроме master. Вы можете изменить это или добавить дополнительные ветки после master:grep -v for-example-your-branch-here |

git branch -r --merged | 
  grep origin | 
  grep -v '>' | 
  grep -v master | 
  xargs -L1 | 
  awk '{sub(/origin\//,"");print}'| 
  xargs git push origin --delete --dry-run

Если это выглядит хорошо, удалите --dry-run. Кроме того, вы можете сначала проверить это на развилке.


Ницца. Мой твик использует perl вместо 1-го xargs + awk: git branch -r --merged | grep origin | grep -v '>' | grep -v мастер | perl -lpe '($ junk, $ _) = split (/ \ //, $ _, 2)' | xargs git push origin --delete
Эндрю

6

Если git branch -rпоказано много веток удаленного отслеживания, которые вас не интересуют, и вы хотите удалить их только из локальной сети, используйте следующую команду:

git branch -r | grep -Ev 'HEAD|master|develop'  | xargs -r git branch -rd

Более безопасной версией было бы удалить только объединенные:

git branch -r --merged | grep -Ev 'HEAD|master|develop'  | xargs -r git branch -rd

Это может быть полезно для больших проектов, где вам не нужны ветви функций других товарищей по команде, но есть много веток удаленного отслеживания, извлеченных из исходного клона.

Однако одного этого шага недостаточно, потому что эти удаленные ветви удаленного отслеживания будут возвращаться позже git fetch.

Чтобы прекратить получать эти ветки удаленного отслеживания, вам нужно явно указать ссылки для извлечения в .git / config :

[remote "origin"]
  # fetch = +refs/heads/*:refs/remotes/origin/*    ### don't fetch everything
  fetch = +refs/heads/master:refs/remotes/origin/master
  fetch = +refs/heads/develop:refs/remotes/origin/develop
  fetch = +refs/heads/release/*:refs/remotes/origin/release/*

В приведенном выше примере мы только извлечь master, developи освободить ветви, не стесняйтесь , чтобы адаптироваться , как вам нужно.


1
Спасибо, первая команда сработала для меня. Вы также можете выбрать только одну ветку git fetch origin branchnameили создать псевдоним, например, ft = "!f() { git fetch origin $(git rev-parse --abbrev-ref HEAD);}; f"выбрать только текущую ветку (мой личный фаворит). Приветствия.
GiovanyMoreno

Может быть, ОТ, но что означает -rфлаг? Я вижу, xargsесть -Rаргумент, но не нашел ничего о -r. Я имею в виду, теоретически, если я правильно помню, как xargsработает, даже без -rнего должно работать.
Альдо 'xoen' Джамбеллука

Мне нравится этот ответ. Пару заметок (на самом деле утверждающих очевидное). Можно «просмотреть», какие ветви будут удалены, удалив последний канал и последнюю команду | xargs git branch -d. Кроме того, удаляя -roption ( --remotes), git branch -dмы очищаем только локальные ветви (чего может быть достаточно, учитывая, что по умолчанию git branchудаленные ветви не отображаются).
Альдо 'xoen' Джамбеллука

Спасибо! Это было именно то, что мне было нужно. Другие решения предлагают перенести удаленные локальные ветви на пульт, чтобы удалить их там, но это не помогает, когда пульт удален или больше не существует. Этот подход удалил локальные ссылки на удаленные ветви, к которым у меня больше нет доступа.
предостережение жуков

@aldo, о xargs -r, а именно --no-run-if-empty, это расширение GNU означает, вот хорошее объяснение .
ryenus

4

Удаление всегда является сложной задачей и может быть опасным !!! Поэтому сначала выполните следующую команду, чтобы увидеть, что произойдет:

git push --all --prune --dry-run

Сделав так, как описано выше, gitвы получите список того, что произойдет, если будет выполнена команда ниже.

Затем выполните следующую команду, чтобы удалить все ветви из удаленного репо, которых нет в вашем локальном репо:

git push --all --prune

10
Эта команда кажется опасной ... Она сумела удалить то, что я хотела (и не смогла сделать хотя бы четыре ответа выше). Но он также удалил четыре других ветки разработки. Git абсолютно отстой ...
Jww

2
Эти ветки, должно быть, не были на вашем месте. Однако еще не все потеряно. Git commit, Git reflog и затем git reset --hard <контрольная сумма>. Вы можете буквально любой коммит (иначе сохранить) и другие с этим. Ветвь - это просто метка, удаление метки не удаляет сохранение ... оно всегда будет иметь контрольную сумму. Дайте мне знать, если я могу помочь
Тимоти LJ Стюарт

3
Конечно, вы захотите восстановить их довольно быстро, так как сборщик мусора в git со временем удалит коммиты, на которые не ссылаются ветки.
Андрей

1
Хорошо добавить -n(пробный запуск) к этой команде, чтобы вы могли просмотреть изменения, а затем, если все в порядке, вызвать их снова без -n.
mati865 11.11.16

1
Согласитесь с @GuiWeinmann - это слишком опасно, особенно без специального выноски, чтобы хотя бы сначала запустить его в пробном режиме.
Вивек М. Чавла,

2

Вот как это сделать с SourceTree (v2.3.1):
1. Нажмите «Получить»
2. Установите флажок «Удалить ветви отслеживания ...»
3. Нажмите OK
4. 😀

введите описание изображения здесь


1

Я должен добавить ответ здесь, потому что другие ответы либо не охватывают мой случай, либо излишне сложны. Я использую github с другими разработчиками, и я просто хочу, чтобы все локальные ветки, удаленные (возможно, объединенные и) удаленные из github PR, были удалены за один раз с моей машины. Нет, такие вещи, как git branch -r --mergedветки, которые не были объединены локально, или ветви, которые вообще не были объединены (заброшены) и т. Д., Поэтому необходимо другое решение.

Во всяком случае, первым шагом я получил его из других ответов:

git fetch --prune

Пробный git remote prune originказалось , что это будет делать то же самое в моем случае, так что я пошел с самой короткой версией , чтобы сохранить его простым.

Теперь a git branch -vдолжен пометить ветви, удаленные из которых удалены [gone]. Поэтому все, что мне нужно сделать, это:

git branch -v|grep \\[gone\\]|awk '{print $1}'|xargs -I{} git branch -D {}

Так просто, он удаляет все, что я хочу для приведенного выше сценария.

Менее распространенный xargsсинтаксис таков, что он также работает на Mac и BSD в дополнение к Linux. Осторожно, эта команда не является пробной, поэтому она принудительно удалит все ветви, отмеченные как [gone]. Очевидно, что это git - ничто не уходит навсегда, если вы видите удаленные ветки, которые, как вы помните, хотели сохранить, вы всегда можете восстановить их (вышеприведенная команда перечислит их хэш при удалении, поэтому все просто git checkout -b <branch> <hash>.


0
# First use prune --dry-run to filter+delete the local branches
git remote prune origin --dry-run \
  | grep origin/ \
  | sed 's,.*origin/,,g' \
  | xargs git branch -D

# Second delete the remote refs without --dry-run
git remote prune origin

Удалите те же самые ветки из локальных и удаленных ссылок (в моем примере из origin).

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.