Frage

Ich habe ein Git -Repository in einem Ordner namens Xxx, und ich habe das zweite Git -Repository aufgerufen YJJ.

Ich möchte die importieren Xxx Repository in die YJJ Repository als Unterverzeichnis benannt Zzz und alles hinzufügen Xxx'S verändern die Geschichte zu YJJ.

Ordnerstruktur vor:

XXX
 |- .git
 |- (project files)
YYY
 |- .git
 |- (project files)

Ordnerstruktur nach:

YYY
 |- .git  <-- This now contains the change history from XXX
 |-  ZZZ  <-- This was originally XXX
      |- (project files)
 |-  (project files)

Kann dies getan werden oder muss ich auf die Verwendung von Untermodulen zurückgreifen?

War es hilfreich?

Lösung

Wahrscheinlich wäre der einfachste Weg, das zu ziehen Xxx Zeug in einen Zweig in YJJ Und dann fusionieren Sie es in den Meister:

Im YJJ:

git remote add other /path/to/XXX
git fetch other
git checkout -b ZZZ other/master
mkdir ZZZ
git mv stuff ZZZ/stuff                      # repeat as necessary for each file/dir
git commit -m "Moved stuff to ZZZ"
git checkout master                
git merge ZZZ --allow-unrelated-histories   # should add ZZZ/ to master
git commit
git remote rm other
git branch -d ZZZ                           # to get rid of the extra branch before pushing
git push                                    # if you have a remote, that is

Ich habe das eigentlich nur mit ein paar meiner Repos versucht und es funktioniert. nicht wie Jörgs Antwort Sie werden Sie nicht weiterhin das andere Repo verwenden, aber ich glaube nicht, dass Sie das sowieso angegeben haben.

Hinweis: Da dies ursprünglich im Jahr 2009 geschrieben wurde, hat Git die in der folgenden Antwort erwähnte Subbree -Zusammenführung hinzugefügt. Ich würde diese Methode wahrscheinlich heute anwenden, obwohl diese Methode natürlich noch funktioniert.

Andere Tipps

Wenn Sie die genaue Festnetzgeschichte des zweiten Repositorys behalten möchten und daher auch die Fähigkeit beibehalten, in Zukunft vorgelagerte Änderungen zu verschmelzen, dann ist hier die gewünschte Methode. Dies führt zu einer unmodifizierten Geschichte des Subtree, das in Ihr Repo importiert wird, plus ein Zusammenführen, um das zusammengeführte Repository in das Unterverzeichnis zu verschieben.

git remote add XXX_remote <path-or-url-to-XXX-repo>
git fetch XXX_remote
git merge -s ours --no-commit --allow-unrelated-histories XXX_remote/master
git read-tree --prefix=ZZZ/ -u XXX_remote/master
git commit -m "Imported XXX as a subtree."

Sie können vorgelagerte Änderungen wie SO verfolgen:

git pull -s subtree XXX_remote master

Git hat selbst herausgefunden, wo sich die Wurzeln vor dem Zusammenführen befinden, sodass Sie das Präfix bei späteren Zusammenführungen nicht angeben müssen.

Git -Versionen vor 2.9: Sie müssen die nicht bestehen --allow-unrelated-histories Option zu git merge.

Die Methode in der anderen Antwort, die verwendet read-tree und überspringt die merge -s ours Der Schritt unterscheidet sich effektiv nicht als das Kopieren der Dateien mit CP und das Festlegen des Ergebnisses.

Originalquelle war von Githubs "Subtree Merge" -Hip -Artikel.

git-subtree ist ein Skript für genau diesen Anwendungsfall, in dem mehrere Repositories in eine verschmolzen sind und gleichzeitig die Geschichte erhalten haben (und/oder die Geschichte der Subträume aufgeteilt werden, obwohl dies für diese Frage irrelevant zu sein scheint). Es ist als Teil des Git -Baumes verteilt Seit Veröffentlichung 1.7.11.

