Jak stworzyć nową (i pustą!) Gałąź „root”?

143

Chciałbym zdefiniować nową gałąź „root” w tym repozytorium git. Przez gałąź "root" rozumiem gałąź, która jest całkowicie niezależna od wszystkich innych gałęzi w repozytorium 1 .

Niestety, nawet zatwierdzenie (nazwijmy to A) w samej podstawie drzewa zatwierdzeń repozytorium zawiera wiele plików (było to repozytorium zainicjowane w już dość dojrzałym projekcie).

Oznacza to, że nawet gdybym podał Ajako nową gałąź <start-point>, ta nowa gałąź nie zaczynałby się od „czystej karty”, ale raczej zawierałaby wszystkie zatwierdzone pliki A.

Czy jest jakiś sposób, żebym mógł stworzyć całkowicie nagą gałąź w tym repozytorium, <start-point>tak blisko, Ajak to możliwe?


1 BTW, nie jest to równoznaczne z utworzeniem nowego repozytorium. Oddzielne repozytoria byłyby mniej wygodne z wielu powodów.


EDYCJA : OK, oto co zrobiłem na podstawie odpowiedzi 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

Chociaż ta procedura jest nieco skomplikowana, wynikiem końcowym jest puste zatwierdzenie podstawowe, które może służyć jako <start-point>nowa gałąź „clean-slate”; wszystko co wtedy musiałbym zrobić to

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

W przyszłości zawsze będę tworzyć nowe repozytoria, takie jak to:

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

... tak, że pierwsze zatwierdzenie jest puste i zawsze dostępne do rozpoczęcia nowej niezależnej gałęzi. (Wiem, że byłby to bardzo rzadko potrzebny obiekt, ale łatwo jest go udostępnić).

kjo
źródło
2
@Anonymoose: Tak dla przypomnienia (zamiast debaty): Nie zgadzam się z twoją opinią.
kjo
1
Wydaje się, że istnieje znacznie prostsze rozwiązanie oparte na git rebase --onto, patrz stackoverflow.com/questions/645450/ ...
Stéphane Gourichon

Odpowiedzi:

233

Użyj --orphanpodczas tworzenia oddziału:

git checkout --orphan YourBranchName

Spowoduje to utworzenie nowej gałęzi z zerowymi zatwierdzeniami, jednak wszystkie Twoje pliki zostaną umieszczone w poczekalni. W tym momencie możesz je po prostu usunąć.
("usuń je": A git reset --hardopróżni indeks, pozostawiając puste drzewo robocze)

Spójrz na stronę podręcznika man do kasy, aby uzyskać więcej informacji na temat --orphan.

vcsjones
źródło
Czy to zasadniczo tworzy pustą kartę? Jak w, od zera? A może zachowuje wszystkie twoje poprzednie zmiany, ale nie w historii git?
Con Antonakos
4
@ConAntonakos To tworzy nową gałąź bez rodzica. Pozostałe gałęzie pozostają nienaruszone, wszystkie ich zmiany są zachowane.
fuz
13

Aby dodać do zaakceptowanej odpowiedzi - najlepszą praktyką powrotu do czystego stanu jest utworzenie początkowego pustego zatwierdzenia, aby można było łatwo zmienić bazę podczas konfigurowania gałęzi dla potomności. Poza tym, ponieważ chcesz mieć czysty stan, prawdopodobnie zatwierdziłeś pliki, których nie powinieneś, więc musisz usunąć je z indeksu. Mając to na uwadze, powinieneś:

$ 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
Mr_and_Mrs_D
źródło
2
Uważam, że od 2012 r. Nie jest to konieczne, ponieważ można zmienić bazę na roota .
Timmmm,
2

Jeśli używasz git 2.23 lub nowszego, możesz być przyzwyczajony do git switchigit restore zamiast git checkout. Jeśli tak, flaga jest taka sama, jak wspomniano w tej odpowiedzi .

git switch --orphan YourBranchHere
Kapitanie Man
źródło
1

Czy jest jakiś sposób, żebym mógł stworzyć całkowicie nagą gałąź w tym repozytorium.

Rzeczywiste polecenie do użycia (z Git 2.28+) to:

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

git switchjest dostępny od Git 2.23 (sierpień 2019) i zastępuje stare, mylące git checkoutpolecenie .

Ale poleciłbym Git 2.28 (Q3 2020), ponieważ git switch --discard-changes --orphanzostał zoptymalizowany w tej wersji.

Zobacz commit 8d3e33d , commit 8186128 (21 maja 2020) autorstwa briana m. carlson ( bk2204) .
(Scalone przez Junio ​​C Hamano - gitster- w zobowiązaniu ded44af , 09 czerwca 2020 r.)

builtin/checkout: uprość inicjalizację metadanych

Podpisał: brian m. Carlson
recenzji po: Derrick Stolee

Kiedy wzywamy init_checkout_metadataw reset_tree,chcemy przekazać identyfikator przedmiotu popełnić w kwestii tak, że może on być przekazany do filtrów lub jeśli nie jest popełnić, drzewa.

Przewidzieliśmy ten drugi przypadek, który może wystąpić w innym miejscu kodu kasy, ale nie może wystąpić w tym miejscu.

Jedynym przypadkiem, w którym nie mamy commit obiekt jest przy wywołaniu git switchz --orphan.

Co więcej, możemy tylko hit tej ścieżki kodu bez popełniania przedmiot dodatkowo albo --forcealbo --discard-changes.

W takim przypadku nie ma sensu inicjowanie metadanych pobierania za pomocą zatwierdzenia lub drzewa, ponieważ

  • (a) nie ma zatwierdzenia, tylko puste drzewo i
  • (b) nigdy nie wykorzystamy danych, ponieważ żadne pliki nie zostaną zamazane podczas sprawdzania gałęzi bez plików.

W tym przypadku podaj zerowy identyfikator obiektu, ponieważ potrzebujemy tylko wartości będącej prawidłowym wskaźnikiem.

Test:

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
VonC
źródło