如何移动一些文件从一个git回购到另一个(不是克隆),保存历史

我们的Git存储库最初是一个大型SVN存储库的一部分,其中每个项目都有自己的树,如下所示:

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

显然,使用svn mv将文件从一个文件移动到另一个文件非常容易。但是在Git中,每个项目都在自己的存储库中,今天我被要求将一个子目录从project2移动到project1。我是这样做的:

$ 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 overwrite 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

但这似乎相当复杂。有没有更好的方法来做这类事情呢?还是我采取了正确的方法?

注意,这涉及到将历史合并到现有的存储库中,而不是简单地从另一个存储库(就像之前的问题一样)的一部分创建一个新的独立存储库。

255255 次浏览

是的,击中filter-branch--subdirectory-filter是关键。您使用它的事实本质上证明了没有更简单的方法—您别无选择,只能重写历史,因为您希望最终只得到文件的一个(重命名的)子集,而这根据定义改变了哈希值。由于没有任何标准命令(例如pull)重写历史,因此您无法使用它们来完成此任务。

当然,您可以细化细节—您的一些克隆和分支并不是严格必要的—但是总体方法是好的!遗憾的是它很复杂,但是git的意义当然不是让重写历史变得容易。

如果你的历史记录是正常的,你可以将提交作为补丁取出,并将它们应用到新的存储库中:

cd repository
git log --pretty=email --patch-with-stat --reverse --full-index --binary -m --first-parent -- path/to/file_or_folder > patch
cd ../another_repository
git am --committer-date-is-author-date < ../repository/patch

或者在一行里

git log --pretty=email --patch-with-stat --reverse --full-index --binary -m --first-parent -- path/to/file_or_folder | (cd /path/to/new_repository && git am --committer-date-is-author-date)

(选自Exherbo的文档)

在尝试了将文件或文件夹从一个Git存储库移动到另一个存储库的各种方法后,下面概述了唯一可靠的方法。

它包括克隆要从中移动文件或文件夹的存储库,将该文件或文件夹移动到根目录,重写Git历史记录,克隆目标存储库,并将具有历史记录的文件或文件夹直接拉到目标存储库中。

阶段一

  1. 按照如下步骤复制存储库a 更改此副本,您不应该推动!< / p >

    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 into it

    cd <git repository A directory>
    #  eg. cd /c/Working/GIT/myprojects
    
  3. Delete the link to the original repository to avoid accidentally making any remote changes (eg. by pushing)

    git remote rm origin
    
  4. Go through your history and files, removing anything that is not in directory 1. The result is the contents of directory 1 spewed out into to the base of repository A.

    git filter-branch --subdirectory-filter <directory> -- --all
    # eg. git filter-branch --subdirectory-filter subfolder1/subfolder2/FOLDER_TO_KEEP -- --all
    
  5. For single file move only: go through what's left and remove everything except the desired file. (You may need to delete files you don't want with the same name and commit.)

    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
    

Stage Two

  1. Cleanup step

    git reset --hard
    
  2. Cleanup step

    git gc --aggressive
    
  3. Cleanup step

    git prune
    

You may want to import these files into repository B within a directory not the root:

  1. Make that directory

    mkdir <base directory>             eg. mkdir FOLDER_TO_KEEP
    
  2. Move files into that directory

    git mv * <base directory>          eg. git mv * FOLDER_TO_KEEP
    
  3. Add files to that directory

    git add .
    
  4. Commit your changes and we’re ready to merge these files into the new repository

    git commit
    

Stage Three

  1. Make a copy of repository B if you don’t have one already

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

    (假设FOLDER_TO_KEEP是要复制到的新存储库的名称)

  2. cd到它

    cd <git repository B directory>
    #  eg. cd /c/Working/GIT/FOLDER_TO_KEEP
    
  3. Create a remote connection to repository A as a branch in repository 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. Pull from this branch (containing only the directory you want to move) into repository B.

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

    拉取会同时复制文件和历史记录。注意:您可以使用合并而不是拉取,但拉取效果更好。< / p >

  5. 最后,你可能想通过移除遥控器来清理一下 连接到存储库A

    git remote rm repo-A-branch
    
  6. Push and you’re all set.

    git push
    

保留目录名

子目录过滤器(或更短的命令git子树)工作得很好,但对我来说并不管用,因为他们从提交信息中删除了目录名。在我的场景中,我只想将一个存储库的部分合并到另一个存储库中,并保留历史记录WITH完整的路径名。