Ein Repository zusammenführen <repo> bei Revision <rev> als Unterverzeichnis <prefix>, verwenden git subtree add folgendermaßen:

git subtree add -P <prefix> <repo> <rev>

Git-Subtree implementiert die Substree Merge -Strategie auf benutzerfreundlichere Weise.

Für Ihren Fall würden Sie in der Repository YJJ ausführen:

git subtree add -P ZZZ /path/to/XXX.git master

Es gibt ein bekanntes Beispiel dafür im Git-Repository selbst, das gemeinsam in der Git-Community als "bekannt ist"die coolste Zusammenführung aller Zeiten"(Nach der Betreffzeile Linus Torvalds, die in der E-Mail an die Git Mailinglist verwendet wird, die diese Zusammenführung beschreibt). In diesem Fall die gitk Git -GUI, die jetzt Teil von Git ist, war tatsächlich ein separates Projekt. Linus hat es geschafft, dieses Repository in eine Weise in das Git -Repository zusammenzufassen

  • Es erscheint im Git -Repository, als ob es immer als Teil von Git entwickelt worden wäre,
  • Die ganze Geschichte wird intakt gehalten und
  • Es kann immer noch unabhängig in seinem alten Repository entwickelt werden, wobei Änderungen einfach sind git pulled.

Die E-Mail enthält die Schritte, die zur Reproduktion erforderlich sind, aber es ist nicht für schwache Nerven: Erstens Linus schrieb Git, also weiß er wahrscheinlich ein bisschen mehr darüber als Sie oder ich, und zweitens war das fast 5 Jahre vor und Git hat sich verbessert wesentlich Seitdem ist es also vielleicht viel einfacher.

Insbesondere würde man heutzutage in diesem speziellen Fall ein Gitk -Submodul verwenden.

Die einfache Möglichkeit, dies zu tun, besteht darin, die Git-Formatpatch zu verwenden.

Angenommen, wir haben 2 Git -Repositories Foo und Bar.

Foo Enthält:

  • foo.txt
  • .Git

Bar Enthält:

  • bar.txt
  • .Git

und wir wollen lenden mit Foo enthält das Bar Verlauf und diese Dateien:

  • foo.txt
  • .Git
  • foobar/bar.txt

