Jak zmiażdżyć wszystkie commity git w jeden?

Jak ściągnąć całe repozytorium do pierwszego commita?

Mogę przełączyć się na pierwszy commit, ale zostawi mi to 2 commity. Czy istnieje sposób, aby odwołać się do commita przed pierwszym?

Author: Jacek Laskowski, 2009-11-01

15 answers

Być może najprostszym sposobem jest utworzenie nowego repozytorium z aktualnym stanem kopii roboczej. Jeśli chcesz zachować wszystkie komunikaty zatwierdzające, możesz najpierw wykonać git log > original.log, a następnie edytować je dla początkowej wiadomości zatwierdzającej w nowym repozytorium:

rm -rf .git
git init
git add .
git commit

Lub

git log > original.log
# edit original.log as desired
rm -rf .git
git init
git add .
git commit -F original.log
 118
Author: Pat Notz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-01 14:23:33

W najnowszych wersjach Gita, możesz użyć git rebase --root -i.

Dla każdego commita z wyjątkiem pierwszego, zmień pick na squash.

 497
Author: Jordan Lewis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-19 04:46:15

Update

Stworzyłem pseudonim git squash-all.
przykładowe użycie: git squash-all "a brand new start".

[alias]
  squash-all = "!f(){ git reset $(git commit-tree HEAD^{tree} -m \"${1:-A new start}\");};f"

Caveat: pamiętaj, aby dodać komentarz, w przeciwnym razie zostanie użyty domyślny komunikat commit "a new start".

Lub możesz utworzyć alias za pomocą następującego polecenia:

git config --global alias.squash-all '!f(){ git reset $(git commit-tree HEAD^{tree} -m "${1:-A new start}");};f'

One Liner

git reset $(git commit-tree HEAD^{tree} -m "A new start")

Uwaga : tutaj "A new start " jest tylko przykładem, możesz używać własnego języka.

TL;DR

No need to squash, użyj git commit-tree, aby utworzyć commit sierocy i przejść z nim.

Wyjaśnij

  1. Utwórz pojedynczy commit poprzez git commit-tree

    Co git commit-tree HEAD^{tree} -m "A new start" robi to:

    Tworzy nowy obiekt zatwierdzania na podstawie dostarczonego obiektu drzewa i emituje nowy identyfikator obiektu commit na standardowym wyjściu. Komunikat dziennika jest odczyt ze standardowego wejścia, chyba że podano opcje-m lub-F.

    Wyrażenie HEAD^{tree} oznacza obiekt drzewa odpowiadający HEAD, czyli końcówkę twojego obecny oddział. zobacz Tree-Objects i Commit-Objects.

  2. Zresetuj bieżącą gałąź do nowego commita

    Następnie git reset wystarczy zresetować bieżącą gałąź do nowo utworzonej Zatwierdź obiekt.

W ten sposób nic w przestrzeni roboczej nie jest dotykane, ani nie ma potrzeba rebase/squasha, co sprawia, że jest naprawdę szybki. Potrzebny czas nie ma znaczenia dla rozmiaru repozytorium czy głębi historii.

Wariant: Nowy Repo od a Szablon Projektu

Jest to przydatne do utworzenia "initial commit" w nowym projekcie przy użyciu innego repozytorium jako szablonu/archetype/seed/skeleton. Na przykład:

cd my-new-project
git init
git fetch --depth=1 -n https://github.com/toolbear/panda.git
git reset --hard $(git commit-tree FETCH_HEAD^{tree} -m "initial commit")

Pozwala to uniknąć dodawania repo szablonu jako zdalnego (origin lub innego) i zwija historię repo szablonu do początkowego zatwierdzenia.

 231
Author: ryenus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-17 13:35:33

Jeśli wszystko, co chcesz zrobić, to ściągnąć wszystkie commity do głównego commita, wtedy while

git rebase --interactive --root

Może działać, jest to niepraktyczne dla dużej liczby commitów (na przykład setek commitów), ponieważ operacja rebase prawdopodobnie będzie działać bardzo powoli, aby wygenerować interaktywną listę commitów edytora rebase, jak również uruchomić samą rebase.

Oto dwa szybsze i bardziej wydajne rozwiązania, gdy zgniatasz dużą liczbę commitów:

Alternatywne rozwiązanie #1: orphan branches

Możesz po prostu utworzyć nową, osieroconą gałąź na końcu (tj. najnowszym commicie) bieżącej gałęzi. Ta osierocona gałąź tworzy początkowy commit root z całkowicie nowego i oddzielnego drzewa historii commitów, co jest równoznaczne z zmiażdżeniem wszystkich commitów:

git checkout --orphan new-master master
git commit -m "Enter commit message for your new initial commit"

# Overwrite the old master branch reference with the new one
git branch -M new-master master

Dokumentacja:

Alternatywne rozwiązanie # 2: soft reset

Innym skutecznym rozwiązaniem jest aby po prostu użyć resetu mieszanego lub miękkiego do commita głównego <root>:

git branch beforeReset

git reset --soft <root>
git commit --amend

# Verify that the new amended root is no different
# from the previous branch state
git diff beforeReset

Dokumentacja:

 126
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-03 02:13:28
echo "message" | git commit-tree HEAD^{tree}