我的解决方案是使用树筛选器,简单地从源存储库的临时克隆中删除不需要的文件和目录,然后通过5个简单步骤将该克隆拉入目标存储库。

# 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

这个答案提供了基于git am的有趣命令,并使用示例逐步给出。

客观的

  • 您希望将部分或全部文件从一个存储库移动到另一个存储库。
  • 你想保留他们的历史。
  • 但是您并不关心是否保留标记和分支。
  • 您接受重命名文件(以及重命名目录中的文件)的有限历史记录。

过程

  1. 使用
    提取邮件格式的历史 李# EYZ0 < / >
  2. 重新组织文件树并更新历史记录中的文件名更改[可选]
  3. 使用git am应用新的历史记录

1. 提取历史的电子邮件格式

示例:提取“file3”、“file4”和“file5”的历史记录

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

清理临时目录目的地

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

清理你的回购

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

提取历史的每个文件的电子邮件格式

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"' {} ';'

不幸的是,选项--follow--find-copies-harder不能与--reverse组合。这就是为什么重命名文件(或重命名父目录)时删除历史记录的原因。

After:邮件格式的临时历史

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

2. 重新组织文件树并更新历史记录中的文件名更改[可选]

假设您希望将这三个文件移动到另一个repo(可能是同一个repo)中。

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

因此,重新组织你的文件:

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

您的临时历史记录现在是:

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

更改历史记录中的文件名:

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

注意:这将重写历史,以反映路径和文件名的变化   ,# EYZ0 < / p >


3.应用新的历史记录

你的另一个回购是:

my_other_repo
├── dirF
│   ├── file55
│   └── file56
└── dirH
└── file77

从临时历史文件中申请提交:

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

你的另一个回购是:

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

使用git status查看准备推送的提交量:-)

因为历史已经被重写以反映路径和文件名的变化:
  ,# EYZ0 < / p >
  • 不需要git mv来改变位置/文件名。
  • 不需要git log --follow来访问完整的历史记录。

额外的技巧:检测重命名/移动文件在你的回购

列出已重命名的文件。

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

更多自定义:您可以使用选项--find-copies-harder--reverse完成命令git log。您还可以使用cut -f3-和grepping complete pattern '{删除前两列。* => .*}'。

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

使用http://blog.neutrino.es/2012/git-copy-a-file-or-directory-from-another-repository-preserving-history/的灵感,我创建了这个Powershell函数来做同样的事情,到目前为止对我来说效果很好:

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

这个例子的用法:

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"

完成此操作后,可以在合并migrate-from-project2分支之前重新组织该分支上的文件。

我发现罗斯·亨德里克森的博客非常有用。这是一种非常简单的方法,您可以创建应用于新回购的补丁。更多细节请参见链接页面。

它只包含三个步骤(复制自博客):

# 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

唯一的问题是我不能一次性应用所有补丁

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

在Windows下,我得到了一个InvalidArgument错误。所以我不得不一个接一个地打补丁。

对于类似的问题(尽管只针对特定存储库中的某些文件),这个脚本被证明非常有用:git-import

简短的版本是,它从现有的存储库中创建给定文件或目录($object)的补丁文件:

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

然后应用到一个新的存储库:

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

详情请查阅:

这个有用的方法可以被下面的< >强bash函数< / >强使用。下面是一个用法示例:

# EYZ0

