Como criar um novo (e vazio!) Ramo "raiz"?


135

Eu gostaria de definir um novo ramo "raiz" neste repositório git. Por ramo "raiz", quero dizer um ramo que é totalmente independente de todos os outros ramos no repositório 1 .

Infelizmente, mesmo o commit (vamos chamá-lo A) na base da árvore de commit do repositório contém muitos arquivos (este foi um repositório que foi inicializado em um projeto já bastante maduro).

Isso significa que, mesmo que eu Adesse como o novo ramo <start-point>, esse novo ramo não seria iniciado a partir de uma "lista limpa", mas conteria todos os arquivos que foram confirmados A.

Existe alguma maneira de criar uma ramificação completamente vazia neste repositório, o <start-point>mais próximo Apossível?


1 BTW, isso não é equivalente a criar um novo repositório. Os repositórios separados seriam menos convenientes por várias razões.


EDIT : OK, foi o que fiz, com base na resposta do vcsjones :

# save rev of the current earliest commit
OLDBASE=$(git rev-list --max-parents=0 HEAD)

# create a new orphan branch and switch to it
git checkout --orphan newbranch
# make sure it's empty
git rm -rf .

# create a new empty commit in the new branch, and
# save its rev in NEWBASE
git commit --allow-empty -m 'base commit (empty)'
NEWBASE=$(git rev-list HEAD)

# specify $NEWBASE as the new parent for $OLDBASE, and
# run filter-branch on the original branch
echo "$OLDBASE $NEWBASE" > .git/info/grafts
git checkout master
git filter-branch

# NOTE: this assumes that the original repo had only one
# branch; if not, a git-filter-branch -f <branch> command
# need to be run for each additional branch.

rm .git/info/grafts

Embora esse procedimento esteja um pouco envolvido, o resultado final é uma confirmação de base vazia que pode servir como <start-point>para qualquer nova "ramificação limpa"; tudo o que eu preciso fazer então é

git checkout -b cleanslate $(git rev-list --max-parents=0 HEAD)

No futuro, sempre criarei novos repositórios como este:

git init
git commit --allow-empty -m 'base commit (empty)'

... para que o primeiro commit esteja vazio e sempre disponível para iniciar uma nova ramificação independente. (Sei que seria uma instalação muito raramente necessária, mas é muito fácil torná-la disponível.)



1
@Anonymoose: Apenas para constar (em vez de debate): Não concordo com a sua opinião.
KJo

1
Parece haver uma solução muito mais simples com base em git rebase --onto, veja stackoverflow.com/questions/645450/…
Stéphane Gourichon

Respostas:


223

Use --orphanao criar a ramificação:

git checkout --orphan YourBranchName

Isso criará uma nova ramificação com zero confirmações, no entanto, todos os seus arquivos serão testados. Nesse ponto, você pode apenas removê-los.
("remova-os": A git reset --hardesvaziará o índice, deixando você com uma árvore de trabalho vazia)

Dê uma olhada na página de manual do checkout para obter mais informações sobre --orphan.


Isso cria essencialmente uma lousa em branco? Como do zero? Ou mantém todas as alterações anteriores, mas não apenas no histórico do git?
Con Antonakos

4
@ConAntonakos Isso cria uma nova ramificação sem um pai. Os outros ramos não são afetados, todas as alterações são mantidas.
fuz 15/10/16

11

Para adicionar à resposta aceita - a melhor prática para reverter para o estado limpo é criar um commit vazio inicial, para que você possa refazer facilmente enquanto configura suas ramificações para a posteridade. Além disso, como você deseja um estado limpo, é provável que você tenha confirmado arquivos que não deveria, então você deve removê-los do índice. Com isso em mente, você deve:

$ git checkout --orphan dev2
Switched to a new branch 'dev2'
$ git reset # unstage all the files, you probably don't want to commit all of them
$ git commit --allow-empty -m 'Initial empty commit'
[dev2 (root-commit) a515c28] Initial empty commit

1
Eu acredito que isso não é necessário a partir de 2012, porque você pode se recuperar novamente .
Timmmm


1

Existe alguma maneira de criar uma ramificação completamente vazia neste repositório.

O comando real a ser usado (com o Git 2.28+) é:

git switch --discard-changes --orphan newBranch
# or
git switch -f --orphan newBranch

git switchestá disponível no Git 2.23 (agosto de 2019) e substitui o antigo git checkoutcomando confuso .

Mas eu recomendaria o Git 2.28 (terceiro trimestre de 2020), porque git switch --discard-changes --orphanfoi otimizado nessa versão.

Consulte commit 8d3e33d , commit 8186128 (21 de maio de 2020) por brian m. Carlson ( bk2204) .
(Mesclado por Junio ​​C Hamano - gitster- em commit ded44af , 09 jun 2020)

builtin/checkout: simplifique a inicialização de metadados

Assinado por: brian m. carlson
Analisado por: Derrick Stolee

Quando chamamos init_checkout_metadataem reset_tree,que quer passar o ID do objeto da comprometer em questão para que ele possa ser passado para filtros, ou se não houver cometer, a árvore.

Antecipamos esse último caso, que pode ocorrer em outra parte do código de pagamento, mas não pode ocorrer aqui.

O único caso em que não temos um objeto de confirmação é ao invocar git switchcom --orphan.

Além disso, só podemos atingir esse caminho de código sem um objeto de confirmação adicionalmente com --forceou --discard-changes.

Nesse caso, não faz sentido inicializar os metadados do checkout com uma confirmação ou árvore porque

  • (a) não há confirmação, apenas a árvore vazia e
  • (b) nunca usaremos os dados, pois nenhum arquivo será manchado ao fazer check-out de uma ramificação sem arquivos.

Passe o ID do objeto com todos os zeros nesse caso, pois precisamos apenas de algum valor que seja um ponteiro válido.

Teste:

git switch master
echo foo >foo.txt
git switch --discard-changes --orphan new-orphan2
git ls-files >tracked-files
# test_must_be_empty tracked-files
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.