Hoe voeg je twee Git-repositories samen?

Overweeg het volgende scenario:

Ik heb een klein experimenteel project A ontwikkeld in zijn eigen Git-repo. Het is nu volwassen en ik zou graag willen dat A deel uitmaakt van groter project B, dat zijn eigen grote opslagplaats heeft. Ik wil nu A toevoegen als een submap van B.

Hoe voeg ik A samen in B, zonder de geschiedenis aan welke kant dan ook te verliezen?


Antwoord 1, autoriteit 100%

Een enkele tak van een andere repository kan eenvoudig onder een subdirectory worden geplaatst met behoud van de geschiedenis. Bijvoorbeeld:

git subtree add --prefix=rails git://github.com/rails/rails.git master

Dit zal verschijnen als een enkele commit waar alle bestanden van de Rails master branch worden toegevoegd aan de “rails” directory.
De titel van de commit bevat echter een verwijzing naar de oude geschiedenisboom:

Voeg ‘rails/’ toe vanuit commit <rev>

Waar <rev>een SHA-1 commit-hash is. Je kunt de geschiedenis nog steeds zien, geef enkele veranderingen de schuld.

git log <rev>
git blame <rev> -- README.md

Merk op dat je het directory-voorvoegsel hier niet kunt zien, omdat dit een echte oude branch is die intact is gelaten.
Je zou dit moeten behandelen als een gebruikelijke vastlegging voor het verplaatsen van een bestand: je hebt een extra sprong nodig om het te bereiken.

# finishes with all files added at once commit
git log rails/README.md
# then continue from original tree
git log <rev> -- README.md

Er zijn complexere oplossingen, zoals dit handmatig doen of de geschiedenis herschrijven zoals beschreven in andere antwoorden.

Het git-subtree-commando maakt deel uit van het officiële git-contrib, sommige pakketbeheerders installeren het standaard (OS X Homebrew).
Maar misschien moet je het naast git ook zelf installeren.


Antwoord 2, autoriteit 95%

Als je project-awilt samenvoegen met project-b:

cd path/to/project-b
git remote add project-a /path/to/project-a
git fetch project-a --tags
git merge --allow-unrelated-histories project-a/master # or whichever branch you want to merge
git remote remove project-a

Overgenomen van: git merge verschillende repositories?

Deze methode werkte redelijk goed voor mij, het is korter en naar mijn mening een stuk schoner.

Als je project-ain een submap wilt plaatsen, kun je git-filter-repo(filter-branchis afgeraden). Voer de volgende opdrachten uit vóór de bovenstaande opdrachten:

cd path/to/project-a
git filter-repo --to-subdirectory-filter project-a

Een voorbeeld van het samenvoegen van 2 grote opslagplaatsen, waarbij een ervan in een submap wordt geplaatst: https:// gist.github.com/x-yuri/9890ab1079cf4357d6f269d073fd9731

Opmerking:De parameter --allow-unrelated-historiesbestaat pas sinds git >= 2.9. Zie Git – git merge Documentation / –allow- niet-gerelateerde geschiedenissen

Update: --tagstoegevoegd zoals voorgesteld door @jstadler om tags te behouden.


Antwoord 3, autoriteit 99%

Hier zijn twee mogelijke oplossingen:

Submodules

Kopieer repository A naar een aparte map in groter project B, of (misschien beter) kloon repository A naar een submap in project B. Gebruik dan git submoduleom van deze repository een submodulevan een repository B.

Dit is een goede oplossing voor los gekoppelde repositories, waar de ontwikkeling in repository A doorgaat, en het grootste deel van de ontwikkeling is een afzonderlijke stand-alone ontwikkeling in A. Zie ook SubmoduleSupporten GitSubmoduleTutorialpagina’s op Git Wiki.

Subboom samenvoegen

Je kunt repository A samenvoegen in een subdirectory van een project B met behulp van de subtree merge-strategie. Dit wordt beschreven in Subtree Merging and Youdoor Markus Prins.

git remote add -f Bproject /path/to/B
git merge -s ours --allow-unrelated-histories --no-commit Bproject/master
git read-tree --prefix=dir-B/ -u Bproject/master
git commit -m "Merge B project as our subdirectory"
git pull -s subtree Bproject master

(Optie --allow-unrelated-historiesis nodig voor Git >= 2.9.0.)

