一个目录中有两个 git 存储库?

发布于 2024-07-11 20:09:25 字数 186 浏览 8 评论 0原文

一个目录下可以有2个git仓库吗? 我想不会,但我想我会问。 基本上,我想检查我的主目录配置文件(例如 .emacs),这些文件在我工作的所有计算机上应该是通用的,但有第二个本地文件存储库(例如 .emacs.local),其中包含机器特定的配置。 我能想到的唯一方法是将本地配置放在子目录中,并忽略主 git 存储库中的该子目录。 还有其他想法吗?

Is it possible to have 2 git repositories in one directory? I'd think not, but thought I'd ask. Basically, I'd like to check in my home directory config files (e.g. .emacs) which should be common across all of the machines I work on, but have a second repository for local files (e.g. .emacs.local), which contains machine-specific configurations. The only way I can think of to do that is to have the local config in a subdirectory and ignore that subdirectory from the main git repository. Any other ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

时光与爱终年不遇 2024-07-18 20:09:26

本文相对较好地介绍了这一点:

https://github.com/rrrene/gitscm-next/blob/master/app/views/blog/progit/2010-04-11-environment.markdown

基本上,如果您正在工作命令行这比您想象的要简单。 假设您想要 2 个 git 存储库:

.gitone
.gittwo

您可以像这样设置它们:

git init .
mv .git .gitone
git init .
mv .git .gittwo

您可以添加一个文件并将其提交到仅一个文件,如下所示:

git --git-dir=.gitone add test.txt
git --git-dir=.gitone commit -m "Test"

所以 git 的选项首先出现,然后是命令,然后是 git 命令的选项。 您可以轻松地为 git 命令添加别名,例如:

#!/bin/sh
alias gitone='git --git-dir=.gitone'
alias gittwo='git --git-dir=.gittwo'

这样您就可以用更少的输入来提交其中一个命令,例如 gitone commit -m "blah"

似乎更棘手的是忽略。 由于 .gitignore 通常位于项目根目录中,因此您需要找到一种方法来切换它而不切换整个根目录。 或者,您可以使用 .git/info/exclude,但是您执行的所有忽略都不会被提交或推送 - 这可能会搞砸其他用户。 使用任一存储库的其他人可能会推送 .gitignore,这可能会导致冲突。 我不清楚解决这些问题的最佳方法。

如果您更喜欢 TortoiseGit 这样的 GUI 工具,您也会遇到一些挑战。 您可以编写一个小脚本,暂时将 .gitone 或 .gittwo 重命名为 .git,以便满足这些工具的假设。

避免 2 个存储库

您可以通过编写分支来实现类似的结果,尽管您仍然需要做一些舞蹈来让事情继续进行。

假设您有本地文件,例如原始问题中的系统特定设置。 您希望将它们排除在对其他开发人员的提交之外,但是,您希望将它们提交到某个地方,因为它们要么是运行所必需的,要么是调试中至关重要的,

而不是 2 个 git 存储库,您可以执行以下操作:

git checkout main
git checkout -b local
git add -A .
git commit -m "local changes"
git checkout main
git checkout -b chris
git checkout -b dev
git merge local

所以,您从本地更改开始,将其放在名为“本地”的分支上。 你永远不会将该分支推送到远程。

您将这些更改放在一边,然后从 main 中创建另一个分支,以您将要推送的内容命名,例如以您的名字命名(在我的例子中为“chris”)。

到目前为止,您已经有了两个不同的分支,但是您没有办法让它们一起工作。 您创建第三个组合分支 - dev,这里是 chris 和 local 的组合。

你在 dev 中进行开发,然后当需要推送时,你:

git checkout chris
git add -A .
git commit -m "My commit message"
git push

git checkout dev
git merge chris

这会推送更改,在 chris 上清理,然后返回到 dev 并重新组合分支。 克里斯继续保持干净整洁,您有意义的更改被推动,并且您想要在本地保留的内容在本地分支上保持安全。

更特殊的场景:

推送本地分支

