web-dev-qa-db-fra.com

Comment déplacer des fichiers d'un dépôt Git à un autre (pas un clone), en préservant l'historique

Nos référentiels Git ont commencé en tant que parties d’un référentiel SVN monstre unique, dans lequel les projets individuels avaient chacun leur propre arbre, comme ceci:

project1/branches
        /tags
        /trunk
project2/branches
        /tags
        /trunk

De toute évidence, il était assez facile de déplacer des fichiers de l'un à l'autre avec svn mv. Mais dans Git, chaque projet est dans son propre référentiel et aujourd'hui, on m'a demandé de déplacer un sous-répertoire de project2 vers project1. J'ai fait quelque chose comme ça:

$ git clone project2 
$ cd project2
$ git filter-branch --subdirectory-filter deeply/buried/Java/source/directory/A -- --all
$ git remote rm Origin  # so I don't accidentally the repo ;-)
$ mkdir -p deeply/buried/different/Java/source/directory/B
$ for f in *.Java; do 
>  git mv $f deeply/buried/different/Java/source/directory/B
>  done
$ git commit -m "moved files to new subdirectory"
$ cd ..
$
$ git clone project1
$ cd project1
$ git remote add p2 ../project2
$ git fetch p2
$ git branch p2 remotes/p2/master
$ git merge p2 # --allow-unrelated-histories for git 2.9
$ git remote rm p2
$ git Push

Mais cela semble assez compliqué. Y a-t-il une meilleure façon de faire ce genre de chose en général? Ou ai-je adopté la bonne approche?

Notez que cela implique la fusion de l'historique dans un référentiel existant, plutôt que la simple création d'un nouveau référentiel autonome à partir d'une partie d'un autre ( comme dans une question précédente ).

439
ebneter

Oui, frapper sur le --subdirectory-filter de filter-branch était la clé. Le fait que vous l'ayez utilisé prouve qu'il n'y a pas de moyen plus simple: vous n'aviez pas d'autre choix que de réécrire l'historique, car vous vouliez vous retrouver avec seulement un sous-ensemble (renommé) des fichiers, ce qui par définition modifie les hachages. Etant donné qu'aucune des commandes standard (par exemple pull) ne réécrit l'historique, vous ne pouvez pas les utiliser pour accomplir cela.

Vous pouvez bien sûr affiner les détails - certains clonages et ramifications n'étaient pas strictement nécessaires - mais l'approche globale est bonne! C’est dommage que ce soit compliqué, mais bien sûr, le but de Git n’est pas de faciliter la réécriture de l’histoire.

52
Cascabel

Si votre historique est sain, vous pouvez prendre les commits comme correctifs et les appliquer dans le nouveau référentiel:

cd repository
git log --pretty=email --patch-with-stat --reverse --full-index --binary -- path/to/file_or_folder > patch
cd ../another_repository
git am < ../repository/patch 

Ou en une seule ligne

git log --pretty=email --patch-with-stat --reverse -- path/to/file_or_folder | (cd /path/to/new_repository && git am)

(Extrait de documents Exherbo )

256
Smar

Après avoir essayé diverses approches pour déplacer un fichier ou un dossier d’un référentiel Git à un autre, la seule solution qui semble fonctionner de manière fiable est décrite ci-dessous.

Cela implique de cloner le référentiel à partir duquel vous souhaitez déplacer le fichier ou le dossier, de déplacer ce fichier ou ce dossier vers la racine, de réécrire l'historique Git, de cloner le référentiel cible et d'extraire le fichier ou le dossier avec l'historique directement dans ce référentiel cible.