Of je kunt de tool git subtreegebruiken (repository op GitHub) door apenwarr (Avery Pennarun), bijvoorbeeld aangekondigd in zijn blogpost Een nieuw alternatief voor Git submodules: git subtree.


Ik denk dat in jouw geval (A moet deel uitmaken van groter project B) de juiste oplossing zou zijn om subtree mergete gebruiken.


Antwoord 4, autoriteit 41%

De submodule-aanpak is goed als je het project apart wilt onderhouden. Als je echter beide projecten echt in dezelfde repository wilt samenvoegen, heb je wat meer werk te doen.

Het eerste zou zijn om git filter-branchte gebruiken om de namen van alles in de tweede repository te herschrijven om in de submap te komen waar je ze zou willen hebben. Dus in plaats van foo.c, bar.html, zou je projb/foo.cen projb/bar.html.

Dan zou je zoiets als het volgende moeten kunnen doen:

git remote add projb [wherever]
git pull projb

De git pulldoet een git fetchgevolgd door een git merge. Er zouden geen conflicten mogen zijn als de repository waar je naartoe trekt nog geen projb/-directory heeft.

Verder zoeken geeft aan dat er iets soortgelijks is gedaan om gitksamen te voegen met git. Junio C Hamano schrijft er hier over: http://www.mail -archive.com/[email protected]/msg03395.html


Antwoord 5, autoriteit 16%

git-subtreeis leuk, maar het is waarschijnlijk niet degene die je wilt.

Bijvoorbeeld, als projectAde directory is die is aangemaakt in B, na git subtree,

git log projectA

geeft slechts ééncommit weer: de merge. De commits van het samengevoegde project zijn voor verschillende paden, dus ze verschijnen niet.

Het antwoord van Greg Hewgill komt het dichtst in de buurt, hoewel er niet echt staat hoe de paden moeten worden herschreven.


De oplossing is verrassend eenvoudig.

(1) In A,

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

Opmerking: dit herschrijft de geschiedenis; misschien wilt u eerst een back-up maken van A.

Opmerking Bene: U moet het vervangende script binnen de sed-opdracht wijzigen in het geval dat u niet-ascii-tekens (of witte tekens) in bestandsnamen of pad gebruikt. In dat geval begint de bestandslocatie binnen een record geproduceerd door “ls-files -s” met een aanhalingsteken.

(2) Voer vervolgens in B uit

git pull path/to/A

Voila! Je hebt een projectAdirectory in B. Als je git log projectAuitvoert, zul je alle commits van A zien.


In mijn geval wilde ik twee subdirectories, projectAen projectB. In dat geval heb ik ook stap (1) naar B gedaan.


Antwoord 6, autoriteit 11%

Als beide repositories dezelfde soort bestanden hebben (zoals twee Rails-repositories voor verschillende projecten), kunt u gegevens van de secundaire repository ophalen naar uw huidige repository:

git fetch git://repository.url/repo.git master:branch_name

en voeg het vervolgens samen met de huidige repository:

git merge --allow-unrelated-histories branch_name

Als je Git-versie kleiner is dan 2.9, verwijder dan --allow-unrelated-histories.

Hierna kunnen er conflicten optreden. Je kunt ze bijvoorbeeld oplossen met git mergetool. kdiff3kan alleen met het toetsenbord worden gebruikt, dus 5 conflictbestanden duren bij het lezen van de code slechts enkele minuten.

Vergeet niet om het samenvoegen te voltooien:

git commit

Antwoord 7, autoriteit 6%

Ik verloor steeds de geschiedenis bij het gebruik van merge, dus uiteindelijk gebruikte ik rebase omdat in mijn geval de twee repositories verschillend genoeg zijn om niet bij elke commit samen te voegen:

git clone git@gitorious/projA.git projA
git clone git@gitorious/projB.git projB
cd projB
git remote add projA ../projA/
git fetch projA 
git rebase projA/master HEAD

=> los conflicten op en ga verder, zo vaak als nodig is…

git rebase --continue

Als je dit doet, krijg je in één project alle commits van projA, gevolgd door commits van projB


Antwoord 8, autoriteit 2%

Ik probeer al dagen hetzelfde te doen, ik gebruik git 2.7.2. Subtree bewaart de geschiedenis niet.

U kunt deze methode gebruiken als u het oude project niet meer gaat gebruiken.