假设您想毕竟推送您的“本地”分支,例如,如果其中没有重要的秘密,并且您部分使用 git 作为备份。 修复很简单,只需将分支命名为长且非常清晰的名称,这样就没有开发人员拉动它并期望它为他们工作,例如 chris-local-settings。 如果您不喜欢一遍又一遍地输入长名称(并且制表符补全还不够),则对分支进行分支非常便宜:

git checkout chris-local-settings
git checkout -b local

生成的文件

假设您的本地分支更复杂,并且生成的文件不断造成混乱。 您需要它们进行调试,但您永远不想将它们推送到只包含您的非生成更改的干净分支。

您生成的文件可能遵循某种模式,或者如果不遵循某种模式,您可能对它们何时生成的位置有一定的发言权,因此它们确实遵循某种模式。 例如,如果您生成的所有文件都出现在名为“bin”的文件夹中,并且您刚刚完成了一些重要的编码:

git checkout local
cd bin
git add -A .
git commit -m "Generated files"
cd ..
git checkout chris
git commit -m "Commit message about my clean handwritten changes"
git push
git checkout dev
git merge local
git merge chris

因为您知道所有生成的文件都在 bin 文件夹中,所以您可以直接 cd 并 git add 在那里。 您可以将它们干净地转储到本地,然后返回到根目录并将其余部分提交到干净的分支。 然后你重构你的开发分支。

如果将来您需要知道给定日期和时间的构建是什么样子,您可以重构另一个分支,或者在 dev 分支上及时退回。 也就是说,我通常会在构建中经常丢弃并重新组合 dev 分支,因此,不幸的是,它没有历史记录:

想象一下 main 上发生了一些更改,我需要在可能毒害我的构建之前验证它们是否有效:

git checkout main
git pull
git checkout dev
git checkout -b test
git merge main

现在我要运行测试以验证构建。 如果他们表现不佳:

git checkout dev
git branch -D test

我会告诉最后推到主线的人,他们打破了它。 现在我在开发中安全了,远离了损坏的主分支。 或者,如果测试进展顺利:

git checkout chris
git merge main
git push
git branch -D dev
git checkout -b dev
git merge local

这会将 dev 变成 chris 的干净合并,其中合并了 main 上的最新内容,因此那些拉动 chris 分支的人将获得 main 上的最新内容加上我的更改,仅此而已 - 这意味着我不是向他们抛出额外的合并冲突。 但这确实意味着我不断失去开发历史。

This article covers this relatively well:

https://github.com/rrrene/gitscm-next/blob/master/app/views/blog/progit/2010-04-11-environment.markdown

Basically if you're working from the command-line this is simpler than you might guess. Suppose you want 2 git repos:

.gitone
.gittwo

You could set them up like so:

git init .
mv .git .gitone
git init .
mv .git .gittwo

You could add a file and commit it to only one like so:

git --git-dir=.gitone add test.txt
git --git-dir=.gitone commit -m "Test"

So the options for git come first, then the command, then the git command's options. You could easily enough alias a git command like:

#!/bin/sh
alias gitone='git --git-dir=.gitone'
alias gittwo='git --git-dir=.gittwo'

So you can commit to one or the other with a bit less typing, like gitone commit -m "blah".

What appears to get trickier is ignores. Since .gitignore normally sits in the project root, you'd need to find a way to switch this as well without switching the entire root. Or, you could use .git/info/exclude, but all the ignores you perform then won't be committed or pushed - which could screw up other users. Others using either repo might push a .gitignore, which may cause conflicts. It's not clear to me the best way to resolve these issues.

If you prefer GUI tools like TortoiseGit you'd also have some challenges. You could write a small script that renames .gitone or .gittwo to .git temporarily so these tools' assumptions are met.

Avoiding 2 Repos

You can accomplish a similar result by composing your branch, although you're still doing a fair bit of dancing to keep things going.

Suppose you have local files, like system-specific settings in the original question. You want to keep them out of your commits to other developers, but, you want them committed somewhere, as they're either essential to run, or, could be critical in debugging

