Frage

Ich habe gefragt, bevor über, wie Sie die ersten beiden Commits zerquetschen in einer Git-Repository.

Während die Lösungen ziemlich interessant sind und nicht wirklich als Geist-Warping wie einige andere Dinge in git, sind sie immer noch ein wenig um den berühmten Sack verletzt, wenn die Prozedur oft entlang der Entwicklung des Projekts wiederholen müssen .

Also, würde ich eher durch den Schmerz gehe nur einmal, und dann in der Lage sein, für immer das interaktive Standardfütterungsmaterial zu verwenden.

Was ich tun möchte, ist, begehen eine leere Anfangs haben, dass ausschließlich für den Zweck besteht die erste zu sein. Kein Code, kein gar nichts. Nur Platz wegnimmt, so kann es die Basis für Fütterungsmaterial sein.

Meine Frage ist dann, ein vorhandenes Repository mit, wie gehe ich über ein neues Einsetzen leer vor dem ersten begehen, und verschieben alle anderen nach vorn?

War es hilfreich?

Lösung

Mid-2017 Antwort

ein neues völlig leer begehen ohne Nebenwirkungen erstellen wird wahrscheinlich am besten durch Git Sanitär direkt verwenden. Doing es auf diese Weise irgendwelche Nebenwirkungen vermeidet: keine die Arbeitskopie oder den Index zu berühren, keine temporären Zweige zu reinigen, etc. Also:

  1. So erstellen Sie eine verpflichten, müssen wir einen Verzeichnisbaum für sie, so schaffen wir eine leere erste:

    tree=`git hash-object -wt tree --stdin < /dev/null`
    
  2. Jetzt können wir wickeln begehen drum herum:

    commit=`git commit-tree -m 'root commit' $tree`
    
  3. Und jetzt können wir auf die rebase:

    git rebase --onto $commit --root master
    

Und das ist es. Sie können das Ganze in einen Liner eines neu anordnen, wenn Sie Ihre Schale gut genug kennen.

(N. B .: in der Praxis ich jetzt filter-branch verwenden würde. Sei das bearbeitet in später.)


Historische Antwort (nach anderen Antworten verwiesen)

Hier ist eine sauberere Implementierung der gleichen Lösung, da sie ohne die Notwendigkeit, arbeiten ein zusätzliches Repository zu erstellen, futz um mit Fernbedienungen und korrigieren freistehenden Kopf:

# first you need a new empty branch; let's call it `newroot`
git checkout --orphan newroot
git rm -rf .

# then you apply the same steps
git commit --allow-empty -m 'root commit'
git rebase --onto newroot --root master
git branch -d newroot

Voila, Sie haben auf master enden mit seiner Geschichte neu geschrieben eine leere Wurzel enthalten begehen.


NB .: auf alte Versionen von Git, die den --orphan Schalter checkout fehlt, müssen Sie die Sanitär einen leeren Zweig erstellen:

git symbolic-ref HEAD refs/heads/newroot
git rm --cached -r .
git clean -f -d

Andere Tipps

Merge von Aristoteles Pagaltzis des und Uwe Kleine-Königs der Antworten und Richard Bronosky Kommentar.

git symbolic-ref HEAD refs/heads/newroot
git rm --cached -r .
git clean -f -d
# touch .gitignore && git add .gitignore # if necessary
git commit --allow-empty -m 'initial'
git rebase --onto newroot --root master
git branch -d newroot

(nur setzt alles an einem Ort)

Ich mag Aristoteles 'Antwort. Fand aber, dass für ein großes Repository (> 5000 Commits) -Filter-Zweig funktioniert besser als aus mehreren Gründen rebase 1) es ist schneller 2) es erfordert keine menschliche Intervention, wenn es ein Merge-Konflikt. 3) es kann die Tags neu zu schreiben - sie bewahren. Beachten Sie, dass Filter-Zweig funktioniert, weil es keine Frage über den Inhalt jeder ist commit -. Es ist genau die gleiche wie vor dieser ‚rebase‘

Meine Schritte sind:

# first you need a new empty branch; let's call it `newroot`
git symbolic-ref HEAD refs/heads/newroot
git rm --cached -r .
git clean -f -d

# then you apply the same steps
git commit --allow-empty -m 'root commit'