Ik zou willen voorstellen dat u eerst filiaal B en in het filiaal werkt.

Dit zijn de stappen zonder vertakkingen:

cd B
# You are going to merge A into B, so first move all of B's files into a sub dir
mkdir B
# Move all files to B, till there is nothing in the dir but .git and B
git mv <files> B
git add .
git commit -m "Moving content of project B in preparation for merge from A"
# Now merge A into B
git remote add -f A <A repo url>
git merge A/<branch>
mkdir A
# move all the files into subdir A, excluding .git
git mv <files> A
git commit -m "Moved A into subdir"
# Move B's files back to root    
git mv B/* ./
rm -rf B
git commit -m "Reset B to original state"
git push

Als u nu een van de bestanden in subdir A logt, krijgt u de volledige geschiedenis

git log --follow A/<file>

Dit was het bericht dat me hierbij hielp:

http:// saintgimp.org/2013/01/22/merging-two-git-repositories-in-one-repository-without-losing-file-history/


9, Autoriteit 2%

Ik heb hier veel informatie verzameld op Stack & Nbsp; Overloop, enz., En hebben erin geslaagd om een ​​script samen te stellen die het probleem voor mij oplost.

Het voorbehoud is dat het alleen rekening houdt met de ‘develop’-tak van elke repository en deze samenvoegt in een aparte map in een volledig nieuwe repository.

Tags en andere branches worden genegeerd – dit is misschien niet wat je wilt.

Het script verwerkt zelfs feature branches en tags – hernoem ze in het nieuwe project zodat je weet waar ze vandaan komen.

#!/bin/bash
#
################################################################################
## Script to merge multiple git repositories into a new repository
## - The new repository will contain a folder for every merged repository
## - The script adds remotes for every project and then merges in every branch
##   and tag. These are renamed to have the origin project name as a prefix
##
## Usage: mergeGitRepositories.sh <new_project> <my_repo_urls.lst>
## - where <new_project> is the name of the new project to create
## - and <my_repo_urls.lst> is a file contaning the URLs to the respositories
##   which are to be merged on separate lines.
##
## Author: Robert von Burg
##            [email protected]
##
## Version: 0.3.2
## Created: 2018-02-05
##
################################################################################
#
# disallow using undefined variables
shopt -s -o nounset
# Script variables
declare SCRIPT_NAME="${0##*/}"
declare SCRIPT_DIR="$(cd ${0%/*} ; pwd)"
declare ROOT_DIR="$PWD"
IFS=$'\n'
# Detect proper usage
if [ "$#" -ne "2" ] ; then
  echo -e "ERROR: Usage: $0 <new_project> <my_repo_urls.lst>"
  exit 1
fi
## Script variables
PROJECT_NAME="${1}"
PROJECT_PATH="${ROOT_DIR}/${PROJECT_NAME}"
TIMESTAMP="$(date +%s)"
LOG_FILE="${ROOT_DIR}/${PROJECT_NAME}_merge.${TIMESTAMP}.log"
REPO_FILE="${2}"
REPO_URL_FILE="${ROOT_DIR}/${REPO_FILE}"
# Script functions
function failed() {
  echo -e "ERROR: Merging of projects failed:"
  echo -e "ERROR: Merging of projects failed:" >>${LOG_FILE} 2>&1
  echo -e "$1"
  exit 1
}
function commit_merge() {
  current_branch="$(git symbolic-ref HEAD 2>/dev/null)"
  if [[ ! -f ".git/MERGE_HEAD" ]] ; then
    echo -e "INFO:   No commit required."
    echo -e "INFO:   No commit required." >>${LOG_FILE} 2>&1
  else
    echo -e "INFO:   Committing ${sub_project}..."
    echo -e "INFO:   Committing ${sub_project}..." >>${LOG_FILE} 2>&1
    if ! git commit -m "[Project] Merged branch '$1' of ${sub_project}" >>${LOG_FILE} 2>&1 ; then
      failed "Failed to commit merge of branch '$1' of ${sub_project} into ${current_branch}"
    fi
  fi
}
# Make sure the REPO_URL_FILE exists
if [ ! -e "${REPO_URL_FILE}" ] ; then
  echo -e "ERROR: Repo file ${REPO_URL_FILE} does not exist!"
  exit 1
fi
# Make sure the required directories don't exist
if [ -e "${PROJECT_PATH}" ] ; then
  echo -e "ERROR: Project ${PROJECT_NAME} already exists!"
  exit 1