Instead of 2 git repos you can do the following:

git checkout main
git checkout -b local
git add -A .
git commit -m "local changes"
git checkout main
git checkout -b chris
git checkout -b dev
git merge local

So, you started with local changes, that you put out on a branch called "local". You're never going to push this branch to the remote.

You set those changes aside, then made another branch off of main named with what you'll be pushing, for example named after you (in my case, "chris").

So far you have the 2 distinct branches, but, you don't have a way for them to work together. You make a third, Composed Branch - dev here is a composition of chris and local.

You do your dev in dev, then when it's time to push, you:

git checkout chris
git add -A .
git commit -m "My commit message"
git push

git checkout dev
git merge chris

This pushes the changes, clean out on chris, then comes back to dev and recomposes the branch. chris continues to remain squeaky clean, your meaningful changes are pushed, and the stuff you wanted to preserve locally stays safe on the local branch.

More special scenarios:

Pushing your local branch

Suppose you wanted to push your "local" branch afterall, for example if there's no important secrets in it and you're using git partly as a backup. Easy fix, just name the branch something long and very clear so no dev pulls it and expects it to work for them, like chris-local-settings. If you dislike typing that long name over and over (and tab completion isn't enough), branching the branch is super cheap:

git checkout chris-local-settings
git checkout -b local

Generated files

Suppose your local branch is more complex, and there are generated files that keep creating clutter. You need them to debug, but you never want to push them to your clean branch filled with just your, non-generated changes.

Your generated files probably follow a pattern, or if they don't, you probably have some say in where they generate when so they do follow a pattern. For example, if all you generated files appear in a folder named "bin" and you've just finished some important coding:

git checkout local
cd bin
git add -A .
git commit -m "Generated files"
cd ..
git checkout chris
git commit -m "Commit message about my clean handwritten changes"
git push
git checkout dev
git merge local
git merge chris

Because you know all your generated files are in the bin folder, you can just cd over and git add there. You cleanly dump them off in local, then back out to root and commit the rest to your clean branch. You then recompose your dev branch.

If in the future you need to know what your build looked like for a given day and time, you can recompose another branch, or, step back in time on the dev branch. That said, I usually throw out and recompose the dev branch often in my build, so, it has no history unfortunately:

Imagine some changes happened on main, and I need to verify they work before potentially poisoning my build:

git checkout main
git pull
git checkout dev
git checkout -b test
git merge main

Now I'd run tests to verify the build. If they go poorly:

git checkout dev
git branch -D test

And off I go to tell whoever last pushed to main, they broke it. Now I'm safe in dev away from the broken main branch. Or, if the tests go well:

git checkout chris
git merge main
git push
git branch -D dev
git checkout -b dev
git merge local

That turns dev into a clean merge of chris, which has the latest on main merged in, so those pulling the chris branch get what's latest on main plus my changes and nothing more - meaning I'm not throwing extra merge conflicts at them. But it does mean I keep losing history on dev.

当梦初醒 2024-07-18 20:09:26

如果我理解您在做什么,您可以在一个存储库中处理所有内容,为每台计算机使用单独的分支,以及包含公共主目录配置文件的分支。

初始化存储库并向其提交公共文件,也许将 MASTER 分支重命名为 Common。 然后为您使用的每台计算机创建一个单独的分支,并将特定于计算机的文件提交到该分支中。 每当您更改公共文件时,请将公共分支合并到每个计算机分支中并推送到其他计算机(如果有很多,请为此编写一个脚本)。

然后在每台机器上,签出该机器的分支,其中还将包括通用配置文件。

If I understand what you're doing, you can handle it all in one repository, using separate branches for each machine, and a branch containing your common home directory config files.

Initialize the repo and commit the common files to it, perhaps renaming the MASTER branch as Common. Then create a separate branch from there for each machine that you work with, and commit machine-specific files into that branch. Any time that you change your common files, merge the common branch into each of the machine branches and push to your other machines (write a script for that if there are many).

Then on each machine, checkout that machine's branch, which will also include the common config files.

假装不在乎 2024-07-18 20:09:26

查看 git 子模块

子模块允许外部存储库
嵌入专用的
源树的子目录,
总是指向特定的提交。

Have a look at git submodule.

Submodules allow foreign repositories
to be embedded within a dedicated
subdirectory of the source tree,
always pointed at a particular commit.

幸福丶如此 2024-07-18 20:09:26

RichiH 编写了一个名为 vcsh 的工具,该工具使用 git 的假裸存储库来管理点文件,以放置多个工作目录到 $HOME. AFAIK 与 csh 无关。

但是,如果您确实有多个目录,则 git-submodules 的替代方案(在最好的情况下这很痛苦,并且此示例用法不是最好的情况)是 gitslave ,它使从属存储库始终在分支的尖端签出,并且不需要三步过程来在附属存储库中进行更改(签出到正确的分支,进行并提交更改,然后进入超级项目并提交新的子模块提交)。

RichiH wrote a tool called vcsh which a tool to manage dotfiles using git's fake bare repos to put more than one working directory into $HOME. Nothing to do with csh AFAIK.

However, if you did have multiple directories, an alternative to git-submodules (which are a pain in the best of circumstances and this example usage is not the best of circumstances) is gitslave which leaves the slave repos checked out on the tip of a branch at all times and doesn't required the three step process to make a change in the subsidiary repo (checkout onto the correct branch, make & commit the change, then go into the superproject and commit the new submodule commit).

踏月而来 2024-07-18 20:09:26

可以通过使用变量 GIT_DIR 来实现,但如果您不知道自己在做什么,则有很多注意事项。

It is possible by using the variable GIT_DIR but has many caveats if you don't know what you are doing.

兔小萌 2024-07-18 20:09:26

我的首选方法是在子目录中使用存储库,并使用递归符号链接:

git clone repo1
cd somerepo
git clone repo2
cd repo2
./build

其中“repo/build”文件如下所示:

#!/bin/bash 
SELF_PATH="$(dirname "$(readlink -f "$0")" )"  # get current dir 
cd .. && git stash && git clean -f -d ''       # remove previous symlinks
cp -sR "$SELF_PATH"/* ../.                     # create recursive symlinks in root

警告:不要使用“git add” .'

my preferred method is using a repo in a subdir, and use recursive symbolic links:

git clone repo1
cd somerepo
git clone repo2
cd repo2
./build

where the 'repo/build'-file looks like:

#!/bin/bash 
SELF_PATH="$(dirname "$(readlink -f "$0")" )"  # get current dir 
cd .. && git stash && git clean -f -d ''       # remove previous symlinks
cp -sR "$SELF_PATH"/* ../.                     # create recursive symlinks in root

caution: dont use 'git add .'

风流物 2024-07-18 20:09:26

是的,一个目录中可以有两个 git 存储库。

我假设一个远程存储库位于 GitHub 中,另一个位于 GitLab 中。 我还使用两个不同的 SSH 密钥来连接到这些远程存储库。

您可以在 GitHub / GitLab 之一中拥有两个远程存储库(并使用单个 SSH 密钥) - 不会有太大变化。

先决条件

  • 公共 SSH 密钥 (id_ecdsa.pub / id_rsa.pub / id_ed25519.pub等)存在于您的 GitHub 和 GitLab 配置文件中

  • 私钥 SSH 密钥(id_ecdsa / id_rsa / id_ed25519 等)已添加并保留在操作系统的钥匙串中

  • SSH 配置文件包含密钥为 GitHub 和 GitLab 指定:

    托管 github.com 
        主机名 github.com 
        AddKeysToAgent 是 
        使用钥匙串 是 
        身份文件 ~/.ssh/id_ecdsa 
    
      托管 gitlab.com 
        主机名 gitlab.com 
        AddKeysToAgent 是 
        使用钥匙串 是 
        身份文件 ~/.ssh/id_rsa 
      

这里是Chris 的回答模拟工作流程的细分 strong>:

  • 初始化目录中的git:

    git init

  • 将 git 连接到一个远程存储库(位于 GitHub)

    git Remote add origin [电子邮件受保护]:您的-用户名/your-repo.git

  • .git 重命名为 .github

    mv .git .github

  • 再次初始化 git

    git init

  • 将git连接到另一个远程存储库(位于GitLab)

    git Remote add origin [电子邮件受保护]:您的-用户名/your-repo.git

  • .git 重命名为 .gitlab

    mv .git .gitlab

  • 验证当前目录是否连接到两个不同的远程存储库

    git --git-dir=.github远程-v

    git --git-dir=.gitlab远程-v

  • < p>拉取远程(GitHub 和 GitLab)存储库

    git --git-dir=.github pull origin main 
      git --git-dir=.gitlab 拉源 main 
      
  • 将文件添加到两个存储库

    git --git-dir=.github 添加 README.md 
      git --git-dir=.gitlab 添加 README.md 
      
  • 写入提交消息

    git --git-dir=.github commit -m "操作概述" 
      git --git-dir=.gitlab commit -m "操作概述" 
      
  • 推送到远程

    git --git-dir=.github Push -u origin main 
      git --git-dir=.gitlab推送-u origin main 
      

我们在这里做的唯一额外的事情是使用 --git-dir 标志。

如果您打算经常这样做,您可以在 shell 配置文件中添加一个别名(例如 .zprofilebashrc 等):

export github="git --git-dir=.github"
export gitlab="git --git-dir=.gitlab"

未来的操作,例如 pull< /code>、pushaddcommit 可以像 - github pull origin main一样执行gitlab pull origin main

Yes, it is possible to have two git repositories in one directory.

I'm assuming that one remote repository is in GitHub and the other in GitLab. I'm also using two different SSH keys to connect to these remote repositories.

You can have both remote repositories in one of GitHub / GitLab (and use a single SSH key) - not much would change.

Pre-requisites:

  • Public SSH keys (id_ecdsa.pub / id_rsa.pub / id_ed25519.pub , etc.) are present in your GitHub and GitLab profiles

  • Private SSH keys (id_ecdsa / id_rsa / id_ed25519 , etc.) are added and persisted in your OS's keychain

  • SSH config file has keys specified for GitHub and GitLab:

    Host github.com
      Hostname github.com
      AddKeysToAgent yes
      UseKeychain yes
      IdentityFile ~/.ssh/id_ecdsa
    
    Host gitlab.com
      Hostname gitlab.com
      AddKeysToAgent yes
      UseKeychain yes
      IdentityFile ~/.ssh/id_rsa
    

Here's a break down of Chris's answer emulating a workflow:

  • Initialize git in a directory:

    git init

  • Connect git to one remote repository (located in GitHub)

    git remote add origin [email protected]:your-username/your-repo.git

  • Rename .git to something like .github

    mv .git .github

  • Initialize git again

    git init

  • Connect git to the other remote repository (located in GitLab)

    git remote add origin [email protected]:your-username/your-repo.git

  • Rename .git to something like .gitlab

    mv .git .gitlab

  • Verify that current directory is connected to two different remote repositories

    git --git-dir=.github remote -v

    git --git-dir=.gitlab remote -v

  • Pull remote (GitHub and GitLab) repositories

    git --git-dir=.github pull origin main
    git --git-dir=.gitlab pull origin main
    
  • Add a file to both repositories

    git --git-dir=.github add README.md
    git --git-dir=.gitlab add README.md
    
  • Write commit message

    git --git-dir=.github commit -m "operational overview"
    git --git-dir=.gitlab commit -m "operational overview"
    
  • Push to remote

    git --git-dir=.github push -u origin main
    git --git-dir=.gitlab push -u origin main
    

The only additional thing we're doing here is using the --git-dir flag.

If you plan on doing this frequently you could add an alias in your shell config file (like .zprofile, bashrc, etc.):

export github="git --git-dir=.github"
export gitlab="git --git-dir=.gitlab"

Future operations like pull, push, add, commit can be performed like - github pull origin main, gitlab pull origin main, etc.

じее 2024-07-18 20:09:26

是的,子模块可能就是您想要的。 另一种选择是将工作副本放在子目录中,然后将符号链接从主目录指向感兴趣的文件。

Yeah, submodules are probably what you want. Another option would be to have your working copy in a subdirectory and then point symlinks from you home directory to the files of interest.

ˇ宁静的妩媚 2024-07-18 20:09:26

另一种选择是将它们放在单独的文件夹中,并创建从一个文件夹到另一个文件夹的符号硬链接。

例如,如果有存储库:

  1. Repo1/FolderA
  2. Repo1/FolderB

和:

  1. Repo2/FolderC

您可以将文件夹 FolderAFolderB 从 Repo1 符号链接到 Repo2。 对于 Windows,在 Repo1 上运行的命令是:

User@Repo1$ mklink /J FullPath/Repo2/FolderA FullPath/Repo1/FolderA
User@Repo1$ mklink /J FullPath/Repo2/FolderB FullPath/Repo1/FolderB
User@Repo1$ printf "/FolderA/*\n/FolderB/*\n" >> .gitignore

对于主存储库上的文件,您需要对每个文件进行符号链接,同时将它们添加到存储库 .gitignore 以避免噪音,除非您想要到它。

The other option is to they on separate folders and create symbolic hard links from one folder to the other.

For example, if there are the repositories:

  1. Repo1/FolderA
  2. Repo1/FolderB

And:

  1. Repo2/FolderC

You may symlink the folders FolderA and FolderB from the Repo1 into the Repo2. For windows the command to run on the Repo1 would be:

User@Repo1$ mklink /J FullPath/Repo2/FolderA FullPath/Repo1/FolderA
User@Repo1$ mklink /J FullPath/Repo2/FolderB FullPath/Repo1/FolderB
User@Repo1$ printf "/FolderA/*\n/FolderB/*\n" >> .gitignore

For the files on the main repositories you would need to symlink each one of them, also adding them to repository .gitignore to avoid noise, unless you want to it.

聚集的泪 2024-07-18 20:09:26

OP 希望将多个存储库中的文件合并到单个目录中。

但是,如果您不想合并,而是需要在单个目录中的存储库之间切换:

mkdir repo
cd repo
git init
git remote add first https://first/repo.git
git remote add second https://second/repo.git
git fetch first
git fetch second
git checkout first/master -b master

现在您可以在目录之间切换,甚至可以在存储库之间挑选提交。

OP wants merging files from multiple repositories to single directory.

But if you do not want mering and instead need switching between repositories in single directory:

mkdir repo
cd repo
git init
git remote add first https://first/repo.git
git remote add second https://second/repo.git
git fetch first
git fetch second
git checkout first/master -b master

Now you can switch between directories and even cherry-pick commits between repositories.

层林尽染 2024-07-18 20:09:26

免责声明:这不是广告。 我是所提供库的开发人员。

我创建了一个 git 扩展来处理您想要将多个存储库混合到一个文件夹中的情况。 该库的优点是跟踪存储库和文件冲突。 你可以在 github 上找到它。 还有 2 个示例存储库可供尝试。

Disclaimer: This is not advertising. I'm the developer of the provided library.

I've created a git extension to handle cases where you want to mix multiple repositories into one folder. The advantage of the lib is, to keep track of the repositories and file conflicts. you can find it on github. There are also 2 example repositories to try it out.

无人接听 2024-07-18 20:09:26

我看到了很多答案,但我有一个更简单的解决方案:

git remote rename origin old-origin
git remote add origin [email protected] # your git repository
git push -u origin --all
git push -u origin --tags

现在你在一个存储库中有两个 git!

在 gitgraken 中,你会看到这样的两个 git:

在此处输入图像描述

I see a lot of answers, but I have a simpler solution:

git remote rename origin old-origin
git remote add origin [email protected] # your git repository
git push -u origin --all
git push -u origin --tags

And now you have two gits in one repository!

In gitgraken you will see these two gits like this:

enter image description here

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文