Première étape

  1. Faites une copie du référentiel A au fur et à mesure que les étapes suivantes apportent des modifications majeures à cette copie que vous ne devez pas pousser!

    git clone --branch <branch> --Origin origin --progress \
      -v <git repository A url>
    # eg. git clone --branch master --Origin origin --progress \
    #   -v https://username@giturl/scm/projects/myprojects.git
    # (assuming myprojects is the repository you want to copy from)
    
  2. cd dedans

    cd <git repository A directory>
    #  eg. cd /c/Working/GIT/myprojects
    
  3. Supprimez le lien vers le référentiel d'origine pour éviter toute modification accidentelle à distance (par ex. En appuyant)

    git remote rm Origin
    
  4. Parcourez votre historique et vos fichiers, en supprimant tout ce qui ne se trouve pas dans le répertoire 1. Le résultat est le contenu du répertoire 1 créé dans la base du référentiel A.

    git filter-branch --subdirectory-filter <directory> -- --all
    # eg. git filter-branch --subdirectory-filter subfolder1/subfolder2/FOLDER_TO_KEEP -- --all
    
  5. Pour le déplacement d'un seul fichier uniquement: parcourez ce qui reste et supprimez tout sauf le fichier souhaité. (Vous devrez peut-être supprimer les fichiers de votre choix avec le même nom et les valider.)

    git filter-branch -f --index-filter \
    'git ls-files -s | grep $'\t'FILE_TO_KEEP$ |
    GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
    git update-index --index-info && \
    mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE || echo "Nothing to do"' --Prune-empty -- --all
    # eg. FILE_TO_KEEP = pom.xml to keep only the pom.xml file from FOLDER_TO_KEEP
    

Deuxième étape

  1. Étape de nettoyage

    git reset --hard
    
  2. Étape de nettoyage

    git gc --aggressive
    
  3. Étape de nettoyage

    git Prune
    

Vous voudrez peut-être importer ces fichiers dans le référentiel B dans un répertoire autre que la racine:

  1. Faire ce répertoire

    mkdir <base directory>             eg. mkdir FOLDER_TO_KEEP
    
  2. Déplacer des fichiers dans ce répertoire

    git mv * <base directory>          eg. git mv * FOLDER_TO_KEEP
    
  3. Ajouter des fichiers à ce répertoire

    git add .
    
  4. Commettez vos modifications et nous sommes prêts à fusionner ces fichiers dans le nouveau référentiel.

    git commit
    

Troisième étape

  1. Faites une copie du référentiel B si vous n’en avez pas déjà un.

    git clone <git repository B url>
    # eg. git clone https://username@giturl/scm/projects/FOLDER_TO_KEEP.git
    

    (en supposant que FOLDER_TO_KEEP est le nom du nouveau référentiel que vous copiez)

  2. cd dedans

    cd <git repository B directory>
    #  eg. cd /c/Working/GIT/FOLDER_TO_KEEP
    
  3. Créer une connexion à distance au référentiel A en tant que branche dans le référentiel B

    git remote add repo-A-branch <git repository A directory>
    # (repo-A-branch can be anything - it's just an arbitrary name)
    
    # eg. git remote add repo-A-branch /c/Working/GIT/myprojects
    
  4. Tirez de cette branche (contenant uniquement le répertoire que vous souhaitez déplacer) dans le référentiel B.

    git pull repo-A-branch master --allow-unrelated-histories
    

    Le pull copie les fichiers et l'historique. Remarque: vous pouvez utiliser une fusion au lieu d'un pull, mais pull fonctionne mieux.

  5. Enfin, vous voudrez probablement nettoyer un peu en supprimant la connexion distante au référentiel A

    git remote rm repo-A-branch
    
  6. Poussez et vous êtes tous ensemble.

    git Push
    
70
mcarans

J'ai trouvé ceci très utile. Il s’agit d’une approche très simple dans laquelle vous créez des correctifs qui sont appliqués au nouveau référentiel. Voir la page liée pour plus de détails.

Il ne contient que trois étapes (copiées du blog):

# Setup a directory to hold the patches
mkdir <patch-directory>

# Create the patches
git format-patch -o <patch-directory> --root /path/to/copy

