承诺使用不同的路径git?

时间:2013-10-27 09:55:51

标签: git

假设我有一个目录/home/userX/whatever结构化:

./wrapper
./wrapper/folder_A
./wrapper/folder_A/file_1
./wrapper/folder_A/file_2
./wrapper/folder_B
./wrapper/folder_B/file_3
./wrapper/folder_B/file_4

我想将它们提交到git repo /home/userX/somewhere/repo.git中,并在git树中使用此结构:

./blah
./blah/folder_A
./blah/folder_A/file_1
./blah/folder_A/file_2
./blah/folder_B
./blah/folder_B/file_3
./blah/folder_B/file_4

无需将这些文件1~4复制或移动到另一个文件夹或不得不触及系统权限(userX不是sudoer)。

有可能吗?有插图吗?

3 个答案:

答案 0 :(得分:3)

你的要求不是我所说的那种清晰明确的要求 一般文件所有权区域,但这里有几种方法可以做到; 希望你找到一个符合你实际需要的。

0级 - 不要那样做

你最有可能说出自己真的需要这样做。 它永远不会像你想要的那样原子,如此多余 你自己的复杂性。

如果失败......

等级1-硬链接

对于大多数操作系统,您可以通过伪造来欺骗自己的出路 文件系统级别的重复。你好像拒绝这个因为 需要root或sudo,但它比其他任何东西都容易得多 不得不提一下它。

在过去,你刚​​刚将whatever/wrapper硬连接起来 目录到cheat/blah,但现在似乎已经被弃用了 我的例子将使用绑定挂载。

git clone /home/userX/somewhere/repo.git level1
cd level1
mkdir blah
sudo mount --bind /home/userX/whatever/wrapper blah
git add blah
git commit
git push
sudo umount blah

简单地说:将要提交的文件挂载到其中的位置 他们对git有意义。然后添加,提交并将它们推送到您的位置 希望他们存储。

2级 - 没有cp

您可以通过直接在存储库中散列文件来备用副本。

git clone /home/userX/somewhere/repo.git level2
cd level2
for f in folder_A/file_1 folder_A/file_2 folder_B/file_3 folder_B/file_4
do
  sha=$(git hash-object -w /home/userX/whatever/wrapper/$f)
  git update-index --add --cacheinfo 644 $sha blah/$f
done

然后像往常一样提交和推送:

git commit
git push

请注意,git hash-object -w命令(显然除了git push之外)是复制文件的命令。

3级 - 无克隆

您可以从“直接”提交到本地裸存储库 外。 blob散列部分仅与2级相同 没有克隆。构建实际的提交将会有点过时 更棘手。

首先,我们需要创建一个引用新的索引的更新索引 文件。由于git没有真正的任何东西 命令在外部树上操作(我们不想依赖 在内部格式上太多了,我们将使用二级索引 我们最初将从存储库的头部复制。除此之外, 它看起来与2级相似。

mkdir level3
cd level3
export GIT_DIR=/home/userX/somewhere/repo.git
export GIT_INDEX_FILE=hack
git read-tree HEAD
for f in folder_A/file_1 folder_A/file_2 folder_B/file_3 folder_B/file_4
do
  sha=$(git hash-object -w /home/userX/whatever/wrapper/$f)
  git update-index --add --cacheinfo 644 $sha blah/$f
done
tree=$(git write-tree)

现在您可以创建一个提交对象并更新HEAD。

parent=$(git rev-parse HEAD)
commit=$(git commit-tree -p $parent -m Your_message_here $tree)
git update-ref HEAD $commit $parent

不要忘记在你身后清理:

rm hack
unset GIT_DIR GIT_INDEX_FILE

等级4-远程

可以远程完成所有这些,但据我所知,没有git 管道命令将帮助我们。 git send-pack假定当地人 存储库,这似乎超出了范围。所以你需要写一个 专用的git协议客户端。

结束思路

如果您的目标是实现所有这一切的可携带性,那么您应该:

  • 进一步调查--path
  • git hash-object选项
  • 确保避免在辅助索引名称上命名冲突

答案 1 :(得分:2)

通过边带索引导入您想要的内容

loaded_tree=$(
    export GIT_INDEX_FILE=$PWD/.git/throwaway
    export GIT_DIR=$PWD/.git
    rm -f .git/throwaway

    export GIT_WORK_TREE=/home/userX/whatever/wrapper
    cd $GIT_WORK_TREE

    git add folder_A folder_B  # add contents (relative to GIT_WORK_TREE)
    git add anything else      # . to repo, record locations ditto in index

    git write-tree             # make an honest tree of it
)

并将其加载到您想要的地方

git checkout --orphan newbranch
git read-tree --empty          # (wipe it because `--prefix=` merges)
git read-tree  $loaded_tree --prefix=blah/
git commit -m "You're done."       

答案 2 :(得分:1)

使用git internal commands非常有可能。注意以下命令,因为这些命令与git用于表示文件结构的文件混在一起,如果使用不正确,可能会导致损坏或错误的状态。

这将仅遵循单个文件的创建,其余文件将遵循类似的过程。所有这些命令都是从提到的repo.git文件夹运行的,该文件夹被假定为--bare存储库:

> cd /home/userX/somewhere

第一步是创建包含要提交的文件的git对象。此命令将在git对象存储中创建文件的压缩副本。这个副本是不可避免的,因为内部副本git需要保留你的文件版本:

> git hash-object -w /home/userX/whatever/wrapper/folder_A/file_1
cafebabe00000000000000000000000000000000

打印的哈希是为存储file_1而创建的对象。哈希当然是虚构的,因为它取决于文件的实际内容。

为了创建file_1所在的子文件夹,您需要为每个子文件夹级别创建一个树对象。注意创建的哈希如何用于下一个子文件夹树:

> echo -e "100644 blob cafebabe00000000000000000000000000000000\tfile_1" | git mktree
1111face11111111111111111111111111111111

> echo -e "040000 tree 1111face11111111111111111111111111111111\tfolder_a" | git mktree
2222face22222222222222222222222222222222

最后一个哈希是将添加到当前树的哈希。如果在--bare仓库中工作,我们需要先创建一个干净的索引。如果您在普通存储库中工作,则可以跳过此步骤,因为已存在索引文件,只需确保git status显示干净状态。

--bare回购中,应该没有索引文件,但万一有,请将其删除:

> rm index

要创建一个干净的索引文件,我们添加要提交的分支的内容,我们将假设master。此命令将打印当前树的内容master,并将其设置为当前索引:

> git cat-file -p master^{tree} | git update-index --index-info

现在有了一个干净的索引,我们添加了包含树的子目录,该树指向我们手动添加的文件。 read-tree将获取给定的树形哈希,并将其作为--prefix中所述的子文件夹添加到当前索引中:

> git read-tree --prefix=blah 2222face22222222222222222222222222222222

然后我们创建另一个树,代表索引的当前状态。 write-tree将从当前索引中读取并从中生成树形哈希:

> git write-tree
deadbeafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

最后一个哈希是我们用来创建提交的哈希:

> echo "at last a commit" | git commit-tree deadbeafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -p master
baddcafe11111111111111111111111111111111

最后但并非最不重要的是,我们更新master以指向新提交:

> git branch --force master baddcafe11111111111111111111111111111111

然后我们设法将git添加到文件而不必将其复制到工作区。所有这些步骤都是git addgit commit最终完成的步骤。通过git内部命令复制它们最终会导致很多工作,很容易发生事故。如果你真的需要谨慎地做这个线程,并理解git为你处理的底层结构,这样你就可以使用它并修改它。