假设我有一个目录/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)。
有可能吗?有插图吗?
答案 0 :(得分:3)
你的要求不是我所说的那种清晰明确的要求 一般文件所有权区域,但这里有几种方法可以做到; 希望你找到一个符合你实际需要的。
你最有可能说出自己真的需要这样做。 它永远不会像你想要的那样原子,如此多余 你自己的复杂性。
如果失败......
对于大多数操作系统,您可以通过伪造来欺骗自己的出路 文件系统级别的重复。你好像拒绝这个因为 需要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有意义。然后添加,提交并将它们推送到您的位置 希望他们存储。
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
之外)是复制文件的命令。
您可以从“直接”提交到本地裸存储库 外。 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
可以远程完成所有这些,但据我所知,没有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 add
和git commit
最终完成的步骤。通过git内部命令复制它们最终会导致很多工作,很容易发生事故。如果你真的需要谨慎地做这个线程,并理解git为你处理的底层结构,这样你就可以使用它并修改它。