fi
# create the new project
echo -e "INFO: Logging to ${LOG_FILE}"
echo -e "INFO: Creating new git repository ${PROJECT_NAME}..."
echo -e "INFO: Creating new git repository ${PROJECT_NAME}..." >>${LOG_FILE} 2>&1
echo -e "===================================================="
echo -e "====================================================" >>${LOG_FILE} 2>&1
cd ${ROOT_DIR}
mkdir ${PROJECT_NAME}
cd ${PROJECT_NAME}
git init
echo "Initial Commit" > initial_commit
# Since this is a new repository we need to have at least one commit
# thus were we create temporary file, but we delete it again.
# Deleting it guarantees we don't have conflicts later when merging
git add initial_commit
git commit --quiet -m "[Project] Initial Master Repo Commit"
git rm --quiet initial_commit
git commit --quiet -m "[Project] Initial Master Repo Commit"
echo
# Merge all projects into the branches of this project
echo -e "INFO: Merging projects into new repository..."
echo -e "INFO: Merging projects into new repository..." >>${LOG_FILE} 2>&1
echo -e "===================================================="
echo -e "====================================================" >>${LOG_FILE} 2>&1
for url in $(cat ${REPO_URL_FILE}) ; do
  if [[ "${url:0:1}" == '#' ]] ; then
    continue
  fi
  # extract the name of this project
  export sub_project=${url##*/}
  sub_project=${sub_project%*.git}
  echo -e "INFO: Project ${sub_project}"
  echo -e "INFO: Project ${sub_project}" >>${LOG_FILE} 2>&1
  echo -e "----------------------------------------------------"
  echo -e "----------------------------------------------------" >>${LOG_FILE} 2>&1
  # Fetch the project
  echo -e "INFO:   Fetching ${sub_project}..."
  echo -e "INFO:   Fetching ${sub_project}..." >>${LOG_FILE} 2>&1
  git remote add "${sub_project}" "${url}"
  if ! git fetch --tags --quiet ${sub_project} >>${LOG_FILE} 2>&1 ; then
    failed "Failed to fetch project ${sub_project}"
  fi
  # add remote branches
  echo -e "INFO:   Creating local branches for ${sub_project}..."
  echo -e "INFO:   Creating local branches for ${sub_project}..." >>${LOG_FILE} 2>&1
  while read branch ; do
    branch_ref=$(echo $branch | tr " " "\t" | cut -f 1)
    branch_name=$(echo $branch | tr " " "\t" | cut -f 2 | cut -d / -f 3-)
    echo -e "INFO:   Creating branch ${branch_name}..."
    echo -e "INFO:   Creating branch ${branch_name}..." >>${LOG_FILE} 2>&1
    # create and checkout new merge branch off of master
    if ! git checkout -b "${sub_project}/${branch_name}" master >>${LOG_FILE} 2>&1 ; then failed "Failed preparing ${branch_name}" ; fi
    if ! git reset --hard ; then failed "Failed preparing ${branch_name}" >>${LOG_FILE} 2>&1 ; fi
    if ! git clean -d --force ; then failed "Failed preparing ${branch_name}" >>${LOG_FILE} 2>&1 ; fi
    # Merge the project
    echo -e "INFO:   Merging ${sub_project}..."
    echo -e "INFO:   Merging ${sub_project}..." >>${LOG_FILE} 2>&1
    if ! git merge --allow-unrelated-histories --no-commit "remotes/${sub_project}/${branch_name}" >>${LOG_FILE} 2>&1 ; then
      failed "Failed to merge branch 'remotes/${sub_project}/${branch_name}' from ${sub_project}"
    fi
    # And now see if we need to commit (maybe there was a merge)
    commit_merge "${sub_project}/${branch_name}"
    # relocate projects files into own directory
    if [ "$(ls)" == "${sub_project}" ] ; then
      echo -e "WARN:   Not moving files in branch ${branch_name} of ${sub_project} as already only one root level."
      echo -e "WARN:   Not moving files in branch ${branch_name} of ${sub_project} as already only one root level." >>${LOG_FILE} 2>&1
    else
      echo -e "INFO:   Moving files in branch ${branch_name} of ${sub_project} so we have a single directory..."
      echo -e "INFO:   Moving files in branch ${branch_name} of ${sub_project} so we have a single directory..." >>${LOG_FILE} 2>&1
      mkdir ${sub_project}
      for f in $(ls -a) ; do
        if  [[ "$f" == "${sub_project}" ]] ||
            [[ "$f" == "." ]] ||
            [[ "$f" == ".." ]] ; then
          continue
        fi
        git mv -k "$f" "${sub_project}/"
      done
      # commit the moving
      if ! git commit --quiet -m  "[Project] Move ${sub_project} files into sub directory" ; then
        failed "Failed to commit moving of ${sub_project} files into sub directory"
      fi
    fi
    echo
  done < <(git ls-remote --heads ${sub_project})
  # checkout master of sub probject
  if ! git checkout "${sub_project}/master" >>${LOG_FILE} 2>&1 ; then
    failed "sub_project ${sub_project} is missing master branch!"
  fi
  # copy remote tags
  echo -e "INFO:   Copying tags for ${sub_project}..."
  echo -e "INFO:   Copying tags for ${sub_project}..." >>${LOG_FILE} 2>&1
  while read tag ; do
    tag_ref=$(echo $tag | tr " " "\t" | cut -f 1)
    tag_name_unfixed=$(echo $tag | tr " " "\t" | cut -f 2 | cut -d / -f 3)
    # hack for broken tag names where they are like 1.2.0^{} instead of just 1.2.0
    tag_name="${tag_name_unfixed%%^*}"
    tag_new_name="${sub_project}/${tag_name}"
    echo -e "INFO:     Copying tag ${tag_name_unfixed} to ${tag_new_name} for ref ${tag_ref}..."
    echo -e "INFO:     Copying tag ${tag_name_unfixed} to ${tag_new_name} for ref ${tag_ref}..." >>${LOG_FILE} 2>&1
    if ! git tag "${tag_new_name}" "${tag_ref}" >>${LOG_FILE} 2>&1 ; then
      echo -e "WARN:     Could not copy tag ${tag_name_unfixed} to ${tag_new_name} for ref ${tag_ref}"
      echo -e "WARN:     Could not copy tag ${tag_name_unfixed} to ${tag_new_name} for ref ${tag_ref}" >>${LOG_FILE} 2>&1
    fi
  done < <(git ls-remote --tags --refs ${sub_project})
  # Remove the remote to the old project
  echo -e "INFO:   Removing remote ${sub_project}..."
  echo -e "INFO:   Removing remote ${sub_project}..." >>${LOG_FILE} 2>&1
  git remote rm ${sub_project}
  echo
done
# Now merge all project master branches into new master
git checkout --quiet master
echo -e "INFO: Merging projects master branches into new repository..."
echo -e "INFO: Merging projects master branches into new repository..." >>${LOG_FILE} 2>&1
echo -e "===================================================="
echo -e "====================================================" >>${LOG_FILE} 2>&1
for url in $(cat ${REPO_URL_FILE}) ; do
  if [[ ${url:0:1} == '#' ]] ; then
    continue
  fi
  # extract the name of this project
  export sub_project=${url##*/}
  sub_project=${sub_project%*.git}
  echo -e "INFO:   Merging ${sub_project}..."
  echo -e "INFO:   Merging ${sub_project}..." >>${LOG_FILE} 2>&1
  if ! git merge --allow-unrelated-histories --no-commit "${sub_project}/master" >>${LOG_FILE} 2>&1 ; then
    failed "Failed to merge branch ${sub_project}/master into master"
  fi
  # And now see if we need to commit (maybe there was a merge)
  commit_merge "${sub_project}/master"
  echo
done
# Done
cd ${ROOT_DIR}
echo -e "INFO: Done."
echo -e "INFO: Done." >>${LOG_FILE} 2>&1
echo
exit 0

U kunt ook het krijgen van http://paste.ubuntu.com/11732805

Maak eerst een bestand met de URL naar elke repository, bijv .:

[email protected]:eitchnet/ch.eitchnet.parent.git
[email protected]:eitchnet/ch.eitchnet.utils.git
[email protected]:eitchnet/ch.eitchnet.privilege.git

Bel het script het geven van een naam van het project en het pad naar het script:

./mergeGitRepositories.sh eitchnet_test eitchnet.lst

Het script zelf heeft veel reacties die moet uitleggen wat het doet.


10

Ik weet dat het lang na de feiten, maar ik was niet blij met de andere antwoorden die ik hier te vinden, dus ik dit schreef:

me=$(basename $0)
TMP=$(mktemp -d /tmp/$me.XXXXXXXX)
echo 
echo "building new repo in $TMP"
echo
sleep 1
set -e
cd $TMP
mkdir new-repo
cd new-repo
    git init
    cd ..
x=0
while [ -n "$1" ]; do
    repo="$1"; shift
    git clone "$repo"
    dirname=$(basename $repo | sed -e 's/\s/-/g')
    if [[ $dirname =~ ^git:.*\.git$ ]]; then
        dirname=$(echo $dirname | sed s/.git$//)
    fi
    cd $dirname
        git remote rm origin
        git filter-branch --tree-filter \
            "(mkdir -p $dirname; find . -maxdepth 1 ! -name . ! -name .git ! -name $dirname -exec mv {} $dirname/ \;)"
        cd ..
    cd new-repo
        git pull --no-commit ../$dirname
        [ $x -gt 0 ] && git commit -m "merge made by $me"
        cd ..
    x=$(( x + 1 ))
done

Antwoord 11

Als je probeert om eenvoudig twee repositories aan elkaar te lijmen, zijn submodules en subtree merges de verkeerde tool om te gebruiken omdat ze niet de hele bestandsgeschiedenis bewaren (zoals mensen hebben opgemerkt in andere antwoorden). Zie dit antwoord hiervoor de eenvoudige en correcte manier om dit te doen.


Antwoord 12

Ik had een soortgelijke uitdaging, maar in mijn geval hadden we één versie van de codebase in repo A ontwikkeld en die vervolgens gekloond in een nieuwe repo, repo B, voor de nieuwe versie van het product. Nadat we enkele bugs in repo A hadden opgelost, moesten we de wijzigingen in repo B doorvoeren. Uiteindelijk deden we het volgende:

  1. Een afstandsbediening toevoegen aan repo B die naar repo A wees (git remote add…)
  2. De huidige branch trekken (we gebruikten master niet voor bugfixes) (git pull remoteForRepoA bugFixBranch)
  3. Samenvoegingen naar github pushen

Heerlijk gewerkt 🙂


Antwoord 13

Vergelijkbaar met @Smar maar gebruikt bestandssysteempaden, ingesteld in PRIMAIRE en SECUNDAIRE:

PRIMARY=~/Code/project1
SECONDARY=~/Code/project2
cd $PRIMARY
git remote add test $SECONDARY && git fetch test
git merge test/master

Vervolgens voeg je handmatig samen.

(aangepast van post van Anar Manafov)


Antwoord 14

2 repo’s samenvoegen

git clone ssh://<project-repo> project1
cd project1
git remote add -f project2 project2
git merge --allow-unrelated-histories project2/master
git remote rm project2
delete the ref to avoid errors
git update-ref -d refs/remotes/project2/master

Antwoord 15

Als je drie of meer projecten in een enkelecommit wilt samenvoegen, voer dan de stappen uit zoals beschreven in de andere antwoorden (remote add -f, merge). Stel vervolgens (zacht) de index opnieuw in op oude kop (waar geen samenvoeging plaatsvond). Voeg alle bestanden toe (git add -A) en commit ze (bericht “Projecten A, B, C en D samenvoegen in één project). Dit is nu de commit-id van master.

Maak nu .git/info/graftsmet de volgende inhoud:

<commit-id of master> <list of commit ids of all parents>

Voer git filter-branch -- head^..head head^2..head head^3..headuit. Als je meer dan drie vertakkingen hebt, voeg dan net zoveel head^n..headtoe als je vertakkingen hebt. Om tags bij te werken, voegt u --tag-name-filter cattoe. Voeg dat niet altijd toe, omdat dit een herschrijving van sommige commits kan veroorzaken. Zie voor details de man-pagina van filter-branch, zoek naar “grafts”.

Nu, aan je laatste commit zijn de juiste ouders gekoppeld.


Antwoord 16

Een A binnen B samenvoegen:

1) In het project A

git fast-export --all --date-order > /tmp/ProjectAExport

2) in het project b

git checkout -b projectA
git fast-import --force < /tmp/ProjectAExport

In deze branche moeten alle operaties doen en plegen.

c) Dan terug naar de master en een klassieke samenvoeging tussen de twee takken:

git checkout master
git merge projectA

17

Ik voeg projecten handmatig samen, waardoor ik kan voorkomen dat ze moeten omgaan met samenvoegconflicten.

Kopieer eerst in de bestanden van het andere project, maar u wilt ze.

cp -R myotherproject newdirectory
git add newdirectory

Volgende Trek in de geschiedenis

git fetch path_or_url_to_other_repo

vertel git om samen te voegen in de geschiedenis van het laatst gehaald

echo 'FETCH_HEAD' > .git/MERGE_HEAD

Begin nu, maar u zou normaal gesproken

begaan

git commit

18

Deze functie zal de Remote Repo klonen in lokale REPO DIR, na het samenvoegen van alle commits worden opgeslagen, git logwordt de originele commits en de juiste paden weergegeven:

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"
}

Hoe te gebruiken:

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

Als u kleine wijzigingen aanbrengt, kunt u zelfs bestanden/mappen van samengevoegde repo’s naar verschillende paden verplaatsen, bijvoorbeeld:

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"

Kennisgevingen
Paden worden vervangen via sed, dus zorg ervoor dat het na het samenvoegen in de juiste paden is verplaatst.
De parameter --allow-unrelated-historiesbestaat pas sinds git >= 2.9.


Antwoord 19

Gegeven commando is de best mogelijke oplossing die ik voorstel.