# then use filter-branch to rebase everything on newroot
git filter-branch --parent-filter 'sed "s/^\$/-p <sha of newroot>/"' --tag-name-filter cat master
Hinweis

, dass die '--tag-name-Filter cat' Optionen bedeutet, dass die Tags neu geschrieben werden, um die neu geschaffenen Commits zu zeigen.

Ich habe Stücke von Aristoteles und Kent Antwort erfolgreich:

# first you need a new empty branch; let's call it `newroot`
git checkout --orphan newroot
git rm -rf .
git commit --allow-empty -m 'root commit'
git filter-branch --parent-filter \
'sed "s/^\$/-p <sha of newroot>/"' --tag-name-filter cat -- --all
# clean up
git checkout master
git branch -D newroot
# make sure your branches are OK first before this...
git for-each-ref --format="%(refname)" refs/original/ | \
xargs -n 1 git update-ref -d

Dies wird neu schreiben auch alle Zweige (nicht nur master) zusätzlich zu den Tags.

git rebase --root --onto $emptyrootcommit

sollte den Trick leicht

Ich war richtig aufgeregt und schrieb eine ‚idempotent‘ -Version dieses schönen Skript ... es wird die gleiche leer begehen immer einfügen, und wenn Sie es zweimal ausführen, wird es nicht Ihre Hashes jedes Mal begehen ändern. So, hier ist mein nehmen auf git-Insert-empty-root :

#!/bin/sh -ev
# idempotence achieved!
tmp_branch=__tmp_empty_root
git symbolic-ref HEAD refs/heads/$tmp_branch
git rm --cached -r . || true
git clean -f -d
touch -d '1970-01-01 UTC' .
GIT_COMMITTER_DATE='1970-01-01T00:00:00 +0000' git commit \
  --date='1970-01-01T00:00:00 +0000' --allow-empty -m 'initial'
git rebase --committer-date-is-author-date --onto $tmp_branch --root master
git branch -d $tmp_branch

Ist es die zusätzliche Komplexität wert? vielleicht auch nicht, aber ich werde diese eine wird.

Auf diese Weise kann auch auf mehr geklonte Kopien des Repo diese Operation durchführt und mit den gleichen Ergebnissen führen, so dass sie nach wie vor kompatibel ... Testen ... ja ja, Arbeit, sondern müssen auch löschen und fügen Sie Ihre Fernbedienung wieder, zum Beispiel:

git remote rm origin
git remote add --track master user@host:path/to/repo

Nun, hier ist, was ich kam mit:

# Just setting variables on top for clarity.
# Set this to the path to your original repository.
ORIGINAL_REPO=/path/to/original/repository

# Create a new repository…
mkdir fun
cd fun
git init
# …and add an initial empty commit to it
git commit --allow-empty -m "The first evil."

# Add the original repository as a remote
git remote add previous $ORIGINAL_REPO
git fetch previous

# Get the hash for the first commit in the original repository
FIRST=`git log previous/master --pretty=format:%H  --reverse | head -1`
# Cherry-pick it
git cherry-pick $FIRST
# Then rebase the remainder of the original branch on top of the newly 
# cherry-picked, previously first commit, which is happily the second 
# on this branch, right after the empty one.
git rebase --onto master master previous/master

# rebase --onto leaves your head detached, I don't really know why)
# So now you overwrite your master branch with the newly rebased tree.
# You're now kinda done.
git branch -f master
git checkout master
# But do clean up: remove the remote, you don't need it anymore
git remote rm previous

Ich denke, dass git replace und git filter-branch verwendet, ist eine bessere Lösung als eine git rebase mit:

  • besser preformance
  • einfacher und weniger riskant (Sie Ihr Ergebnis bei jedem Schritt überprüfen konnten und ungeschehen machen, was du getan hast ...)
  • Arbeit gut mit mehreren Niederlassungen mit garantierten ergebnissen

Die Idee dahinter ist:

  • Erstellen Sie eine neue leere weit in der Vergangenheit
  • commit
  • Ersetzen Sie die alte Wurzel durch eine Festschreibung begehen genau ähnlich, außer dass die neue Wurzel Festschreibung als Eltern
  • hinzugefügt wird
  • Stellen Sie sicher, dass alles wie erwartet und laufen git filter-branch
  • Wieder einmal überprüfen, ob alles in Ordnung ist und reinigen Sie die nicht mehr benötigten Dateien git

