modificados - Cómo mover archivos de un repositorio de git a otro(no un clon), conservando el historial
git push (12)
Nuestros repositorios de Git comenzaron como partes de un único repositorio SVN de monstruos donde los proyectos individuales tenían cada uno su propio árbol así:
project1/branches
/tags
/trunk
project2/branches
/tags
/trunk
Obviamente, fue bastante fácil mover archivos de uno a otro con svn mv
. Pero en Git, cada proyecto está en su propio repositorio, y hoy me pidieron que mueva un subdirectorio de project2
a project1
. Hice algo como esto:
$ 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
Pero eso parece bastante complicado. ¿Hay una mejor manera de hacer este tipo de cosas en general? ¿O he adoptado el enfoque correcto?
Tenga en cuenta que esto implica fusionar el historial en un repositorio existente, en lugar de simplemente crear un nuevo repositorio independiente de parte de otro ( como en una pregunta anterior ).
Con la inspiración de http://blog.neutrino.es/2012/git-copy-a-file-or-directory-from-another-repository-preserving-history/ , creé esta función Powershell para hacer lo mismo, que tiene funcionó muy bien para mí hasta ahora:
# 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 }
}
Uso para este ejemplo:
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"
Después de hacer esto, puede reorganizar los archivos en la rama migrate-from-project2
antes de fusionarlos.
Después de haber probado varios métodos para mover un archivo o carpeta de un repositorio Git a otro, el único que parece funcionar de manera confiable se describe a continuación.
Implica clonar el repositorio desde el que desea mover el archivo o carpeta, mover ese archivo o carpeta a la raíz, volver a escribir el historial de Git, clonar el repositorio de destino y extraer el archivo o la carpeta con el historial directamente en este repositorio de destino.
La etapa uno
Haga una copia del repositorio A, ya que los siguientes pasos hacen cambios importantes en esta copia que no debe presionar.
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
(asumiendo que myprojects es el repositorio desde el que desea copiar)
cd en él
cd <git repository A directory> eg. cd /c/Working/GIT/myprojects
Elimine el enlace al repositorio original para evitar realizar cambios remotos accidentalmente (por ejemplo, presionando)
git remote rm origin
Ir a través de su historial y archivos, eliminando todo lo que no está en el directorio 1. El resultado es el contenido del directorio 1 arrojado a la base del repositorio A.
git filter-branch --subdirectory-filter <directory> -- --all eg. git filter-branch --subdirectory-filter subfolder1/subfolder2/FOLDER_TO_KEEP -- --all
Solo para mover un solo archivo: revise lo que queda y elimine todo excepto el archivo deseado. (Es posible que deba eliminar los archivos que no desee con el mismo nombre y confirmación).
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
p.ej. FILE_TO_KEEP = pom.xml para mantener solo el archivo pom.xml de FOLDER_TO_KEEP
Etapa dos
Paso de limpieza
git reset --hard
Paso de limpieza
git gc --aggressive
Paso de limpieza
git prune
Es posible que desee importar estos archivos al repositorio B dentro de un directorio que no sea la raíz:
Hacer ese directorio
mkdir <base directory> eg. mkdir FOLDER_TO_KEEP
Mover archivos a ese directorio
git mv * <base directory> eg. git mv * FOLDER_TO_KEEP
Agregar archivos a ese directorio
git add .
Confirme sus cambios y estamos listos para combinar estos archivos en el nuevo repositorio
git commit
Etapa tres
Haga una copia del repositorio B si aún no tiene una
git clone <git repository B url> eg. git clone https://username@giturl/scm/projects/FOLDER_TO_KEEP.git
(asumiendo que FOLDER_TO_KEEP es el nombre del nuevo repositorio en el que está copiando)
cd en él
cd <git repository B directory> eg. cd /c/Working/GIT/FOLDER_TO_KEEP
Cree una conexión remota al repositorio A como una rama en el repositorio B
git remote add repo-A-branch <git repository A directory>
(repo-A-branch puede ser cualquier cosa, es solo un nombre arbitrario)
eg. git remote add repo-A-branch /c/Working/GIT/myprojects
Tire de esta rama (que contiene solo el directorio que desea mover) al repositorio B.
git pull repo-A-branch master --allow-unrelated-histories
El pull copia tanto los archivos como el historial. Nota: puede usar una combinación en lugar de una extracción, pero la extracción funciona mejor.
Finalmente, es probable que desee limpiar un poco eliminando la conexión remota al repositorio A
git remote rm repo-A-branch
Empuje y ya está todo listo.
git push
El que siempre uso es aquí http://blog.neutrino.es/2012/git-copy-a-file-or-directory-from-another-repository-preserving-history/ . Sencillo y rápido.
Para cumplir con los estándares de , aquí está el procedimiento:
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
En mi caso, no necesitaba preservar el repositorio desde el que estaba migrando ni conservar ningún historial anterior. Tenía un parche de la misma rama, desde un control remoto diferente
#Source directory
git remote rm origin
#Target directory
git remote add branch-name-from-old-repo ../source_directory
En esos dos pasos, pude hacer que la rama del otro repo apareciera en el mismo repositorio.
Finalmente, configuré esta rama (que importé del otro repositorio) para seguir la línea principal del repositorio de destino (para poder diferenciarla con precisión)
git br --set-upstream-to=origin/mainline
Ahora se comportó como si fuera solo otra rama que había empujado contra el mismo repositorio.
Encontré this muy útil. Es un enfoque muy simple en el que crea parches que se aplican al nuevo repositorio. Vea la página vinculada para más detalles.
Solo contiene tres pasos (copiados del 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
El único problema que tuve fue que no podía aplicar todos los parches a la vez usando
git am --3way <patch-directory>/*.patch
Bajo Windows recibí un error InvalidArgument. Así que tuve que aplicar todos los parches uno tras otro.
Esta respuesta proporciona comandos interesantes basados en git am
y se presenta utilizando ejemplos, paso a paso.
Objetivo
- Desea mover algunos o todos los archivos de un repositorio a otro.
- Quieres mantener su historia.
- Pero no te importa mantener etiquetas y ramas.
- Acepta un historial limitado para archivos renombrados (y archivos en directorios renombrados).
Procedimiento
- Extraer el historial en formato de correo electrónico usando
git log --pretty=email -p --reverse --full-index --binary
- Reorganizar el árbol de archivos y actualizar el cambio de nombre de archivo en el historial [opcional]
- Aplicar nueva historia usando
git am
1. Extraer el historial en formato de correo electrónico.
Ejemplo: extraer el historial de file4
, file4
y file5
my_repo
├── dirA
│ ├── file1
│ └── file2
├── dirB ^
│ ├── subdir | To be moved
│ │ ├── file3 | with history
│ │ └── file4 |
│ └── file5 v
└── dirC
├── file6
└── file7
Limpie el directorio de destino temporal
export historydir=/tmp/mail/dir # Absolute path
rm -rf "$historydir" # Caution when cleaning
Limpia tu fuente de repo
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
Extraer el historial de cada archivo en formato de correo electrónico.
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"'' {} '';''
Desafortunadamente, la opción --follow
o --find-copies-harder
no se puede combinar con --reverse
. Esta es la razón por la cual el historial se corta cuando se cambia el nombre del archivo (o cuando se cambia el nombre de un directorio principal).
Después: Historial temporal en formato de correo electrónico.
/tmp/mail/dir
├── subdir
│ ├── file3
│ └── file4
└── file5
2. Reorganizar el árbol de archivos y actualizar el cambio de nombre de archivo en el historial [opcional]
Supongamos que desea mover estos tres archivos en este otro repositorio (puede ser el mismo repositorio).
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
Por eso reorganiza tus archivos:
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
Tu historia temporal es ahora:
/tmp/mail/dir
└── dirB
├── dirB1
│ ├── file33
│ └── file44
└── dirB2
└── file5
Cambie también los nombres de archivos dentro de la historia:
cd "$historydir"
find * -type f -exec bash -c ''sed "/^diff --git a/|^--- a/|^+++ b/s:/( [ab]/)/[^ ]*:/1/$0:g" -i "$0"'' {} '';''
Nota: Esto vuelve a escribir el historial para reflejar el cambio de ruta y nombre de archivo.
(es decir, el cambio de la nueva ubicación / nombre dentro del nuevo repositorio)
3. Aplicar nueva historia.
Tu otro repo es:
my_other_repo
├── dirF
│ ├── file55
│ └── file56
└── dirH
└── file77
Aplicar confirmaciones de archivos de historial temporal:
cd my_other_repo
find "$historydir" -type f -exec cat {} + | git am
Tu otro repo es ahora:
my_other_repo
├── dirF
│ ├── file55
│ └── file56
├── dirB ^
│ ├── dirB1 | New files
│ │ ├── file33 | with
│ │ └── file44 | history
│ └── dirB2 | kept
│ └── file5 v
└── dirH
└── file77
Use el git status
para ver la cantidad de confirmaciones listas para ser empujadas :-)
Nota: como el historial se ha reescrito para reflejar la ruta y el cambio de nombre de archivo:
(es decir, comparado con la ubicación / nombre dentro del repositorio anterior)
- No es necesario
git mv
para cambiar la ubicación / nombre de archivo. - No es necesario
git log --follow
para acceder al historial completo.
Truco adicional: detecte archivos renombrados / movidos dentro de su repositorio
Para listar los archivos que han sido renombrados:
find -name .git -prune -o -exec git log --pretty=tformat:'''' --numstat --follow {} '';'' | grep ''=>''
Más personalizaciones: puede completar el comando git log
usando las opciones --find-copies-harder
o --reverse
. También puede eliminar las dos primeras columnas usando cut -f3-
y grepping el patrón completo ''{. * =>. *}''.
find -name .git -prune -o -exec git log --pretty=tformat:'''' --numstat --follow --find-copies-harder --reverse {} '';'' | cut -f3- | grep ''{.* => .*}''
GUARDANDO EL NOMBRE DEL DIRECTORIO
El filtro de subdirectorio (o el subárbol git de comando más corto) funciona bien pero no funcionó para mí, ya que eliminan el nombre del directorio de la información de confirmación. En mi escenario, solo quiero combinar partes de un repositorio en otro y conservar el historial con el nombre completo de la ruta.
Mi solución fue usar el filtro de árbol y simplemente eliminar los archivos y directorios no deseados de un clon temporal del repositorio de origen, luego extraer de ese clon a mi repositorio de destino en 5 pasos 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
Habiendo tenido una picazón similar al rasguño (aunque solo para algunos archivos de un repositorio determinado), esta secuencia de comandos demostró ser realmente útil: git-import
La versión corta es que crea archivos de parche del archivo o directorio dado ( $object
) desde el repositorio existente:
cd old_repo
git format-patch --thread -o "$temp" --root -- "$object"
que luego se aplican a un nuevo repositorio:
cd new_repo
git am "$temp"/*.patch
Para más detalles, consulte:
- la git-import documentada
- git format-patch
- git am
Quería algo robusto y reutilizable (función one-command-and-go + undo), así que escribí el siguiente script de bash. Me funcionó en varias ocasiones, así que pensé en compartirlo aquí.
Es capaz de mover una carpeta /path/to/foo
arbitraria /path/to/foo
desde repo1
a /some/other/folder/bar
repo2
(las rutas de la carpeta pueden ser iguales o diferentes, la distancia desde la carpeta raíz puede ser diferente).
Dado que solo pasa por las confirmaciones que tocan los archivos en la carpeta de entrada (no sobre todas las confirmaciones del repositorio de origen), debería ser bastante rápido incluso en grandes repositorios de origen, si simplemente extrae una subcarpeta profundamente anidada que no se tocó en cada cometer.
Ya que lo que esto hace es crear una rama huérfana con todo el historial del antiguo repo y luego fusionarla con la HEAD, incluso funcionará en caso de conflictos de nombres de archivos (entonces tendrá que resolver una fusión al final del curso) .
Si no hay conflictos de nombre de archivo, solo necesita git commit
al final para finalizar la fusión.
El inconveniente es que probablemente no seguirá los REWRITE_FROM
de archivos (fuera de la carpeta REWRITE_FROM
) en el repositorio de origen; las solicitudes de extracción en GitHub son bienvenidas para dar cabida a eso.
Enlace de 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
Sí, pulsar en el --subdirectory-filter
de filter-branch
fue clave. El hecho de que lo usaste esencialmente demuestra que no hay una manera más fácil: no tenías más remedio que volver a escribir el historial, ya que querías terminar con solo un subconjunto (renombrado) de los archivos, y esto por definición cambia los hashes. Dado que ninguno de los comandos estándar (p. Ej., pull
) reescribe el historial, no hay forma de que puedas usarlos para lograr esto.
Por supuesto, podría refinar los detalles, ya que parte de su clonación y ramificación no fue estrictamente necesaria, ¡pero el enfoque general es bueno! Es una pena que sea complicado, pero, por supuesto, el objetivo de git no es facilitar la reescritura de la historia.
Si las rutas para los archivos en cuestión son las mismas en los dos repositorios y desea traer solo un archivo o un pequeño conjunto de archivos relacionados, una forma fácil de hacerlo es usar git cherry-pick
.
El primer paso es llevar las confirmaciones del otro repositorio a su propio repositorio local usando git fetch <remote-url>
. Esto dejará a FETCH_HEAD
apuntando a la confirmación de cabecera del otro repositorio; Si desea conservar una referencia a ese compromiso después de haber realizado otras búsquedas, puede etiquetarlo con la git tag other-head FETCH_HEAD
.
A continuación, deberá crear una confirmación inicial para ese archivo (si no existe) o una confirmación para llevar el archivo a un estado que pueda parcharse con la primera confirmación del otro repositorio que desee traer. Puede podrá hacer esto con un git cherry-pick <commit-0>
si commit-0
introdujo los archivos que desea, o si necesita construir el commit ''a mano''. Agregue -n
a las opciones de selección directa si necesita modificar la confirmación inicial para, por ejemplo, eliminar los archivos de esa confirmación que no desea incluir.
Después de eso, puede continuar con git cherry-pick
subsiguientes confirmaciones, nuevamente usando -n
donde sea necesario. En el caso más simple (todas las confirmaciones son exactamente lo que usted quiere y se aplican de manera limpia) puede proporcionar la lista completa de confirmaciones en la línea de comando cherry-pick: git cherry-pick <commit-1> <commit-2> <commit-3> ...
Si su historial es sensato, puede quitar las confirmaciones como parche y aplicarlas en el nuevo repositorio:
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
O en una linea
git log --pretty=email --patch-with-stat --reverse -- path/to/file_or_folder | (cd /path/to/new_repository && git am)
(Tomado de los documentos de Exherbo )