将有限的提交历史推送到远程 git
pushing limited commit history to remote git
我在学校的实验室机器上有一个 git 存储库,并且 运行 遇到了一个我一直试图解决的问题。
由于我们使用的 CUDA SDK 的安排,我在同一目录中有两个遥控器,但我不希望来自一个遥控器的所有提交,origin,被推送到另一个遥控器,"proj1".下面我会更清楚:
最初,此目录有一个 git 存储库和一个远程,例如,以下提交历史记录:
A-B-C-D-E <-(origin/master)
然后我添加了第二个远程并创建了一个本地分支,我将从中推送和获取:
A-B-C-D-E-G <-(origin/master) (master)
'
'-F-H-I <-(proj1/newbranch) (newbranch)
现在,当我将我的更改从 "newbranch" 推送到远程 "proj1/newbranch" 时,我不想用它推送提交 A-E,我只想从 F 向前推送。
我知道一个孤立的分支正是我在这里寻找的,但我们的实验室是 运行 git 1.7.x,它还没有那个功能,让管理员更新它太费时了(当然我们没有权限自己做)。
我还读到我可以使用 rebase 重新排序我的提交,以便 F 是最旧的提交,然后我可以将单个提交推送到 "proj1"。但是这样做 alter/mess 不会在 master 分支上也增加我的历史记录吗? (A-E 已经在 origin/master)
所以我想知道我是否缺少 git 的某些功能来完成我想要的?有没有其他方法可以删除 "newbranch" 的提交历史记录或至少将其中断?也许我正在做的是不好的做法,但正如我所说,我需要将所有文件都放在这个目录中用于 CUDA SDK,我不想弄乱它。
[[tl;dr...如果你能让你的"origin"项目成为"proj1"项目的子目录,并使用Git子模块,你将过上幸福的生活和平。如果你不能或不愿意,你注定要将 10% 的时间花在 "proj1" 开发上,而将 90% 的时间花在战斗 Git 上,你会血流成河。]]
好吧,我几乎可以肯定你认为你需要处理这件事的方式不仅仅是糟糕的做法,它是行不通的,所以我有道义上的责任一位 Git 用户告诉您您 应该 做什么,而不是帮助您做您 认为 应该做的事情。也许其他人会提出我没有想到的神奇解决方案,但我不会屏住呼吸。
我认为您需要接受这样一个事实,即这是两个独立的项目,它们需要有两个独立的工作目录(具有独立的“.git”子目录)。当然,这会带来两个紧迫的问题。首先,如果您需要将这些文件大量混合在同一个目录中,这似乎行不通;我尝试在下面解决这个问题。其次,如果目录是完全独立的,那么它们的历史记录是完全独立的,所以当你提交一个特定版本的 "proj1" 时,你不会有哪个版本的 "origin" 被用于的记录运行它。
如果您想要跟踪"origin"用于"proj1"每次提交的版本,那么Git子模块(见git help submodule
) 是要走的路。为此,"origin" 必须保存在 "proj1" 树的子目录中。您可以根据自己的喜好组织 "proj1" 的其余部分。同样,如果您需要混合文件,请参见下文。 Git 子模块在一个项目 ("proj1") 上进行开发时工作良好,而第二个项目 ("origin") 仅使用 Git 以方便跟进-到目前为止并记住哪个版本的 "origin" 用于 运行 哪个版本的 "proj1"。 (如果需要,子模块允许对第二个项目进行更改,但是让一切正常工作有点麻烦,所以如果子模块只是 "read only" 会好得多。)
顺便说一下,Git 子树(不是孤儿分支)是最接近做你想做的事情的事情,但它们 do 需要 "sub"-项目被安置在它自己的专用子目录中,他们确实要求子项目的整个历史都包含在主项目中;他们只是允许子项目被拆分并独立地推或拉。从理论上讲,您可以将它们用于您的设置,将 "origin" 视为主项目并将 "proj1" 作为 "subtree" 保存在单独的子目录中。您将像往常一样在存储库上工作,并且 "git subtree" 将提供一种机制来拆分在 "proj1" 子树中完成的工作并单独提交。太好了,对吧?可悲的是,子树仅作为贡献模块提供(默认情况下未安装,我不认为)与 Git 1.7.10 及更高版本。但是,您可以尝试 "git help subtree" 来检查。
但是,这些解决方案中的任何一个都需要将一个项目隔离在其自己的子目录中。
如果文件绝对必须混合在一个目录中,那么您将陷入痛苦的世界:最直接的方法是仍然维护两个单独的Git 工作目录(或 Git 子树)使用上述机制(即完全独立或一个使用子模块或子树的另一个子目录),然后构建一个符号链接树。符号链接树可以:
是一个单独的 "build" 目录,您实际上 运行 项目,所有文件的符号链接到每个真正的 "proj1" 和 "origin" 工作目录。
是一组实际添加到 "proj1" 工作目录并签入存储库的符号链接。它们都可以指向作为子模块管理的子目录中 "origin" 的副本。
我能想到的唯一替代符号链接树的方法是 更多 痛苦。从技术上讲,您可以设置一个 "proj1" 工作目录,“.git 忽略”所有 "origin" 文件。然后,您可以愉快地 运行 "git" 只管理 "proj1" 文件,忽略任何 "origin" 东西。当你想使用 "origin" 工作时(例如,用 "git pull" 更新它),你可以 运行 Git 使用 "--git-dir " and/or "--work-tree" 参数将您的工作树与不同的 ".git" 目录相匹配(配置为使用替代的 ".gitignore-origin" 文件或者其他的东西)。我从来没有尝试过这个,这听起来很糟糕,但你可能会成功。
现在,关于您 Git 存储库的当前状态,您遇到了问题。您的 "newbranch" 现在与 "origin" 项目的历史深深交织在一起,没有简单的方法可以将其分开。如果你想重建历史,你要么需要使用一些过滤器分支黑魔法,要么你需要手动完成(例如,对于从头到尾的每个提交,在你当前的树中检查它,复制 "proj1" 文件到新的 Git 工作目录,删除任何 "origin" 文件,然后重新提交)。
关于孤儿分支,他们不会在这里帮助你。孤儿分支只是普通的旧分支,恰好与同一存储库中的其他分支不共享任何历史记录。它可能看起来像您所追求的,但一旦您经历了设置它们的痛苦,您就会发现一些令人苦恼的事情。当您 "git checkout newproj" 处理 "proj1" 时,Git 将检查您的所有 "newproj" 文件并删除所有 CUDA API 文件!当您 "git checkout master" 访问 CUDA API 文件时,Git 将检查所有文件并删除所有 "newproj" 文件!你如何一次获得所有文件?显然,您设置了两个单独的工作目录,并在一个目录中检出 "newproj",在另一个目录中检出 "master",然后使用上述方法之一组合它们。与将它们视为完全独立的项目相比,它没有任何优势。你不能有一个孤儿分支,它以某种方式 "keeps" CUDA API 文件而不让它们签入分支。
我在学校的实验室机器上有一个 git 存储库,并且 运行 遇到了一个我一直试图解决的问题。
由于我们使用的 CUDA SDK 的安排,我在同一目录中有两个遥控器,但我不希望来自一个遥控器的所有提交,origin,被推送到另一个遥控器,"proj1".下面我会更清楚:
最初,此目录有一个 git 存储库和一个远程,例如,以下提交历史记录:
A-B-C-D-E <-(origin/master)
然后我添加了第二个远程并创建了一个本地分支,我将从中推送和获取:
A-B-C-D-E-G <-(origin/master) (master)
'
'-F-H-I <-(proj1/newbranch) (newbranch)
现在,当我将我的更改从 "newbranch" 推送到远程 "proj1/newbranch" 时,我不想用它推送提交 A-E,我只想从 F 向前推送。
我知道一个孤立的分支正是我在这里寻找的,但我们的实验室是 运行 git 1.7.x,它还没有那个功能,让管理员更新它太费时了(当然我们没有权限自己做)。
我还读到我可以使用 rebase 重新排序我的提交,以便 F 是最旧的提交,然后我可以将单个提交推送到 "proj1"。但是这样做 alter/mess 不会在 master 分支上也增加我的历史记录吗? (A-E 已经在 origin/master)
所以我想知道我是否缺少 git 的某些功能来完成我想要的?有没有其他方法可以删除 "newbranch" 的提交历史记录或至少将其中断?也许我正在做的是不好的做法,但正如我所说,我需要将所有文件都放在这个目录中用于 CUDA SDK,我不想弄乱它。
[[tl;dr...如果你能让你的"origin"项目成为"proj1"项目的子目录,并使用Git子模块,你将过上幸福的生活和平。如果你不能或不愿意,你注定要将 10% 的时间花在 "proj1" 开发上,而将 90% 的时间花在战斗 Git 上,你会血流成河。]]
好吧,我几乎可以肯定你认为你需要处理这件事的方式不仅仅是糟糕的做法,它是行不通的,所以我有道义上的责任一位 Git 用户告诉您您 应该 做什么,而不是帮助您做您 认为 应该做的事情。也许其他人会提出我没有想到的神奇解决方案,但我不会屏住呼吸。
我认为您需要接受这样一个事实,即这是两个独立的项目,它们需要有两个独立的工作目录(具有独立的“.git”子目录)。当然,这会带来两个紧迫的问题。首先,如果您需要将这些文件大量混合在同一个目录中,这似乎行不通;我尝试在下面解决这个问题。其次,如果目录是完全独立的,那么它们的历史记录是完全独立的,所以当你提交一个特定版本的 "proj1" 时,你不会有哪个版本的 "origin" 被用于的记录运行它。
如果您想要跟踪"origin"用于"proj1"每次提交的版本,那么Git子模块(见git help submodule
) 是要走的路。为此,"origin" 必须保存在 "proj1" 树的子目录中。您可以根据自己的喜好组织 "proj1" 的其余部分。同样,如果您需要混合文件,请参见下文。 Git 子模块在一个项目 ("proj1") 上进行开发时工作良好,而第二个项目 ("origin") 仅使用 Git 以方便跟进-到目前为止并记住哪个版本的 "origin" 用于 运行 哪个版本的 "proj1"。 (如果需要,子模块允许对第二个项目进行更改,但是让一切正常工作有点麻烦,所以如果子模块只是 "read only" 会好得多。)
顺便说一下,Git 子树(不是孤儿分支)是最接近做你想做的事情的事情,但它们 do 需要 "sub"-项目被安置在它自己的专用子目录中,他们确实要求子项目的整个历史都包含在主项目中;他们只是允许子项目被拆分并独立地推或拉。从理论上讲,您可以将它们用于您的设置,将 "origin" 视为主项目并将 "proj1" 作为 "subtree" 保存在单独的子目录中。您将像往常一样在存储库上工作,并且 "git subtree" 将提供一种机制来拆分在 "proj1" 子树中完成的工作并单独提交。太好了,对吧?可悲的是,子树仅作为贡献模块提供(默认情况下未安装,我不认为)与 Git 1.7.10 及更高版本。但是,您可以尝试 "git help subtree" 来检查。
但是,这些解决方案中的任何一个都需要将一个项目隔离在其自己的子目录中。
如果文件绝对必须混合在一个目录中,那么您将陷入痛苦的世界:最直接的方法是仍然维护两个单独的Git 工作目录(或 Git 子树)使用上述机制(即完全独立或一个使用子模块或子树的另一个子目录),然后构建一个符号链接树。符号链接树可以:
是一个单独的 "build" 目录,您实际上 运行 项目,所有文件的符号链接到每个真正的 "proj1" 和 "origin" 工作目录。
是一组实际添加到 "proj1" 工作目录并签入存储库的符号链接。它们都可以指向作为子模块管理的子目录中 "origin" 的副本。
我能想到的唯一替代符号链接树的方法是 更多 痛苦。从技术上讲,您可以设置一个 "proj1" 工作目录,“.git 忽略”所有 "origin" 文件。然后,您可以愉快地 运行 "git" 只管理 "proj1" 文件,忽略任何 "origin" 东西。当你想使用 "origin" 工作时(例如,用 "git pull" 更新它),你可以 运行 Git 使用 "--git-dir " and/or "--work-tree" 参数将您的工作树与不同的 ".git" 目录相匹配(配置为使用替代的 ".gitignore-origin" 文件或者其他的东西)。我从来没有尝试过这个,这听起来很糟糕,但你可能会成功。
现在,关于您 Git 存储库的当前状态,您遇到了问题。您的 "newbranch" 现在与 "origin" 项目的历史深深交织在一起,没有简单的方法可以将其分开。如果你想重建历史,你要么需要使用一些过滤器分支黑魔法,要么你需要手动完成(例如,对于从头到尾的每个提交,在你当前的树中检查它,复制 "proj1" 文件到新的 Git 工作目录,删除任何 "origin" 文件,然后重新提交)。
关于孤儿分支,他们不会在这里帮助你。孤儿分支只是普通的旧分支,恰好与同一存储库中的其他分支不共享任何历史记录。它可能看起来像您所追求的,但一旦您经历了设置它们的痛苦,您就会发现一些令人苦恼的事情。当您 "git checkout newproj" 处理 "proj1" 时,Git 将检查您的所有 "newproj" 文件并删除所有 CUDA API 文件!当您 "git checkout master" 访问 CUDA API 文件时,Git 将检查所有文件并删除所有 "newproj" 文件!你如何一次获得所有文件?显然,您设置了两个单独的工作目录,并在一个目录中检出 "newproj",在另一个目录中检出 "master",然后使用上述方法之一组合它们。与将它们视为完全独立的项目相比,它没有任何优势。你不能有一个孤儿分支,它以某种方式 "keeps" CUDA API 文件而不让它们签入分支。