Hier ist ein Skript für die 2 ersten Schritte:

#!/bin/bash
root_commit_sha=$(git rev-list --max-parents=0 HEAD)
git checkout --force --orphan new-root
find . -path ./.git -prune -o -exec rm -rf {} \; 2> /dev/null
git add -A
GIT_COMMITTER_DATE="2000-01-01T12:00:00" git commit --date==2000-01-01T12:00:00 --allow-empty -m "empty root commit"
new_root_commit_sha=$(git rev-parse HEAD)

echo "The commit '$new_root_commit_sha' will be added before existing root commit '$root_commit_sha'..."

parent="parent $new_root_commit_sha"
replacement_commit=$(
 git cat-file commit $root_commit_sha | sed "s/author/$parent\nauthor/" |
 git hash-object -t commit -w --stdin
) || return 3
git replace "$root_commit_sha" "$replacement_commit"

Sie können dieses Skript ohne Risiko laufen (auch wenn ein Backup zu tun, bevor sie Maßnahmen tun Sie nie zuvor eine gute Idee ist;)), und wenn das Ergebnis nicht die erwarteten, löschen Sie einfach die Dateien im Ordner .git/refs/replace erstellt und versuchen Sie es erneut;)

Wenn Sie sich vergewissert haben, dass der Zustand des Endlagers ist, was Sie erwarten, führen Sie den folgenden Befehl, um die Geschichte von aktualisieren Alle Branchen :

git filter-branch -- --all

Nun müssen Sie zwei Geschichten sehen, die alten und die neuen (Hilfe auf filter-branch für weitere Informationen). Sie können die 2 und prüfen Sie erneut vergleichen, wenn alles in Ordnung ist. Wenn Sie zufrieden sind, löschen Sie die nicht mehr benötigten Dateien:

rm -rf ./.git/refs/original
rm -rf ./.git/refs/replace

Sie könnten zurück in Ihre master Zweig und löschen Sie die temporären Zweig:

git checkout master
git branch -D new-root

Nun sollte alles getan werden;)

Hier ist eine einfache Einzeiler, die verwendet werden können, ein leeres begehen zu Beginn eines Endlagers hinzufügen möchten, wenn Sie eine leere erstellen vergessen begehen sofort nach „git init“:

git rebase --root --onto $(git commit-tree -m 'Initial commit (empty)' 4b825dc642cb6eb9a060e54bf8d69288fbee4904)

Hier ist mein bash Skript basiert auf Kent 's Antwort mit Verbesserungen:

  • überprüft er den ursprünglichen Zweig aus, nicht nur master, wenn Sie fertig sind;
  • Ich habe versucht, den temporären Zweig zu vermeiden, aber git checkout --orphan funktioniert nur mit einem Zweig, nicht losgelöst Kopf Zustand, so dass es lange genug überprüft, um die neue Wurzel zu machen begeht und dann gelöscht;
  • nutzt die Hash-Wert des neuen Root begeht während der filter-branch (Kent dort einen Platzhalter links für die manuellen Ersatz);
  • der filter-branch Betrieb umschreibt nur die lokalen Niederlassungen, nicht Fernbedienungen zu
  • der Autor und Committer Metadaten standardisiert ist, so dass die Wurzel über Repositorys identisch begehen.

#!/bin/bash

# Save the current branch so we can check it out again later
INITIAL_BRANCH=`git symbolic-ref --short HEAD`
TEMP_BRANCH='newroot'

# Create a new temporary branch at a new root, and remove everything from the tree
git checkout --orphan "$TEMP_BRANCH"
git rm -rf .

# Commit this empty state with generic metadata that will not change - this should result in the same commit hash every time
export GIT_AUTHOR_NAME='nobody'
export GIT_AUTHOR_EMAIL='nobody@example.org'
export GIT_AUTHOR_DATE='2000-01-01T00:00:00+0000'
export GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"
export GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"
export GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
git commit --allow-empty -m 'empty root'
NEWROOT=`git rev-parse HEAD`

