github pull - Come posso cancellare tutti i rami Git che sono stati uniti?




checkout push (25)

Uso il seguente script Ruby per eliminare i rami locali e remoti già uniti. Se lo faccio per un repository con più telecomandi e desidero solo eliminarlo, aggiungo semplicemente un'istruzione select all'elenco dei telecomandi per ottenere solo i telecomandi che voglio.

#!/usr/bin/env ruby

current_branch = `git symbolic-ref --short HEAD`.chomp
if current_branch != "master"
  if $?.exitstatus == 0
    puts "WARNING: You are on branch #{current_branch}, NOT master."
  else
    puts "WARNING: You are not on a branch"
  end
  puts
end

puts "Fetching merged branches..."
remote_branches= `git branch -r --merged`.
  split("\n").
  map(&:strip).
  reject {|b| b =~ /\/(#{current_branch}|master)/}

local_branches= `git branch --merged`.
  gsub(/^\* /, '').
  split("\n").
  map(&:strip).
  reject {|b| b =~ /(#{current_branch}|master)/}

if remote_branches.empty? && local_branches.empty?
  puts "No existing branches have been merged into #{current_branch}."
else
  puts "This will remove the following branches:"
  puts remote_branches.join("\n")
  puts local_branches.join("\n")
  puts "Proceed?"
  if gets =~ /^y/i
    remote_branches.each do |b|
      remote, branch = b.split(/\//)
      `git push #{remote} :#{branch}`
    end

    # Remove local branches
    `git branch -d #{local_branches.join(' ')}`
  else
    puts "No branches removed."
  end
end

Ho molti rami Git. Come faccio a eliminare i rami che sono già stati uniti? C'è un modo semplice per eliminarli tutti invece di eliminarli uno per uno?


Basta estendere la risposta di Adam un po ':

Aggiungi questo alla tua configurazione Git eseguendo git config -e --global

[alias]
    cleanup = "!git branch --merged | grep  -v '\\*\\|master\\|develop' | xargs -n 1 git branch -d"

E poi puoi cancellare tutti i rami uniti locali facendo una semplice git cleanup .


Non c'è alcun comando in Git che lo farà automaticamente. Ma puoi scrivere uno script che usa i comandi Git per darti quello che ti serve. Questo potrebbe essere fatto in molti modi a seconda del modello di ramificazione che stai utilizzando.

Se hai bisogno di sapere se un ramo è stato fuso in master, il seguente comando non produrrà output se myTopicBranch è stato unito (ovvero puoi eliminarlo)

$ git rev-list master | grep $(git rev-parse myTopicBranch)

È possibile utilizzare il comando ramo Git e analizzare tutti i rami in Bash e fare un ciclo for su tutti i rami. In questo ciclo controlli con il comando precedente se puoi cancellare il ramo o no.


Come eliminare i rami uniti nella console di PowerShell

git branch --merged | %{git branch -d $_.Trim()}

Vedi GitHub per Windows


Per eliminare i rami locali che sono stati uniti al ramo master, sto usando il seguente alias ( git config -e --global ):

cleanup = "!git branch --merged master | grep -v '^*\\|master' | xargs -n 1 git branch -D"

Sto usando git branch -D per evitare error: The branch 'some-branch' is not fully merged. messaggi mentre il mio checkout corrente è diverso dal master branch.


Se si utilizza un modello di diramazione come HubFlow o GitFlow, è possibile utilizzare questo comando per rimuovere i rami di feature unite:

git branch --merged | grep feature.* | grep -v "\*" | xargs -n 1 git branch -d


Usando Git versione 2.5.0:

git branch -d `git branch --merged`

Per eliminare tutti i rami su remoto già uniti:

git branch -r --merged | grep -v master | sed 's/origin\//:/' | xargs -n 1 git push origin

Nelle versioni più recenti di Git

git branch -r --merged | grep -v master | sed 's/origin\///' | xargs -n 1 git push --delete origin

Versione alias della risposta aggiornata di Adam :

[alias]
    branch-cleanup = "!git branch --merged | egrep -v \"(^\\*|master|dev)\" | xargs git branch -d #"

Inoltre, consulta questa risposta per suggerimenti pratici su come eseguire l'escape di alias complessi.


AGGIORNARE:

Puoi aggiungere altri rami da escludere come master e dev se il tuo flusso di lavoro ha quelli come possibile antenato. Di solito mi distacco da un tag "sprint-start" e master, dev e qa non sono antenati.

Per eliminare tutti i rami locali già uniti nel ramo attualmente ritirato:

git branch --merged | egrep -v "(^\*|master|dev)" | xargs git branch -d

Puoi vedere che master e dev sono esclusi nel caso in cui siano antenati.

È possibile eliminare un ramo locale unito con:

git branch -d branchname

Se non è unito, usa:

git branch -D branchname

Per eliminarlo dal telecomando nelle vecchie versioni di Git, utilizzare:

git push origin :branchname

Nelle versioni più recenti di Git usi:

git push --delete origin branchname

Una volta eliminato il ramo dal telecomando, è possibile eliminare i rami di monitoraggio remoto con:

git remote prune origin

o potare i singoli rami di localizzazione remota, come suggerisce l'altra risposta, con:

git branch -dr branchname

Spero che questo ti aiuti.


A partire dal 2018.07

Aggiungi questo alla sezione [alias] di ~/.gitconfig :

sweep = !"f() { git branch --merged | egrep -v \"(^\\*|master|dev)\" || true | xargs git branch -d; }; f"

Ora puoi semplicemente chiamare git sweep per eseguire la pulizia necessaria.


Per evitare di eseguire accidentalmente il comando da qualsiasi altro ramo rispetto al master, utilizzo il seguente script di bash. Altrimenti, eseguendo git branch --merged | grep -v "\*" | xargs -n 1 git branch -d git branch --merged | grep -v "\*" | xargs -n 1 git branch -d git branch --merged | grep -v "\*" | xargs -n 1 git branch -d da un ramo che è stato unito di off master potrebbe cancellare il ramo master.

#!/bin/bash

branch_name="$(git symbolic-ref HEAD 2>/dev/null)" ||
branch_name="(unnamed branch)"     # detached HEAD
branch_name=${branch_name##refs/heads/}

if [[ $branch_name == 'master' ]]; then
   read -r -p "Are you sure? [y/N] " response
   if [[ $response =~ ^([yY][eE][sS]|[yY])$ ]]; then
       git branch --merged | grep -v "\*" | xargs -n 1 git branch -d
   fi
else
   echo "Refusing to delete branches that are not merged into '$branch_name'. Checkout master first."
fi

Puoi usare lo strumento git-del-br .

git-del-br -a

Puoi installarlo tramite pip usando

pip install git-del-br

PS: sono l'autore dello strumento. Eventuali suggerimenti / feedback sono i benvenuti.


Io uso uno schema di denominazione esque git-flow, quindi questo funziona in modo molto sicuro per me:

git branch --merged | grep -e "^\s\+\(fix\|feature\)/" | xargs git branch -d

Cerca fondamentalmente i commit uniti che iniziano con la fix/ stringhe o con la feature/ .


Prova il seguente comando:

git branch -d $(git branch --merged | grep -vw $(git rev-parse --abbrev-ref HEAD))

Usando git rev-parse otterrà il nome del ramo corrente per poterlo escludere. Se hai ricevuto l'errore, significa che non ci sono rami locali da rimuovere.

Per fare lo stesso con i rami remoti (cambia origin con il tuo nome remoto), prova:

git push origin -vd $(git branch -r --merged | grep -vw $(git rev-parse --abbrev-ref HEAD) | cut -d/ -f2)

Se hai più telecomandi, aggiungi l' grep origin | prima di cut per filtrare solo l' origin .

Se il comando precedente non riesce, provare prima a eliminare i rami uniti di tracciamento remoto:

git branch -rd $(git branch -r --merged | grep -vw $(git rev-parse --abbrev-ref HEAD))

Quindi git fetch nuovamente il telecomando e usa di nuovo il precedente comando git push -vd .

Se lo stai usando spesso, ~/.gitconfig considerazione l'aggiunta di alias nel tuo file ~/.gitconfig .

Nel caso in cui hai rimosso alcuni rami per errore, usa git reflog per trovare i commit persi.


Scrivi uno script in cui Git controlla tutti i rami che sono stati uniti per diventare master.

Quindi fai il git checkout master .

Infine, elimina i rami uniti.

for k in $(git branch -ra --merged | egrep -v "(^\*|master)"); do
  branchnew=$(echo $k | sed -e "s/origin\///" | sed -e "s/remotes\///")
  echo branch-name: $branchnew
  git checkout $branchnew
done

git checkout master

for k in $(git branch -ra --merged | egrep -v "(^\*|master)"); do
  branchnew=$(echo $k | sed -e "s/origin\///" | sed -e "s/remotes\///")
  echo branch-name: $branchnew
  git push origin --delete $branchnew
done

Se desideri eliminare tutti i rami locali già integrati nel ramo in cui ti trovi al momento, ho creato un comando sicuro, in base alle risposte precedenti:

git branch --merged | grep -v \* | grep -v '^\s*master$' | xargs -t -n 1 git branch -d

Questo comando non influirà sul ramo attuale o sul ramo principale. Ti dirà anche cosa sta facendo prima di farlo, usando il flag -t di xargs.


Qui sotto la query funziona per me

for branch in  `git branch -r --merged | grep -v '\*\|master\|develop'|awk 'NR > 0 {print$1}'|awk '{gsub(/origin\//, "")}1'`;do git push origin --delete $branch; done

e questo filtra ogni dato ramo nella pipe di grep.

Funziona bene su http clone, ma non così bene per la connessione ssh.


Questo funziona anche per eliminare tutti i rami uniti tranne il master.

git branch --merged | grep -v '^* master$' | grep -v '^  master$' | xargs git branch -d


Script Python compatibile con Windoze (perché git-sweep bloccato sul repository Wesnoth):

#!/usr/bin/env python
# Remove merged git branches. Cross-platform way to execute:
#
#   git branch --merged | grep -v master | xargs git branch -d
#
# Requires gitapi - https://bitbucket.org/haard/gitapi
# License: Public Domain

import gitapi

repo = gitapi.Repo('.')
output = repo.git_command('branch', '--merged').strip()
for branch in output.split('\n'):
  branch = branch.strip()
  if branch.strip(' *') != 'master':
    print(repo.git_command('branch', '-d', branch).strip())

https://gist.github.com/techtonik/b3f0d4b9a56dbacb3afc


git branch --merged | grep -Ev '^(. master|\*)' | xargs -n 1 git branch -d git branch --merged | grep -Ev '^(. master|\*)' | xargs -n 1 git branch -d cancellerà tutti i rami locali tranne il ramo e / o il master estratti.

Ecco un articolo utile per coloro che desiderano comprendere questi comandi: Git Clean: Elimina rami già unificati, di Steven Harman .


La soluzione accettata è piuttosto buona, ma presenta il problema che elimina anche i rami locali che non erano stati ancora uniti in un telecomando.

Se guardi l'output di te vedrai qualcosa di simile

$ git branch --merged master -v
  api_doc                  3a05427 [gone] Start of describing the Java API
  bla                      52e080a Update wording.
  branch-1.0               32f1a72 [maven-release-plugin] prepare release 1.0.1
  initial_proposal         6e59fb0 [gone] Original proposal, converted to AsciiDoc.
  issue_248                be2ba3c Skip unit-for-type checking. This needs more work. (#254)
  master                   be2ba3c Skip unit-for-type checking. This needs more work. (#254)

I rami bla e issue_248 sono rami locali che verrebbero cancellati silenziosamente.

Ma puoi anche vedere la parola [gone] , che indica i rami che sono stati spinti su un telecomando (che ora è scomparso) e quindi denotano che i rami possono essere cancellati.

La risposta originale può quindi essere modificata in (divisa in multilinea per una lunghezza della linea più breve)

git branch --merged master -v | \
     grep  "\\[gone\\]" | \
     sed -e 's/^..//' -e 's/\S* .*//' | \
      xargs git branch -d

per proteggere i rami non ancora uniti. Non è necessario nemmeno il grepping per il master per proteggerlo, in quanto ha un origine remota e non si presenta come andato.


Ho usato la risposta di Adam per anni. Detto questo, ci sono alcuni casi in cui non si comportava come mi aspettavo:

  1. i rami che contenevano la parola "maestro" sono stati ignorati, ad esempio "notmaster" o "masterful", piuttosto che solo il ramo principale
  2. i rami che contenevano la parola "dev" sono stati ignorati, ad esempio "dev-test", piuttosto che solo il ramo dev
  3. eliminazione di rami raggiungibili dal HEAD del ramo corrente (ovvero, non necessariamente master)
  4. in stato HEAD distaccato, eliminando ogni ramo raggiungibile dal commit corrente

1 e 2 erano semplici da indirizzare, con solo una modifica alla regex. 3 dipende dal contesto di ciò che si desidera (vale a dire solo eliminare i rami che non sono stati uniti in master o contro il ramo corrente). 4 ha il potenziale di essere disastroso (anche se recuperabile con git reflog ), se involontariamente lo si è verificato in stato di TESTA distaccato.

Infine, volevo che tutto questo fosse in un one-liner che non richiedesse uno script separato (Bash | Ruby | Python).

TL; DR

Crea un "sweep" alias git che accetta un flag -f opzionale:

git config --global alias.sweep '!f(){ git branch --merged $([[ $1 != "-f" ]] \
&& git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)" \
| xargs git branch -d; }; f'

e invocilo con:

git sweep

o:

git sweep -f

La risposta lunga e dettagliata

È stato più facile per me creare un esempio di repository git con alcuni rami e mi impegno a testare il comportamento corretto:

Crea un nuovo repository git con un singolo commit

mkdir sweep-test && cd sweep-test && git init
echo "hello" > hello
git add . && git commit -am "initial commit"

Crea alcuni nuovi rami

git branch foo && git branch bar && git branch develop && git branch notmaster && git branch masterful
git branch --list
  bar
  develop
  foo
* master
  masterful
  notmaster

Comportamento desiderato: selezionare tutti i rami uniti tranne: master, develop o current

Il regex originale manca i rami "magistrale" e "notmaster":

git checkout foo
git branch --merged | egrep -v "(^\*|master|dev)"
  bar

Con la regex aggiornata (che ora esclude "develop" piuttosto che "dev"):

git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
bar
masterful
notmaster

Passa al ramo foo, fai un nuovo commit, quindi controlla un nuovo ramo, foobar, basato su foo:

echo "foo" > foo
git add . && git commit -am "foo"
git checkout -b foobar
echo "foobar" > foobar
git add . && git commit -am "foobar"

Il mio attuale ramo è foobar, e se rieseguo il comando precedente per elencare i rami che voglio cancellare, il ramo "foo" è incluso anche se non è stato fuso in master:

git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
  bar
  foo
  masterful
  notmaster

Tuttavia, se eseguo lo stesso comando su master, il ramo "foo" non è incluso:

git checkout master && git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
  bar
  masterful
  notmaster

E questo è semplicemente perché git branch --merged valore predefinito il HEAD del ramo corrente se non diversamente specificato. Almeno per il mio flusso di lavoro, non voglio eliminare i rami locali a meno che non siano stati uniti al master, quindi preferisco la seguente variante:

git checkout foobar
git branch --merged $(git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)"
  bar
  masterful
  notmaster

Stato HEAD distaccato

Affidarsi al comportamento predefinito di git branch --merged ha conseguenze ancora più significative nello stato di HEAD distaccato:

git checkout foobar
git checkout HEAD~0
git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
  bar
  foo
  foobar
  masterful
  notmaster

Questo avrebbe cancellato il ramo su cui mi trovavo, "foobar" e "foo", che non è certo il risultato desiderato. Con il nostro comando revisionato, tuttavia:

git branch --merged $(git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)"
  bar
  masterful
  notmaster

Una riga, inclusa l'eliminazione effettiva

git branch --merged $(git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)" | xargs git branch -d

Tutto racchiuso in un git alias "sweep":

git config --global alias.sweep '!f(){ git branch --merged $([[ $1 != "-f" ]] \
&& git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)" \
| xargs git branch -d; }; f'

L'alias accetta un flag facoltativo -f . Il comportamento predefinito consiste nell'eliminare solo i rami che sono stati uniti in master, ma il flag -f cancellerà i rami che sono stati uniti nel ramo corrente.

git sweep
Deleted branch bar (was 9a56952).
Deleted branch masterful (was 9a56952).
Deleted branch notmaster (was 9a56952).
git sweep -f
Deleted branch foo (was 2cea1ab).

Fonte: https://gist.github.com/sagarjethi/c07723b2f4fa74ad8bdf229166cf79d8

Elimina l'ultimo commit

Ad esempio il tuo ultimo commit

origine push git + aa61ab32 ^: master

Ora si desidera eliminare questo commit, quindi un modo semplice per farlo in seguito

passi

  1. Prima resetta il ramo al genitore del commit corrente

  2. Forza-spingilo al telecomando.

git reset HEAD^ --hard

git push origin -f

Per il commit particolare, vuoi reimpostare sta seguendo

git reset bb676878^ --hard

git push origin -f




git github version-control branch feature-branch