gitcp ()
{
fromdir="$1";
frompath="$2";
to="$3";
echo "Moving git files from "$fromdir" at "$frompath" to "$to" ..";
tmpdir=/tmp/gittmp;
cd "$fromdir";
git format-patch --thread -o $tmpdir --root -- "$frompath";
cd "$to";
git am $tmpdir/*.patch
}

我经常用的是http://blog.neutrino.es/2012/git-copy-a-file-or-directory-from-another-repository-preserving-history/。简单快捷。

为了符合stackoverflow标准,以下是步骤:

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

我想要一些健壮和可重用的东西(一个命令行+撤销函数),所以我写了下面的bash脚本。我用过几次,所以我想在这里分享一下。

它能够移动任意文件夹/path/to/foorepo1/some/other/folder/barrepo2(文件夹路径可以相同或不同,距离根文件夹可能不同)。

由于它只遍历输入文件夹中涉及文件的提交(而不是源回购的所有提交),即使在大的源回购上,如果你只是提取一个在每次提交中都没有触及的嵌套很深的子文件夹,它也应该相当快。

因为这样做是创建一个带有所有旧的回购历史的孤立分支,然后将其合并到HEAD,它甚至可以在文件名冲突的情况下工作(当然,然后您必须在最后解决合并)。

如果没有文件名冲突,您只需要在最后使用git commit来完成合并。

缺点是它可能不会遵循文件重命名(在REWRITE_FROM文件夹之外)在源repo - pull请求中欢迎GitHub来适应这一点。

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

在我的例子中,我不需要保存我正在迁移的回购,也不需要保存任何以前的历史记录。我用不同的遥控器,截取了同一根树枝的补丁

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

在这两个步骤中,我能够让另一个回购的分支出现在同一个回购中。

最后,我设置这个分支(我从另一个回购导入)遵循目标回购的主线(所以我可以准确地区分它们)

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

现在它的行为就好像它只是我在同一次回购中推的另一个分支。

如果有关文件的路径在两个回购中是相同的,并且您希望只带来一个文件或一小组相关文件,那么一种简单的方法是使用git cherry-pick

第一步是使用git fetch <remote-url>将其他repo的提交带入您自己的本地repo。这将留下FETCH_HEAD指向头提交从另一个回购;如果你想在你完成其他取回之后保留对该提交的引用,你可能想用git tag other-head FETCH_HEAD标记它。

然后,您将需要为该文件创建一个初始提交(如果它不存在)或一个提交,以将该文件带到一个可以用您希望引入的另一个repo的第一次提交修补的状态。如果commit-0引入了你想要的文件,你可以使用git cherry-pick <commit-0>来完成,或者你可能需要“手动”构造提交。如果你需要修改最初的提交,添加-n到选择选项,例如,从你不想引入的提交中删除文件。

在此之后,您可以继续执行git cherry-pick后续提交,在必要时再次使用-n。在最简单的情况下(所有提交都是您想要的,并且干净地应用),您可以在精选命令行上给出完整的提交列表:git cherry-pick <commit-1> <commit-2> <commit-3> ...

试试这个

# EYZ0

这将删除除上述目录之外的所有目录,仅为这些目录保留历史记录

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

现在,您可以在git远程中添加新的repo并将其推到该位置

git remote remove origin <old-repo>
git remote add origin <new-repo>
git push origin <current-branch>

添加-f来覆盖

下面是通过维护所有分支和保存历史记录来将我的GIT Stash迁移到GitLab的方法。

将旧的存储库克隆到本地。

git clone --bare <STASH-URL>

在GitLab中创建一个空存储库。

git push --mirror <GitLab-URL>

当我们将代码从stash迁移到GitLab时,我执行了上述操作,效果非常好。

通过使用git-filter-repo,这变得更简单。

为了移动project2/sub/dirproject1/sub/dir:

# Create a new repo containing only the subdirectory:
git clone project2 project2_clone --no-local
cd project2_clone
git filter-repo --path sub/dir


# Merge the new repo:
cd ../project1
git remote add tmp ../project2_clone/
git fetch tmp master
git merge remotes/tmp/master --allow-unrelated-histories
git remote remove tmp
安装工具:pip3 install git-filter-repo (# EYZ0) < / p >
# Before: (root)
.
|-- project1
|   `-- 3
`-- project2
|-- 1
`-- sub
`-- dir
`-- 2


# After: (project1)
.
├── 3
└── sub
└── dir
└── 2

git subtree直观地工作,甚至保留了历史。

< p >使用例子: 将git repo添加为子目录:

git subtree add --prefix foo https://github.com/git/git.git master

解释:

#├── repo_bar
#│   ├── bar.txt
#└── repo_foo
#    └── foo.txt


cd repo_bar
git subtree add --prefix foo ../repo_foo master


#├── repo_bar
#│   ├── bar.txt
#│   └── foo
#│       └── foo.txt
#└── repo_foo
#    └── foo.txt

不需要linux或Github命令

1)去github在线。 2)带着你想要移动的文件去旧存储库。 3)原始复制文件内容。我的是pytorchimagessegmentation。ipynb 4)创建新的存储库并输入 5)单击“添加新文件”,创建新文件 6)将内容粘贴到文件中 7)给文件相同的扩展名在其他回购。我的是。ipynb,我保持相同的标题,所以它是pytorchimagesegement。Ipynb在新的回购以及

文件移动。没有尝试过用文件夹。我认为用这种方法不可能。