Also, um das zu tun:

 1. create a temporary directory eg PATH_YOU_WANT/patch-bar
 2. go in bar directory
 3. git format-patch --root HEAD --no-stat -o PATH_YOU_WANT/patch-bar --src-prefix=a/foobar/ --dst-prefix=b/foobar/
 4. go in foo directory
 5. git am PATH_YOU_WANT/patch-bar/*

Und wenn wir alle Nachrichten -Commits von Bar, z. B. unter Linux, umschreiben möchten:

git filter-branch --msg-filter 'sed "1s/^/\[bar\] /"' COMMIT_SHA1_OF_THE_PARENT_OF_THE_FIRST_BAR_COMMIT..HEAD

Dies fügt zu Beginn jeder Commit -Nachricht [bar] hinzu.

Basierend In diesem Artikel, Die Verwendung von Subtree hat für mich funktioniert und nur die anwendbare Geschichte übertragen. Veröffentlichen Sie hier, falls jemand die Schritte benötigt (ersetzen Sie die Platzhalter durch Werte, die für Sie zutreffend sind):

In Ihrem Quell -Repository -Unterordner in einen neuen Zweig aufgeteilt

git subtree split --prefix=<source-path-to-merge> -b subtree-split-result

In Ihrem Ziel -Repo verschmelzen Sie in der Split -Ergebnis -Zweigstelle

git remote add merge-source-repo <path-to-your-source-repository>
git fetch merge-source-repo
git merge -s ours --no-commit merge-source-repo/subtree-split-result
git read-tree --prefix=<destination-path-to-merge-into> -u merge-source-repo/subtree-split-result

Überprüfen Sie Ihre Änderungen und verpflichten Sie sich

git status
git commit

Vergiss es nicht

Aufräumen, indem Sie das löschen subtree-split-result Zweig

git branch -D subtree-split-result

Entfernen Sie die Fernbedienung, die Sie hinzugefügt haben, um die Daten von Source Repo zu holen

git remote rm merge-source-repo

Diese Funktion klonen Remote Repo in lokales Repo Dir, nachdem alle Commits zusammengeführt werden, wird gespeichert. git log wird die ursprünglichen Commits und die richtigen Wege zeigen:

function git-add-repo
{
    repo="$1"
    dir="$(echo "$2" | sed 's/\/$//')"
    path="$(pwd)"

    tmp="$(mktemp -d)"
    remote="$(echo "$tmp" | sed 's/\///g'| sed 's/\./_/g')"

    git clone "$repo" "$tmp"
    cd "$tmp"

    git filter-branch --index-filter '
        git ls-files -s |
        sed "s,\t,&'"$dir"'/," |
        GIT_INDEX_FILE="$GIT_INDEX_FILE.new" git update-index --index-info &&
        mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"
    ' HEAD

    cd "$path"
    git remote add -f "$remote" "file://$tmp/.git"
    git pull "$remote/master"
    git merge --allow-unrelated-histories -m "Merge repo $repo into master" --edit "$remote/master"
    git remote remove "$remote"
    rm -rf "$tmp"
}

Wie benutzt man:

cd current/package
git-add-repo https://github.com/example/example dir/to/save

Wenn Sie ein wenig Änderungen vornehmen, können Sie sogar Dateien/Diren von Fusions -Repo in verschiedene Pfade verschieben, z. B.:

repo="https://github.com/example/example"
path="$(pwd)"

tmp="$(mktemp -d)"
remote="$(echo "$tmp" | sed 's/\///g' | sed 's/\./_/g')"

git clone "$repo" "$tmp"
cd "$tmp"

GIT_ADD_STORED=""

function git-mv-store
{
    from="$(echo "$1" | sed 's/\./\\./')"
    to="$(echo "$2" | sed 's/\./\\./')"

    GIT_ADD_STORED+='s,\t'"$from"',\t'"$to"',;'
}

# NOTICE! This paths used for example! Use yours instead!
git-mv-store 'public/index.php' 'public/admin.php'
git-mv-store 'public/data' 'public/x/_data'
git-mv-store 'public/.htaccess' '.htaccess'
git-mv-store 'core/config' 'config/config'
git-mv-store 'core/defines.php' 'defines/defines.php'
git-mv-store 'README.md' 'doc/README.md'
git-mv-store '.gitignore' 'unneeded/.gitignore'

git filter-branch --index-filter '
    git ls-files -s |
    sed "'"$GIT_ADD_STORED"'" |
    GIT_INDEX_FILE="$GIT_INDEX_FILE.new" git update-index --index-info &&
    mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"
' HEAD

GIT_ADD_STORED=""

cd "$path"
git remote add -f "$remote" "file://$tmp/.git"
git pull "$remote/master"
git merge --allow-unrelated-histories -m "Merge repo $repo into master" --edit "$remote/master"
git remote remove "$remote"
rm -rf "$tmp"

Mitteilungen
Pfade ersetzt durch sed, Stellen Sie also sicher, dass es sich nach dem Zusammenführen auf den richtigen Wegen bewegte.
Das --allow-unrelated-histories Der Parameter existiert nur seit Git> = 2,9.

Eine weitere Antwort hinzuzufügen, da ich denke, dass dies etwas einfacher ist. Ein Zug von repo_dest wird in repo_to_import gemacht und dann ist ein drückend-set-oberstream-URL: repo_dest master erledigt.

Diese Methode hat für mich funktioniert, um mehrere kleinere Repos in eine größere zu importieren.

So importieren Sie: repo1_to_import zu repo_dest

# checkout your repo1_to_import if you don't have it already 
git clone url:repo1_to_import repo1_to_import
cd repo1_to_import

# now. pull all of repo_dest
git pull url:repo_dest
ls 
git status # shows Your branch is ahead of 'origin/master' by xx commits.
# now push to repo_dest
git push --set-upstream url:repo_dest master

# repeat for other repositories you want to import

Benennen oder verschieben Sie Dateien und Diren in Original Repo in die gewünschte Position, bevor Sie den Import durchführen. z.B

cd repo1_to_import
mkdir topDir
git add topDir
git mv this that and the other topDir/
git commit -m"move things into topDir in preparation for exporting into new repo"
# now do the pull and push to import

Die unter dem folgende Link beschriebene Methode inspirierte diese Antwort. Ich mochte es, da es einfacher schien. Aber Vorsicht! Es gibt Drachen! https://help.github.com/articles/import-an-external-git-repository git push --mirror url:repo_dest Schiebt Ihre lokale Repo -Geschichte und Ihren Zustand in Remote (URL: repo_dest). Aber es löscht die alte Geschichte und den Zustand der Fernbedienung. Spaß kommt! : -E

Ich wollte in meinem Fall nur einige Dateien aus dem anderen Repository (XXX) importieren. Der Subtree war für mich zu kompliziert und die anderen Lösungen funktionierten nicht. Das habe ich getan:

ALL_COMMITS=$(git log --reverse --pretty=format:%H -- ZZZ | tr '\n' ' ')

Auf diese Weise erhalten Sie eine platzgetrennte Liste aller Commits, die sich auf die Dateien auswirken, die ich importieren wollte (ZZZ) in umgekehrter Reihenfolge (Sie müssen möglicherweise hinzufügen-folgen-, um auch um die Umbenennung zu erfassen). Ich ging dann in das Ziel -Repository (YJJ), fügte das andere Repository (xxx) als Fernbedienung hinzu, habe einen Abruf von ihm gemacht und schließlich:

git cherry-pick $ALL_COMMITS

Was alle Commits zu Ihrer Niederlassung hinzufügt, haben Sie also alle Dateien mit ihrer Geschichte und können mit ihnen alles tun, als ob sie schon immer in diesem Repository waren.

Ich war in einer Situation, in der ich suchte -s theirs Aber natürlich existiert diese Strategie nicht. Meine Geschichte war, dass ich ein Projekt auf Github und jetzt aus irgendeinem Grund meine lokale master konnte nicht fusioniert werden upstream/master Obwohl ich keine lokalen Änderungen an diesem Zweig vorgenommen hatte. (Ich weiß wirklich nicht, was dort passiert ist - ich denke, Upstream hatte vielleicht ein paar schmutzige Schieben hinter den Kulissen gemacht?)

Was ich am Ende tat, war

# as per https://help.github.com/articles/syncing-a-fork/
git fetch upstream
git checkout master
git merge upstream/master
....
# Lots of conflicts, ended up just abandonging this approach
git reset --hard   # Ditch failed merge
git checkout upstream/master
# Now in detached state
git branch -d master # !
git checkout -b master   # create new master from upstream/master

Also jetzt mein master ist wieder synchron mit mit upstream/master (Und Sie können das oben genannte für jeden anderen Zweig wiederholen, den Sie auch ähnlich synchronisieren möchten).

Sehen Grundlegendes Beispiel in Dieser Artikel und berücksichtigen Sie solche Zuordnungen auf Repositories:

  • A <-> YYY,
  • B <-> XXX

Nach allen in diesem Kapitel beschriebenen Aktivität (nach dem Zusammenführen), entfernen Sie die Verzweigung B-master:

$ git branch -d B-master

Dann drücken Sie Änderungen.

Für mich geht das.

Ich kann eine andere Lösung vorschlagen (Alternative zu Git-Submodules) für Ihr Problem - GIL (Git Links) Tool

Es ermöglicht die Beschreibung und Verwaltung komplexer Abhängigkeiten von Git -Repositories.

Es bietet auch eine Lösung für die Git rekursive Submodules Abhängigkeitsproblem.

Bedenken Sie, dass Sie die folgenden Projektabhängigkeiten haben:Beispiel Git -Abhängigkeitsgrafik Git Repository

Dann können Sie definieren .gitlinks Datei mit Repositories Beziehung Beschreibung:

# Projects
CppBenchmark CppBenchmark https://github.com/chronoxor/CppBenchmark.git master
CppCommon CppCommon https://github.com/chronoxor/CppCommon.git master
CppLogging CppLogging https://github.com/chronoxor/CppLogging.git master

# Modules
Catch2 modules/Catch2 https://github.com/catchorg/Catch2.git master
cpp-optparse modules/cpp-optparse https://github.com/weisslj/cpp-optparse.git master
fmt modules/fmt https://github.com/fmtlib/fmt.git master
HdrHistogram modules/HdrHistogram https://github.com/HdrHistogram/HdrHistogram_c.git master
zlib modules/zlib https://github.com/madler/zlib.git master

# Scripts
build scripts/build https://github.com/chronoxor/CppBuildScripts.git master
cmake scripts/cmake https://github.com/chronoxor/CppCMakeScripts.git master

Jede Zeile beschreibt die Git -Verbindung im folgenden Format:

  1. Eindeutiger Name des Repositorys
  2. Relativer Pfad des Repositorys (gestartet vom Pfad der .gitlinks -Datei)
  3. Git -Repository, das in Git Clone -Befehlsrepository -Zweig zum Auschecken verwendet wird
  4. Leere Zeile oder Linie mit # werden nicht analysiert (als Kommentar behandelt).

Schließlich müssen Sie Ihr Stamm -Beispiel -Repository aktualisieren:

# Clone and link all git links dependencies from .gitlinks file
gil clone
gil link

# The same result with a single command
gil update

In dem Ergebnis klonen Sie alle erforderlichen Projekte und verknüpfen sie auf ordnungsgemäße Weise miteinander.

Wenn Sie alle Änderungen in einem Repository mit allen Änderungen in unterkäuflichen Repositories begehen möchten, können Sie dies mit einem einzigen Befehl tun:

gil commit -a -m "Some big update"

Pull, Push -Befehle funktioniert auf ähnliche Weise:

gil pull
gil push

Das GIL -Tool (Git Links) unterstützt die folgenden Befehle:

usage: gil command arguments
Supported commands:
    help - show this help
    context - command will show the current git link context of the current directory
    clone - clone all repositories that are missed in the current context
    link - link all repositories that are missed in the current context
    update - clone and link in a single operation
    pull - pull all repositories in the current directory
    push - push all repositories in the current directory
    commit - commit all repositories in the current directory

Mehr über Git rekursive Submodules Abhängigkeitsproblem.

Ich weiß keine einfache Möglichkeit, dies zu tun. Sie könnten das tun:

  1. Verwenden Sie die GIT-Filter-Branch, um ein Zzz-Super-Verzeichnis auf das XXX-Repository hinzuzufügen
  2. Schieben Sie den neuen Zweig zum YYY -Repository
  3. Fusionieren Sie den Pushed Ast mit Yyys Koffer.

Ich kann mit Details bearbeiten, wenn das attraktiv klingt.

Ich denke, Sie können dies mit 'Git MV' und 'Git Pull' tun.

Ich bin ein fairer Git Noob - sei also vorsichtig mit Ihrem Haupt -Repository -, aber ich habe es gerade in einem Temperatur -Dir versucht und es scheint zu funktionieren.

Erstens - benennen Sie die Struktur von XXX um, um zu entsprechen, wie sie aussehen sollen, wenn sie innerhalb von YYY ist:

cd XXX
mkdir tmp
git mv ZZZ tmp/ZZZ
git mv tmp ZZZ

Jetzt sieht xxx so aus:

XXX
 |- ZZZ
     |- ZZZ

Verwenden Sie nun "Git Pull", um die Änderungen zu erzielen:

cd ../YYY
git pull ../XXX

Jetzt sieht Yjy so aus:

YYY
 |- ZZZ
     |- ZZZ
 |- (other folders that already were in YYY)
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top