【问题标题】:How to setup the Output and Intermeidate directory in visual studio to be dependent on current git branch?如何在 Visual Studio 中设置输出和中间目录以依赖于当前的 git 分支?
【发布时间】:2014-09-14 14:01:49
【问题描述】:

我正在寻找一种解决方案,以避免在 git 中从一个分支移动到另一个分支时进行大量重新编译。 为不同的分支使用不同的文件夹是一种解决方案,但它只会在我的工作流程中造成混乱。

我能想到的最佳解决方案是将 git 分支作为项目设置中使用的选项 $ 变量传递,这样我就可以将“输出目录”设置为类似

..\bin\$(branch)\$(Configuration)$(Platform)\

与中间目录类似。

可以配置这样的东西吗?

编辑: 问题是,即使每个分支的输出/中间目录不同(或者在更改分支时从存档中移动),预编译的头文件总是会重新编译,因此项目也会重新编译。

【问题讨论】:

    标签: git visual-studio compilation git-branch


    【解决方案1】:

    解决方案 1

    我认为 OP 使用 $(branch) 的方式很酷。但是无法使用Visual Studio 中分支名称的动态值创建用户宏。如果我们在VS启动后将pre-build事件添加到pre-build事件中,Visual Studio要么不可能重新加载环境变量,除非它重新启动。似乎最直接的方法就是在git 存储库中的post-checkout 中挂钩,就像@ConfusedSushi 提到的那样。

    我刚刚测试了解决方案,它运行良好。详情如下。

    创建git hookpost-checkout(文件名就是post-checkout,放入GIT_DIR/.git/hooks,会调用一个批处理文件set-branch.bat

    #!/bin/bash
    
    if [ "$3" -eq "1" ]; then
        cmd.exe /c "`pwd`/.git/hooks/set-branch.bat" 
    fi
    

    批处理文件set-branch.bat如下。并将其放入GIT_DIR/.git/hooks

    @echo off
    
    for /f %%i in ('git rev-parse --abbrev-ref HEAD') do setx branch %%i
    

    然后像 OP 一样设置Output directory

    ..\bin\$(branch)\$(Configuration)$(Platform)\
    

    现在,每次通过git check 更改分支时,都会设置一个环境变量branch。而你需要重启Visual Studio才能获取环境变量值。它只是根据您的需要工作。

    解决方案 2

    由于 OP 的评论,另一种解决方案是让 Visual Studio 使用相同的文件夹,但在结帐后挂钩中移动 Output/intermediate 目录。

    只需使用以下脚本创建一个 git hook post-checkout。并且用您自己的真实文件夹替换Test/Test/Debug 下面的我的测试文件夹。可以是绝对目录,也可以是与git仓库相关的目录。构建文件夹如果不是当前分支,会添加branch name作为后缀。

    #!/bin/bash
    
    build_folder=Test/Test/Debug
    if [ "$3" -eq "1" ]; then
        oldref=$(git reflog | awk 'NR==1{ print $6; exit }')
        newref=$(git rev-parse --abbrev-ref HEAD)
    
        if [ "$oldref" != "$newref" ]; then
            if [ -d "$build_folder-$oldref" ]; then
                rm -rf "$build_folder-$oldref"
                echo "Deleted $build_folder-$oldref"
            fi
    
            if [ -d "$build_folder" ]; then
                mv "$build_folder" "$build_folder-$oldref"
                echo "Moved $build_folder to $build_folder-$oldref"
            fi
    
            if [ -d "$build_folder-$newref" ]; then
                mv "$build_folder-$newref" "$build_folder"
                echo "Moved $build_folder-$newref to $build_folder"
            fi
        fi
    fi
    

    [已更新] 对于已编辑的问题,由于切换分支时预编译的头文件总是会发生变化,因此项目总是会重新编译。其实有解决办法,但是有点危险

    VS 检测源文件的modified time 来决定是否需要重新编译。所以我们能做的就是modified time改成作弊VS。我们可以使用命令touch 来完成。

    但很难决定哪个时间合适。为了实用,我们可以选择一个不会因为切换分支而改变的文件,而且也比较稳定,将预编译头文件的modified time设置为和选择的文件一样。我们也可以在post-checkout 钩子中实现。

    touch -r some_stable_chosen_file precompiled_header
    

    但我们应该记住它是不安全的,因为它也可能忽略对预编译头文件的实际更改。我们必须手动处理它。

    【讨论】:

    • 好的,是否可以自动重启Visual Studio?如果需要重新启动?也许让Visual Studio使用相同的文件夹会更好,但是将Output/intermediate目录移动到pre/post-checkout分支中?
    • 我认为最好不要在脚本中重新启动,因为您可能打开了多个解决方案,脚本可能必须将它们全部关闭并重新启动。但是您只需要重新启动与分支切换相关的一项即可。第二个问题很重要。如果可行,我会稍后尝试并更新答案。
    • @kovarex 已更新答案。有任何问题请告诉我。
    • 问题是,即使我在移动文件时,项目的预编译头文件 (Compile.hpp) 也会重新编译,因此整个项目会再次重新编译。我不知道可能是什么原因。我也尝试移动 ipch 文件夹,但没有帮助。
    • @kovarex 它在我的测试中有效。您的预编译头文件或项目文件在不同分支之间是否相同?如果它们不同,git checkout 将重新加载这些文件。而VS会检测到这些变化,认为应该重新编译。
    【解决方案2】:

    您可以在 git 中设置结帐后挂钩。这个钩子可以运行一个批处理文件,该文件确定当前分支并将其传递给环境变量。您应该使用SETX 将环境变量设置为永久设置。在 MsBuild-Files 中,您可以使用环境变量。因此,您建议的项目设置应该可以工作。当然你也可以用你喜欢的语言来实现你的钩子,而不是使用批处理文件。

    【讨论】:

      【解决方案3】:

      这是基于我实际使用的 Landys 答案的解决方案,以避免重新启动 Visual Studio 以重新加载环境变量的新值。

      脚本只使用目录branches/ 作为分支的中间/输出目录。在 post-checkout 钩子中,之前的目录被移动到存档中,而需要的目录被移动到它们的位置。

      #!/bin/bash
      
      prevHEAD=$1                                                                      
      newHEAD=$2                                                                       
      checkoutType=$3                                                                  
      
      if [ $checkoutType -ne 1 ] ; then exit ; fi
      
      prevBranch=`git name-rev --name-only $prevHEAD`
      newBranch=`git name-rev --name-only $newHEAD`
      
      targetDir=vs-2013-files/branches/$prevBranch
      mkdir -p $targetDir
      mv vs-2013-files/*Win32 vs-2013-files/*Win32Lib vs-2013-files/*x64 vs-2013-files/*x64Lib $targetDir 2>/dev/null
      mv bin $targetDir 2>/dev/null
      
      sourceDir=vs-2013-files/branches/$newBranch
      mv $sourceDir/*Win32 $sourceDir/*Win32Lib $sourceDir/*x64 $sourceDir/*x64Lib vs-2013-files    2>/dev/null
      mv $sourceDir/bin . 2>/dev/null
      

      【讨论】:

      • git name-rev --name-only $prevHEAD 有问题。如果dev1dev2 等两个分支指向同一个提交对象,则即使从dev2 签出到另一个分支,脚本也只会得到一个分支名称,如dev1。你可以参考我的回答。
      猜你喜欢
      • 2012-04-08
      • 2021-05-30
      • 2010-10-15
      • 1970-01-01
      • 2021-03-03
      • 2021-06-10
      • 2015-08-31
      • 2017-04-06
      • 2011-03-16
      相关资源
      最近更新 更多