git subtree add --prefix=MY_PROJECT git://github.com/project/my_project.git master

Antwoord 20

Ik moest het vandaag als volgt oplossen:
Project A zat in bitbucket en Project B zat in code commit .. beide zijn dezelfde projecten, maar moesten wijzigingen van A naar B samenvoegen. (De truc is om dezelfde naambranch in Project A te maken, hetzelfde als in Project B)

  • git kassa Project A
  • git remote verwijder oorsprong
  • git remote add origin Project B
  • git kassa-tak
  • git add *
  • git commit -m “we hebben de code verplaatst”
  • git push

Antwoord 21

Ik wilde een klein project naar een submap van een groter project verplaatsen. Omdat mijn kleine project niet veel commits had, gebruikte ik git format-patch --output-directory /path/to/patch-dir. Bij het grotere project gebruikte ik git am --directory=dir/in/project /path/to/patch-dir/*.

Dit voelt veelminder eng en veel schoner dan een filtertak. Toegegeven, het is mogelijk niet van toepassing op alle gevallen.


Antwoord 22

https://github.com/hraban/tomonoals een andere vermelding van een scriptgebaseerd oplossing.

Ik ben niet de auteur, maar heb het gebruikt en het doet zijn werk.

Een positief aspect is dat je alle branches en alle geschiedenis in de uiteindelijke repo krijgt. Voor mijn repo’s (geen dubbele mappen in repo’s – eigenlijk kwamen ze uit de tfs2git-migratie) waren er geen conflicten en verliep alles geautomatiseerd.

Het wordt voornamelijk gebruikt (zie naam) om monorepos te maken.

Voor Windows-gebruikers: git bash kan het .sh-bestand uitvoeren. Het wordt geleverd met de standaard git-installatie.


Antwoord 23

Naast alle antwoorden met remote add-> fetch-> merge-strategie: als je tags van de andere repository wilt behouden, maar ze niet allemaal in een gemeenschappelijke naamruimte wilt verspreiden (en mogelijk botsingen wilt krijgen), wil je misschien het fetch-commando een beetje wijzigen :

git fetch --no-tags other_repo
git fetch --no-tags other_repo 'refs/tags/*:refs/tags/other_repo/*'

Eerste commando haalt alle branches op zoals gewoonlijk, maar laat tags die aan commits zijn gekoppeld weg, de tweede laat ook het gebruikelijke tag-ophaalmechanisme weg (git help fetchvoor meer), en haalt alle tags mapping op ze van Xnaar other_repo/Xmet behulp van de refspec-functionaliteit van git.

Referenties (takken, tags) zijn gewoon bestanden in git, en je kunt mappen gebruiken voor naamruimte. De twee bovenstaande commando’s zullen tags van de eerste repository behouden zoals ze zijn, en die van de andere zullen worden voorafgegaan door other_repo/

Na de operatie is het het beste om de andere afstandsbediening te verwijderen, zodat je niet per ongeluk de tags op de normale manier ophaalt en er een puinhoop van maakt.

Other episodes