# Check out the commit we just made and delete the temporary branch
git checkout --detach "$NEWROOT"
git branch -D "$TEMP_BRANCH"

# Rewrite all the local branches to insert the new root commit, delete the 
# original/* branches left behind, and check out the rewritten initial branch
git filter-branch --parent-filter "sed \"s/^\$/-p $NEWROOT/\"" --tag-name-filter cat -- --branches
git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
git checkout "$INITIAL_BRANCH"

Zum Umschalten der Wurzel zu begehen:

Erstellen Sie zunächst die verpflichten Sie als erstes wollen.

Zweitens, schalten Sie die Reihenfolge der Commits mit:

git rebase -i --root

Ein Editor wird mit den Commits angezeigt, bis die Wurzel begehen, wie:

Pick 1234 alte Wurzel Nachricht

Pick 0294 A in der Mitte begehen

Pick 5678 verpflichten Sie an der Wurzel setzen wollen

Sie können dann die Commit setzen Sie zuerst wollen, indem sie es in der ersten Zeile platzieren. Im Beispiel:

Pick 5678 verpflichten Sie an der Wurzel setzen wollen

Pick 1234 alte Wurzel Nachricht

Pick 0294 A in der Mitte begehen

Verlassen Sie den Editor der Commit-Reihenfolge geändert haben wird.

PS: Um den Editor git Anwendungen zu ändern, führen:

git config---global core.editor name_of_the_editor_program_you_want_to_use

Nach der Antwort des Aristoteles Pagaltzis und andere, aber mit einfachen Befehlen

zsh% git checkout --orphan empty     
Switched to a new branch 'empty'
zsh% git rm --cached -r .
zsh% git clean -fdx
zsh% git commit --allow-empty -m 'initial empty commit'
[empty (root-commit) 64ea894] initial empty commit
zsh% git checkout master
Switched to branch 'master'
zsh% git rebase empty
First, rewinding head to replay your work on top of it...
zsh% git branch -d empty 
Deleted branch empty (was 64ea894).

Beachten Sie Ihre Repo nicht warten, keine lokalen Änderungen enthalten sollten verpflichtet werden.
Hinweis git checkout --orphan wird bei neuen Versionen von Git arbeiten, ich denke.
Beachten Sie die meiste Zeit git status gibt nützliche Hinweise.

Starten

ein neues Repository.

Stellen Sie das Datum wieder auf das Startdatum Sie wollen.

Sie alles so, wie Sie Sie wollen es getan haben, um die Systemzeit Einstellung zu reflektieren, wenn Sie gewünscht werden Sie es auf diese Weise getan haben. Ziehen Sie Dateien aus dem vorhandenen Repository nach Bedarf eine Menge unnötiger Tipparbeit zu vermeiden.

Wenn Sie heute bekommen, tauschen die Repositories und du bist fertig.

Wenn Sie gerade verrückt sind (gegründet), aber einigermaßen intelligent (wahrscheinlich, weil Sie eine bestimmte Menge an smarts haben müssen verrückte Ideen wie diese erdenken) erhalten Sie Skript den Vorgang.

Das wird auch es schöner, wenn Sie Ihnen die Vergangenheit eine andere Art und Weise geschehen sein eine Woche ab jetzt wollen entscheiden.

Ich weiß, dass dieser Beitrag ist alt, aber diese Seite ist die erste, wenn googeln „Einfügen begeht git“.

Warum einfache Dinge kompliziert machen?

Sie haben A-B-C und Sie wollen A-B-Z-C.

  1. git rebase -i trunk (oder irgendetwas vor B)
  2. Änderung wählt auf der B-Leitung bearbeiten
  3. Ihre Änderungen: git add ..
  4. git commit (git commit --amend die B wird bearbeiten und nicht erstellen Z)

[Sie können so viele git commit machen, wie Sie hier wollen mehr Commits einzufügen. Natürlich haben Sie möglicherweise Probleme mit Schritt 5, aber mit git ist, sollten Sie haben eine Fähigkeit Konflikt verschmelzen zu lösen. Wenn nicht, üben!]

  1. git rebase --continue

Einfach, nicht wahr?

Wenn Sie verstehen git rebase, das Hinzufügen eines 'root' begehen sollte kein Problem sein.

Haben Sie Spaß mit git!

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top