检出子目录

时间:2016-07-02 22:26:13

标签: git git-checkout

我正在尝试检查特定目录“code / app”中的所有文件和子目录,但git为我提供了代码/ app目录及其内容。我只想要它的内容。我想在post-receive git hook中使用它。

git checkout -f master -- code/app

我也试过以下无济于事

git checkout -f master -- code/app/*

git checkout -f master -- code/app/.

如何获得上述预期行为?

更新

后接收

#!/usr/bin/env ruby
# post-receive

# Read STDIN
from, to, branch = ARGF.read.split " "

if (branch =~ /master$/)
        puts "Received branch #{branch}, deploying."

        # Copy files to deploy directory
        deploy_to_dir = File.expand_path('../development')
        dir_to_checkout = '06\ -\ Code/app/'
        `GIT_WORK_TREE="#{deploy_to_dir}" git checkout -f master -- #{dir_to_checkout}`
        puts "DEPLOY: master(#{to}) copied to '#{deploy_to_dir}'"

        exit
end

# Only deploy if pre-production branch was pushed
if (branch =~ /pre-production$/)
        puts "Received branch #{branch}, deploying."

        # Copy files to deploy directory
        deploy_to_dir = File.expand_path('../staging')
        dir_to_checkout = '06\ -\ Code/app/'
        `GIT_WORK_TREE="#{deploy_to_dir}" git checkout -f pre-production -- #{dir_to_checkout}`
        puts "DEPLOY: pre-production(#{to}) copied to '#{deploy_to_dir}'"

        exit
end

if (branch =~ /production$/)
        puts "Received branch #{branch}, deploying."

        # Copy files to deploy directory
        deploy_to_dir = File.expand_path('../')
        dir_to_checkout = '06\ -\ Code/app/'
        `GIT_WORK_TREE="#{deploy_to_dir}" git checkout -f production -- #{dir_to_checkout}`
        puts "DEPLOY: production(#{to}) copied to '#{deploy_to_dir}'"

        exit
end

3 个答案:

答案 0 :(得分:0)

我不是Ruby专家,但幸运的是,这似乎并不重要:我可以阅读您的代码应该做的事情(虽然没有说明它是否有任何特定于Ruby的问题)。

如果我稍微改一下你的问题,你会说:

  

git checkout命令主要执行我想要的操作:

git checkout -f <branch> -- <dir-path>
     

e.g。

git checkout -f master -- Code/app/
     

提取名为Code/app/somedir/somefile的所有文件。我不喜欢的部分是,当我希望它们只在Code/app/somedir/somefile时,它会将它们放在名为somedir/somefile的文件中。

方法重命名文件,但没有一种方法简单易行,至少与仅仅进行结帐然后重命名文件相比。这样做 - 结帐,然后重命名文件 - 可能就是你应该做的。

但这里有一些微妙的问题。

首先,这种特殊形式的git checkout只需在工作树中添加或替换文件。假设在您的某个部署分支(masterpre-productionproduction)中,您删除某些不需要的文件。部署脚本将添加或更新任何已添加或更新的文件,但不会删除文件,因此不会从部署区域中删除已删除的文件。

(对于某些文件,你可能想要这种行为。对于#34;只是正确的文件&#34;它可能会很棘手。)

其次,您的脚本似乎部署名称​​以这三个名称结尾的任何分支。这在实践中可能不是问题:谁将命名他们的分支fred/master?但是,如果有人这样做,你可能会做错事,除非 喜欢部署这样的分支。最好检查引用名称是字面refs/heads/masterrefs/heads/pre-production和/或refs/heads/production

最后......好吧,这个很复杂。请记住,Git有一个名为 index 临时区域(或有时缓存)的东西:当你git add个文件时,你是将它们复制到索引中,当你git commit时,Git会获取索引内容的快照,这将成为新的提交。我认为Git文档强调的一个含义是,始终的索引包含将在下一次提交中的每个文件。 (并且在提交之后,索引是&#34;空&#34;,因为几个命令和文档的含义暗示:相反,它充满了你刚刚提交的所有内容。)< / p>

git checkout命令利用了这个事实,这可能会让你感到悲伤。

您在这些不同的结帐命令之前设置变量GIT_WORK_TREE,但您设置GIT_INDEX_FILE。因此,Git将使用 索引文件 - 每个单独的标准文件,相同的文件 - 用于这些不同的结帐命令。

为什么索引文件对于结帐

很重要

Git努力优化结帐。其中一些只是为了速度,有些是因为一个&#34;开关分支&#34;故意检查 clobber工作树更改,让您将它们带到新分支,以防您的意图。 (有关详细信息,请参阅Git - checkout another branch when there are uncommitted changes on the current branch。)无论哪种方式,Git都使用此技巧:

  • 如果索引条目显示正确的文件已经到位,并且工作树中的文件不是索引时间戳更新,请不要触摸工作 - 树文件。

也就是说,假设我们假装是Git,我们正在做git checkout $branch(有或没有-- Code/app或其他:有和没有相似之处,但对于下一个案例我们可以使用一个测试)。我们将分支名称$branch转换为提交ID,并将其转换为树ID,并开始查看树及其子树。我们找到了一个名为Code/app/xyz.rb的文件。我们查看索引/缓存,并看到它有Code/app/xyz.rb的条目。

索引的条目显示&#34; blob a123456...已安装为Code/app/xyz.rb,时间戳为1467505093(2016年7月2日星期六17:18:13)。我们检查工作树文件Code/app/xyz.rb。通过lstat呼叫获得的时间戳为1467500000(同一天下午3:33左右,即几小时前)。嗯,这很奇怪,它又回到过去了,但很明显它没有被改变因为我们上次检查了它 - 所以让我们把它留在原地!

但是,请问,我们是如何首先陷入这种情况的?好吧,大约两个小时前我们跑去部署pre-production。我们(记住,&#34;我们&#34;这里是我们 - 正在Git-checkout)实际上已经将Git blob a123456...复制到工作树Code/app/xyz.rb时间。但是$GIT_WORK_TREE然后是&#34; / some / path / to / preprod / area&#34;,现在它&#34; / some / path / to / master / area&#34;

我们必须在这两点之前的某个时刻部署master,以便该文件存在于当前工作树中。但是当我们这样做时,master的树说使用Git blob 01234567而不是a123456。然后,两个小时前,我们被要求部署pre-production,并且特定Code/app/xyz.rb已更新为版本a123456。现在我们要求重新部署master,其Code/app/xyz.rb应该a123456,但我们发现我们已经部署了版本{{1 - 它在索引中! - 从那时起工作树版本还没有被编辑过,所以一定很好。

(它并不好,那是不同的工作树。但我们不知道:索引不记录工作树的路径;我们&# 39;重新假设现在a123456$GIT_WORK_TREE相同。)

有几种方法可以在这里起作用:

  • 删除工作树,以便Git必须重新部署每个文件。

    这种方法具有简单的优点。它的缺点是让Git复制出每个文件。当然,如果您要重命名工作树的子目录,这个&#34;只是工作&#34;无论如何,这可能是一个很好的方式。

  • 删除索引(缓存),以便Git必须重新部署每个文件。

    这几乎和以前一样。 Git将重建索引。

  • 每个工作树使用一个索引。

    这是最复杂的方法,但应该是最有效的方法。此外,它是新的(自Git版本2.5)$GIT_WORK_TREE命令以及git worktree add将隐藏所有复杂性。如果你的Git足够新,你可以用新的worktree功能替换这个有点复杂的部署脚本。

答案 1 :(得分:0)

只需执行基础操作,不要费心更新(甚至检查)HEAD

git read-tree -um `git write-tree` master:code/app

绕过便利命令并直接执行您想要的操作。你没有检查开发分支,没有提交你正在检查的内容。 git write-tree现在为树中的列表中的列出,master:code/app命名master提交中的树,双树git read-tree -um在索引和工作树中进行转换。

如果您要维护多个工作树,请通过将GIT_INDEX_FILE导出为“$GIT_DIR/index”之外的内容来维护每个工作树的索引。

答案 2 :(得分:0)

@torek,@ jthill我从你的帖子中学到了很多东西。那里有好主意。但是,我选择使用PM2,它可以很好地从客户端计算机上完成。我还发现shipit是我问题中说明的问题的另一种选择。