# Apply the patches in the new repo using a 3 way merge in case of conflicts
# (merges from the other repo are not turned into patches). 
# The 3way can be omitted.
git am --3way <patch-directory>/*.patch

Le seul problème que j’avais était que je ne pouvais pas appliquer tous les patchs à la fois en utilisant

git am --3way <patch-directory>/*.patch

Sous Windows, j'ai eu une erreur InvalidArgument. J'ai donc dû appliquer tous les correctifs l'un après l'autre.

21
anhoppe

CONSERVER LE NOM DE L’ANNUAIRE

Le sous-répertoire-filtre (ou la commande plus courte git sous-arbre) fonctionne bien mais ne fonctionne pas pour moi car ils suppriment le nom du répertoire des informations de validation. Dans mon scénario, je souhaite simplement fusionner des parties d'un référentiel dans un autre et conserver l'historique AVEC le nom de chemin complet.

Ma solution consistait à utiliser le filtre d'arborescence et à simplement supprimer les fichiers et les répertoires indésirables d'un clone temporaire du référentiel source, puis de les extraire de ce clone dans le référentiel cible en 5 étapes simples.

# 1. clone the source
git clone ssh://<user>@<source-repo url>
cd <source-repo>
# 2. remove the stuff we want to exclude
git filter-branch --tree-filter "rm -rf <files to exclude>" --Prune-empty HEAD
# 3. move to target repo and create a merge branch (for safety)
cd <path to target-repo>
git checkout -b <merge branch>
# 4. Add the source-repo as remote 
git remote add source-repo <path to source-repo>
# 5. fetch it
git pull source-repo master
# 6. check that you got it right (better safe than sorry, right?)
gitk
6
Joachim Nilsson

Cette réponse fournit des commandes intéressantes basées sur git am et présentées à l'aide d'exemples, étape par étape.

Objectif

  • Vous souhaitez déplacer tout ou partie des fichiers d'un référentiel à un autre.
  • Vous voulez garder leur histoire.
  • Mais vous ne vous souciez pas de garder les étiquettes et les branches.
  • Vous acceptez un historique limité pour les fichiers renommés (et les fichiers dans des répertoires renommés).

Procédure

  1. Extraire l’historique au format email en utilisant
    _git log --pretty=email -p --reverse --full-index --binary_
  2. Réorganiser l'arborescence des fichiers et mettre à jour les modifications de nom de fichier dans l'historique [facultatif]
  3. Appliquer un nouvel historique à l'aide de _git am_

1. Extraire l'historique au format email

Exemple: extrait de l'historique de _file3_, _file4_ et _file5_

_my_repo
├── dirA
│   ├── file1
│   └── file2
├── dirB            ^
│   ├── subdir      | To be moved
│   │   ├── file3   | with history
│   │   └── file4   | 
│   └── file5       v
└── dirC
    ├── file6
    └── file7
_

Nettoyer le répertoire temporaire destination

_export historydir=/tmp/mail/dir  # Absolute path
rm -rf "$historydir"             # Caution when cleaning
_

Nettoyez votre le repo source

_git commit ...           # Commit your working files
rm .gitignore            # Disable gitignore
git clean -n             # Simulate removal
git clean -f             # Remove untracked file
git checkout .gitignore  # Restore gitignore
_

Extraire l'historique de chaque fichier au format email

_cd my_repo/dirB
find -name .git -Prune -o -type d -o -exec bash -c 'mkdir -p "$historydir/${0%/*}" && git log --pretty=email -p --stat --reverse --full-index --binary -- "$0" > "$historydir/$0"' {} ';'
_

Malheureusement, l'option _--follow_ ou _--find-copies-harder_ ne peut pas être combinée avec _--reverse_. C'est pourquoi l'historique est coupé lorsque le fichier est renommé (ou lorsqu'un répertoire parent est renommé).

Après: historique temporaire au format email

_/tmp/mail/dir
    ├── subdir
    │   ├── file3
    │   └── file4
    └── file5
_

2. Réorganisez l'arborescence des fichiers et mettez à jour les modifications de nom de fichier dans l'historique [facultatif]

Supposons que vous souhaitiez déplacer ces trois fichiers dans cet autre référentiel (il peut s'agir du même référentiel).

_my_other_repo
├── dirF
│   ├── file55
│   └── file56
├── dirB              # New tree
│   ├── dirB1         # was subdir
│   │   ├── file33    # was file3
│   │   └── file44    # was file4
│   └── dirB2         # new dir
│        └── file5    # = file5
└── dirH
    └── file77
_

Réorganisez donc vos fichiers:

_cd /tmp/mail/dir
mkdir     dirB
mv subdir dirB/dirB1
mv dirB/dirB1/file3 dirB/dirB1/file33
mv dirB/dirB1/file4 dirB/dirB1/file44
mkdir    dirB/dirB2
mv file5 dirB/dirB2
_

Votre historique temporaire est maintenant:

_/tmp/mail/dir
    └── dirB
        ├── dirB1
        │   ├── file33
        │   └── file44
        └── dirB2
             └── file5
_

Changer également les noms de fichiers dans l'historique:

_cd "$historydir"
find * -type f -exec bash -c 'sed "/^diff --git a\|^--- a\|^+++ b/s:\( [ab]\)/[^ ]*:\1/$0:g" -i "$0"' {} ';'
_

Remarque: Ceci réécrit l'historique pour refléter le changement de chemin et de nom de fichier.
 (c'est-à-dire le changement du nouvel emplacement/nom dans le nouveau dépôt)


3. Appliquer la nouvelle histoire

Votre autre repo est:

_my_other_repo
├── dirF
│   ├── file55
│   └── file56
└── dirH
    └── file77
_

Appliquer des commits à partir de fichiers d'historique temporaires:

_cd my_other_repo
find "$historydir" -type f -exec cat {} + | git am 
_

Votre autre repo est maintenant:

_my_other_repo
├── dirF
│   ├── file55
│   └── file56
├── dirB            ^
│   ├── dirB1       | New files
│   │   ├── file33  | with
│   │   └── file44  | history
│   └── dirB2       | kept
│        └── file5  v
└── dirH
    └── file77
_

Utilisez _git status_ pour voir le nombre de commits prêts à être envoyés :-)

Remarque: Comme l'historique a été réécrit pour refléter le chemin et le nom du fichier:
 (c'est-à-dire comparé au lieu/nom dans le rapport précédent)

  • Pas besoin de _git mv_ pour changer l'emplacement/nom du fichier.
  • Pas besoin de _git log --follow_ pour accéder à l'historique complet.

Astuce supplémentaire: détecter les fichiers renommés/déplacés dans votre dépôt

Pour lister les fichiers ayant été renommés:

_find -name .git -Prune -o -exec git log --pretty=tformat:'' --numstat --follow {} ';' | grep '=>'
_

Plus de personnalisations: Vous pouvez compléter la commande _git log_ en utilisant les options _--find-copies-harder_ ou _--reverse_. Vous pouvez également supprimer les deux premières colonnes à l’aide de _cut -f3-_ et du motif complet grepping '{. * =>. *}'.

_find -name .git -Prune -o -exec git log --pretty=tformat:'' --numstat --follow --find-copies-harder --reverse {} ';' | cut -f3- | grep '{.* => .*}'
_
5
olibre

Celui que j'utilise toujours est ici http://blog.neutrino.es/2012/git-copy-a-file-or-directory-from-another-repository-preserving-history/ . Simple et rapide.

Pour se conformer aux normes stackoverflow, voici la procédure:

mkdir /tmp/mergepatchs
cd ~/repo/org
export reposrc=myfile.c #or mydir
git format-patch -o /tmp/mergepatchs $(git log $reposrc|grep ^commit|tail -1|awk '{print $2}')^..HEAD $reposrc
cd ~/repo/dest
git am /tmp/mergepatchs/*.patch
4
Hugh Perkins

Ayant eu un démon similaire à gratter (bien que pour certains fichiers d’un dépôt), ce script s’est avéré très utile: git-import

La version courte est qu'il crée des fichiers de correctif du fichier ou du répertoire donné ($object) à partir du référentiel existant:

cd old_repo
git format-patch --thread -o "$temp" --root -- "$object"

qui sont ensuite appliqués à un nouveau référentiel:

cd new_repo
git am "$temp"/*.patch 

Pour plus de détails s'il vous plaît chercher:

3
ViToni

Essaye ça

cd repo1

Cela supprimera tous les répertoires sauf ceux mentionnés, en préservant l'historique uniquement pour ces répertoires.

git filter-branch --index-filter 'git rm --ignore-unmatch --cached -qr -- . && git reset -q $GIT_COMMIT -- dir1/ dir2/ dir3/ ' --Prune-empty -- --all

Maintenant, vous pouvez ajouter votre nouveau dépôt dans votre télécommande git et le pousser à cette

git remote remove Origin <old-repo>
git remote add Origin <new-repo>
git Push Origin <current-branch>

ajouter -f pour écraser

2
Chetan Basutkar

Je voulais quelque chose de robuste et de réutilisable (fonction commande-et-défaire + annulation) alors j'ai écrit le script bash suivant. Travaillé pour moi à plusieurs reprises, j'ai donc pensé le partager ici.

Il est capable de déplacer un dossier arbitraire /path/to/foo de repo1 dans /some/other/folder/bar vers repo2 (les chemins des dossiers peuvent être identiques ou différents, la distance du dossier racine peut être différente).

Comme il ne traite que les commits qui touchent les fichiers du dossier d’entrée (pas tous les commits du référentiel source), il devrait être assez rapide, même sur les gros dépôts de source, si vous extrayez simplement un sous-dossier profondément imbriqué qui n’a pas été touché à chaque fois. commettre.

Dans la mesure où cela crée une branche orpheline contenant tout l'historique de l'ancien référentiel, puis le fusionne dans HEAD, cela fonctionnera même en cas de conflit de noms de fichiers (vous devrez alors résoudre une fusion à la fin du cours). .

S'il n'y a pas de conflit de nom de fichier, il vous suffit de git commit à la fin pour finaliser la fusion.

L'inconvénient est qu'il ne suivra probablement pas les renominations de fichiers (en dehors du dossier REWRITE_FROM] dans le référentiel source - les requêtes d'extraction sont les bienvenues sur GitHub afin de répondre à ces besoins.

Lien GitHub: git-move-folder-between-repos-keep-history

#!/bin/bash

# Copy a folder from one git repo to another git repo,
# preserving full history of the folder.

SRC_GIT_REPO='/d/git-experimental/your-old-webapp'
DST_GIT_REPO='/d/git-experimental/your-new-webapp'
SRC_BRANCH_NAME='master'
DST_BRANCH_NAME='import-stuff-from-old-webapp'
# Most likely you want the REWRITE_FROM and REWRITE_TO to have a trailing slash!
REWRITE_FROM='app/src/main/static/'
REWRITE_TO='app/src/main/static/'

verifyPreconditions() {
    #echo 'Checking if SRC_GIT_REPO is a git repo...' &&
      { test -d "${SRC_GIT_REPO}/.git" || { echo "Fatal: SRC_GIT_REPO is not a git repo"; exit; } } &&
    #echo 'Checking if DST_GIT_REPO is a git repo...' &&
      { test -d "${DST_GIT_REPO}/.git" || { echo "Fatal: DST_GIT_REPO is not a git repo"; exit; } } &&
    #echo 'Checking if REWRITE_FROM is not empty...' &&
      { test -n "${REWRITE_FROM}" || { echo "Fatal: REWRITE_FROM is empty"; exit; } } &&
    #echo 'Checking if REWRITE_TO is not empty...' &&
      { test -n "${REWRITE_TO}" || { echo "Fatal: REWRITE_TO is empty"; exit; } } &&
    #echo 'Checking if REWRITE_FROM folder exists in SRC_GIT_REPO' &&
      { test -d "${SRC_GIT_REPO}/${REWRITE_FROM}" || { echo "Fatal: REWRITE_FROM does not exist inside SRC_GIT_REPO"; exit; } } &&
    #echo 'Checking if SRC_GIT_REPO has a branch SRC_BRANCH_NAME' &&
      { cd "${SRC_GIT_REPO}"; git rev-parse --verify "${SRC_BRANCH_NAME}" || { echo "Fatal: SRC_BRANCH_NAME does not exist inside SRC_GIT_REPO"; exit; } } &&
    #echo 'Checking if DST_GIT_REPO has a branch DST_BRANCH_NAME' &&
      { cd "${DST_GIT_REPO}"; git rev-parse --verify "${DST_BRANCH_NAME}" || { echo "Fatal: DST_BRANCH_NAME does not exist inside DST_GIT_REPO"; exit; } } &&
    echo '[OK] All preconditions met'
}

# Import folder from one git repo to another git repo, including full history.
#
# Internally, it rewrites the history of the src repo (by creating
# a temporary orphaned branch; isolating all the files from REWRITE_FROM path
# to the root of the repo, commit by commit; and rewriting them again
# to the original path).
#
# Then it creates another temporary branch in the dest repo,
# fetches the commits from the rewritten src repo, and does a merge.
#
# Before any work is done, all the preconditions are verified: all folders
# and branches must exist (except REWRITE_TO folder in dest repo, which
# can exist, but does not have to).
#
# The code should work reasonably on repos with reasonable git history.
# I did not test pathological cases, like folder being created, deleted,
# created again etc. but probably it will work fine in that case too.
#
# In case you realize something went wrong, you should be able to reverse
# the changes by calling `undoImportFolderFromAnotherGitRepo` function.
# However, to be safe, please back up your repos just in case, before running
# the script. `git filter-branch` is a powerful but dangerous command.
importFolderFromAnotherGitRepo(){
    SED_COMMAND='s-\t\"*-\t'${REWRITE_TO}'-'

    verifyPreconditions &&
    cd "${SRC_GIT_REPO}" &&
      echo "Current working directory: ${SRC_GIT_REPO}" &&
      git checkout "${SRC_BRANCH_NAME}" &&
      echo 'Backing up current branch as FILTER_BRANCH_BACKUP' &&
      git branch -f FILTER_BRANCH_BACKUP &&
      SRC_BRANCH_NAME_EXPORTED="${SRC_BRANCH_NAME}-exported" &&
      echo "Creating temporary branch '${SRC_BRANCH_NAME_EXPORTED}'..." &&
      git checkout -b "${SRC_BRANCH_NAME_EXPORTED}" &&
      echo 'Rewriting history, step 1/2...' &&
      git filter-branch -f --Prune-empty --subdirectory-filter ${REWRITE_FROM} &&
      echo 'Rewriting history, step 2/2...' &&
      git filter-branch -f --index-filter \
       "git ls-files -s | sed \"$SED_COMMAND\" |
        GIT_INDEX_FILE=\$GIT_INDEX_FILE.new git update-index --index-info &&
        mv \$GIT_INDEX_FILE.new \$GIT_INDEX_FILE" HEAD &&
    cd - &&
    cd "${DST_GIT_REPO}" &&
      echo "Current working directory: ${DST_GIT_REPO}" &&
      echo "Adding git remote pointing to SRC_GIT_REPO..." &&
      git remote add old-repo ${SRC_GIT_REPO} &&
      echo "Fetching from SRC_GIT_REPO..." &&
      git fetch old-repo "${SRC_BRANCH_NAME_EXPORTED}" &&
      echo "Checking out DST_BRANCH_NAME..." &&
      git checkout "${DST_BRANCH_NAME}" &&
      echo "Merging SRC_GIT_REPO/" &&
      git merge "old-repo/${SRC_BRANCH_NAME}-exported" --no-commit &&
    cd -
}

# If something didn't work as you'd expect, you can undo, tune the params, and try again
undoImportFolderFromAnotherGitRepo(){
  cd "${SRC_GIT_REPO}" &&
    SRC_BRANCH_NAME_EXPORTED="${SRC_BRANCH_NAME}-exported" &&
    git checkout "${SRC_BRANCH_NAME}" &&
    git branch -D "${SRC_BRANCH_NAME_EXPORTED}" &&
  cd - &&
  cd "${DST_GIT_REPO}" &&
    git remote rm old-repo &&
    git merge --abort
  cd -
}

importFolderFromAnotherGitRepo
#undoImportFolderFromAnotherGitRepo
1
jakub.g

En m'inspirant de http://blog.neutrino.es/2012/git-copy-a-file-or-directory-from-another-repository-preserving-history/ , j'ai créé cette fonction Powershell pour faire la même chose, ce qui a bien fonctionné pour moi jusqu'à présent:

# Migrates the git history of a file or directory from one Git repo to another.
# Start in the root directory of the source repo.
# Also, before running this, I recommended that $destRepoDir be on a new branch that the history will be migrated to.
# Inspired by: http://blog.neutrino.es/2012/git-copy-a-file-or-directory-from-another-repository-preserving-history/
function Migrate-GitHistory
{
    # The file or directory within the current Git repo to migrate.
    param([string] $fileOrDir)
    # Path to the destination repo
    param([string] $destRepoDir)
    # A temp directory to use for storing the patch file (optional)
    param([string] $tempDir = "\temp\migrateGit")

    mkdir $tempDir

    # git log $fileOrDir -- to list commits that will be migrated
    Write-Host "Generating patch files for the history of $fileOrDir ..." -ForegroundColor Cyan
    git format-patch -o $tempDir --root -- $fileOrDir

    cd $destRepoDir
    Write-Host "Applying patch files to restore the history of $fileOrDir ..." -ForegroundColor Cyan
    ls $tempDir -Filter *.patch  `
        | foreach { git am $_.FullName }
}

Utilisation pour cet exemple:

git clone project2
git clone project1
cd project1
# Create a new branch to migrate to
git checkout -b migrate-from-project2
cd ..\project2
Migrate-GitHistory "deeply\buried\Java\source\directory\A" "..\project1"

Ceci fait, vous pouvez réorganiser les fichiers sur la branche migrate-from-project2 avant de le fusionner.

1
crimbo

Si les chemins des fichiers en question sont les mêmes dans les deux dépôts et que vous souhaitez importer un seul fichier ou un petit ensemble de fichiers associés, une méthode simple consiste à utiliser git cherry-pick.

La première étape consiste à importer les validations de l'autre dépôt dans votre propre dépôt local à l'aide de git fetch <remote-url>. Cela laissera FETCH_HEAD pointant vers la tête commet de l'autre dépôt; Si vous souhaitez conserver une référence à ce commit après avoir effectué d'autres extractions, vous pouvez le baliser avec git tag other-head FETCH_HEAD.

Vous devrez ensuite créer un commit initial pour ce fichier (s'il n'existe pas) ou un commit pour amener le fichier à un état qui peut être corrigé avec le premier commit de l'autre dépôt que vous souhaitez importer. être capable de le faire avec un git cherry-pick <commit-0> si commit-0 a introduit les fichiers que vous voulez, ou vous devrez peut-être construire le commit 'à la main'. Ajoutez -n aux options de choix de recherche si vous devez modifier le commit initial, par exemple, supprimer les fichiers de ce commit que vous ne souhaitez pas importer.

Après cela, vous pouvez continuer à git cherry-pick, puis à nouveau en utilisant -n si nécessaire. Dans le cas le plus simple (tous les commits correspondent exactement à ce que vous voulez et vous appliquez proprement), vous pouvez donner la liste complète des commits sur la ligne de commande cherry-pick: git cherry-pick <commit-1> <commit-2> <commit-3> ....

0
Curt J. Sampson

Dans mon cas, je n'avais pas besoin de préserver le référentiel d'où je migrais ni de conserver l'historique. J'ai eu un patch de la même branche, d'une autre télécommande

#Source directory
git remote rm Origin
#Target directory
git remote add branch-name-from-old-repo ../source_directory

Dans ces deux étapes, j'ai pu faire en sorte que la branche de l'autre référentiel apparaisse dans le même référentiel.

Enfin, j'ai paramétré cette branche (que j'ai importée de l'autre référentiel) pour qu'elle suive la ligne principale du référentiel cible (afin de pouvoir les différencier avec précision).

git br --set-upstream-to=Origin/mainline

Maintenant, il se comportait comme si c’était une autre branche que j’avais attaquée contre le même dépôt.

0
Jason D