Wie erstelle ich einen neuen (und leeren!) "Root" -Zweig?

135

Ich möchte einen neuen "Root" -Zweig in diesem Git-Repository definieren. Mit "Root" -Zweig meine ich einen Zweig, der völlig unabhängig von allen anderen Zweigen im Repository ist 1 ist .

Leider auch das Commit (nennen wir es A ) ganz unten im Commit-Baum des Repos viele Dateien (dies war ein Repository, das in einem bereits ziemlich ausgereiften Projekt initialisiert wurde).

Das heißt, auch wenn ich Aals neue Filiale gegeben habe<start-point> angeben würde, dieser neue Zweig nicht von einem "sauberen Schiefer" ausgehen würde, sondern alle Dateien enthalten würde, die festgeschrieben wurden A.

Gibt es eine Möglichkeit, einen vollständig leeren Zweig in diesem Repository <start-point>so nah Awie möglich zu erstellen ?


1 Übrigens ist dies nicht eine neue repo Schaffung äquivalent. Separate Repos wären aus vielen Gründen weniger bequem.


EDIT : OK, das habe ich getan, basierend auf der Antwort von 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

Obwohl diese Prozedur etwas kompliziert ist, ist das Endergebnis ein leeres Basis-Commit, das als <start-point>für jeden neuen "Clean-Slate-Zweig" dienen kann. Alles was ich dann tun müsste ist

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

In Zukunft werde ich immer neue Repositorys wie diese erstellen:

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

... damit das erste Commit leer ist und immer zum Starten eines neuen unabhängigen Zweigs verfügbar ist. (Ich weiß, dies wäre eine sehr selten benötigte Einrichtung, aber es ist ziemlich mühelos, sie sofort verfügbar zu machen.)

kjo
quelle
1
@Anonymoose: Nur zur Veranschaulichung (statt zur Debatte): Ich bin mit Ihrer Meinung nicht einverstanden.
Kjo
1
Es scheint , basiert auf eine viel einfachere Lösung zu sein git rebase --onto, siehe stackoverflow.com/questions/645450/...
Stéphane Gourichon

Antworten:

222

Verwenden Sie --orphanbeim Erstellen des Zweigs Folgendes:

git checkout --orphan YourBranchName

Dadurch wird ein neuer Zweig erstellt, auf dem keine Commits ausgeführt werden. Alle Ihre Dateien werden jedoch bereitgestellt. An diesem Punkt können Sie sie einfach entfernen.
("entferne sie": A.git reset --hard leert den Index und hinterlässt einen leeren Arbeitsbaum)

Weitere Informationen zu --orphan finden Sie auf der Manpage zur Kasse.

vcsjones
quelle
Erzeugt dies im Wesentlichen eine leere Tafel? Wie in, von Grund auf neu? Oder behält es alle Ihre vorherigen Änderungen bei, aber nicht in der Git-Geschichte?
Con Antonakos
4
@ConAntonakos Dadurch wird ein neuer Zweig ohne übergeordnetes Element erstellt. Die anderen Zweige sind nicht betroffen, alle Änderungen bleiben erhalten.
Fuz
11

Zur akzeptierten Antwort hinzufügen - Best Practice ist WIEDERHERSTELLEN sauberen Zustand zu schaffen , ein erstes leer begehen , so dass Sie leicht rebase können , während der Zweige für die Nachwelt einrichten. Da Sie einen sauberen Status wünschen, haben Sie wahrscheinlich Dateien festgeschrieben, die Sie nicht sollten, sodass Sie sie aus dem Index entfernen müssen. In diesem Sinne sollten Sie:

$ 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
quelle
1
Ich glaube, dass dies ab 2012 nicht mehr erforderlich ist, da Sie auf root zurückgreifen können .
Timmmm
1

Gibt es eine Möglichkeit, einen vollständig leeren Zweig in diesem Repository zu erstellen?

Der tatsächlich zu verwendende Befehl (mit Git 2.28+) lautet:

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

git switchist ab Git 2.23 (August 2019) verfügbar und ersetzt den alten verwirrenden git checkoutBefehl .

Aber ich würde Git 2.28 (Q3 2020) empfehlen, da git switch --discard-changes --orphanes in dieser Version optimiert wurde.

Siehe Commit 8d3e33d , Commit 8186128 (21. Mai 2020) von Brian M. Carlson ( bk2204) .
(Zusammengeführt von Junio ​​C Hamano - gitster- in commit ded44af , 09. Juni 2020)

builtin/checkout: Vereinfachen Sie die Metadateninitialisierung

Unterzeichnet von: brian m. carlson
Bewertet von: Derrick Stolee

Wenn wir rufen init_checkout_metadatainreset_tree, uns die Objekt - ID des Commit in Frage übergeben wollen , so dass es zu Filter geleitet werden kann, oder wenn es keine begehen ist, den Baum.

Wir haben diesen letzteren Fall vorweggenommen, der an anderer Stelle im Checkout-Code auftreten kann, aber hier nicht auftreten kann.

Der einzige Fall, in dem wir kein Commit-Objekt haben, ist beim Aufrufen git switchmit--orphan .

Darüber hinaus können wir diesen Codepfad nur ohne ein Commit-Objekt zusätzlich mit entweder --forceoder treffen--discard-changes .

In einem solchen Fall macht es keinen Sinn, die Checkout-Metadaten mit einem Commit oder Baum zu initialisieren, weil

  • (a) Es gibt kein Commit, nur den leeren Baum und
  • (b) Wir werden die Daten niemals verwenden, da beim Auschecken eines Zweigs ohne Dateien keine Dateien verschmiert werden.

Übergeben Sie in diesem Fall die Objekt-ID mit allen Nullen, da wir nur einen Wert benötigen, der ein gültiger Zeiger ist.

Prüfung:

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
quelle