Spowoduje utworzenie osieroconego commita z drzewem głowy i wyświetli jego nazwę (SHA - 1) na standardowym wyjściu. Więc zresetuj swoją gałąź.

git reset SHA-1
 45
Author: kusma,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-23 15:04:21

Najprostszym sposobem jest użycie polecenia 'plumbing' update-ref do usunięcia bieżącej gałęzi.

Nie możesz użyć git branch -D, ponieważ posiada zawór bezpieczeństwa, który zatrzymuje usuwanie bieżącej gałęzi.

Spowoduje to powrót do stanu "początkowy commit", w którym możesz zacząć od nowego początkowego commita.

git update-ref -d refs/heads/master
git commit -m "New initial commit"
 32
Author: CB Bailey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-02 13:17:06

Oto jak skończyłem to robić, na wypadek, gdyby to działało dla kogoś innego:

Pamiętaj, że robienie takich rzeczy zawsze wiąże się z ryzykiem i nigdy nie jest złym pomysłem stworzenie gałęzi save przed uruchomieniem.

Zacznij od zalogowania

git log --oneline

Scroll to first commit, copy SHA

git reset --soft <#sha#>

Zastąp <#sha#> w / SHA skopiowane z dziennika

git status

Upewnij się, że wszystko jest zielone, w przeciwnym razie uruchom git add -A

git commit --amend

Zmień wszystkie bieżące zmiany na bieżące pierwsze commit

Teraz naciśnij tę gałąź, a ona nadpisze to, co tam jest.

 32
Author: Logan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-05 16:04:50

Czytałem coś o użyciu przeszczepów, ale nigdy nie badałem tego zbyt wiele.

W każdym razie, możesz ręcznie zmiażdżyć ostatnie 2 commity czymś takim:

git reset HEAD~1
git add -A
git commit --amend
 21
Author: R. Martinho Fernandes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-01 10:27:43

Najpierw połącz wszystkie commity w jeden commit używając git rebase --interactive. Teraz zostały Ci dwa commity do squasha. Aby to zrobić, przeczytaj dowolny z

 16
Author: Frerich Raabe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:27

Do squasha za pomocą przeszczepów

Dodaj plik .git/info/grafts, umieść tam hash commit, który chcesz stać się Twoim rootem

git log rozpocznie się od tego commita

To make it 'real' run git filter-branch

 3
Author: dimus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-05 19:12:11

"alternatywne rozwiązanie #1: orphan branches" mi pomaga.

" Git rebase --interactive --root " utknął w konflikcie plików gitignored.

 2
Author: sasha-ch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-26 13:17:19

Ta odpowiedź poprawia się na kilka powyższych (prosimy o głosowanie), zakładając, że oprócz utworzenia jednego commita (no-parents no-history), ty również chcesz zachować wszystkie dane commita tego commita:

  • Autor (imię i e-mail)
  • Data autora
  • Commiter (nazwa i e-mail)
  • Data zobowiązania
  • commit log message

Oczywiście commit-SHA nowego / pojedynczego commita zmieni się, ponieważ reprezentuje nowy (Nie-)historia, staje się parentless / root-commit.

Można to zrobić poprzez odczytanie git log i ustawienie niektórych zmiennych dla git commit-tree. Zakładając, że chcesz utworzyć pojedynczy commit z master w nowej gałęzi one-commit, zachowując powyższe dane commit:

git checkout -b one-commit master ## create new branch to reset
git reset --hard \
$(eval "$(git log master -n1 --format='\
COMMIT_MESSAGE="%B" \
GIT_AUTHOR_NAME="%an" \
GIT_AUTHOR_EMAIL="%ae" \
GIT_AUTHOR_DATE="%ad" \
GIT_COMMITTER_NAME="%cn" \
GIT_COMMITTER_EMAIL="%ce" \
GIT_COMMITTER_DATE="%cd"')" 'git commit-tree master^{tree} <<COMMITMESSAGE
$COMMIT_MESSAGE
COMMITMESSAGE
')
 1
Author: javabrett,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-28 17:27:50

Zwykle robię to tak:

  • Upewnij się, że wszystko jest zatwierdzone i zapisz najnowszy identyfikator zatwierdzenia na wypadek, gdyby coś poszło nie tak, lub utwórz oddzielną gałąź jako kopię zapasową

  • Uruchom git reset --soft `git rev-list --max-parents=0 --abbrev-commit HEAD`, aby zresetować głowę do pierwszego commita, ale pozostaw indeks bez zmian. Wszystkie zmiany od pierwszego commita będą teraz gotowe do zatwierdzenia.

  • Uruchom git commit --amend -m "initial commit", Aby zmienić commit do pierwszego commita I zmienić komunikat commit, lub jeśli chcesz zachowaj istniejący komunikat commit, możesz uruchomić git commit --amend --no-edit

  • Run git push -f to force push your changes

 0
Author: Kent Munthe Caspersen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-18 13:13:28

Tworzenie kopii zapasowej

git branch backup

Reset do podanego commita

git reset --soft <root>

Dodaj wszystkie pliki do stagingu

git add .

Zatwierdź bez aktualizacji wiadomości

git commit --amend --no-edit

Push new branch with squashed commits to repo

git push -f
 0
Author: David,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-19 14:12:55

W jednej linijce 6 słów

git checkout --orphan new_root_branch  &&  git commit
 0
Author: kyb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-15 21:57:00