How to set the Output and Intermeidate directory in visual studio to depend on the current git branch?

I am looking for a solution to avoid recompiling when going from branch to branch in git. Using different folders for different branches is a solution, but it just created havoc in my workflow.

The best solution I can think of is to pass the git branch as the $ options variable used in the project settings, so I can set the "Output Directory" to something like

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

      

Similar to the intermediate directory.

Can such a configuration be customized?

Edit: The problem is that even when the output / intermediate directory is different for each branch (or moved out of the archive when changing branches), the precompiled headers are always recompiled anyway, so the project is recompiled as well.

+3


source to share


3 answers


Solution 1

I think the OP's way of using is $(branch)

cool. But there is no way to create a custom macro with dynamic branch name value in Visual Studio

. And it is not possible if Visual Studio

reloads environment variables, if we add it to an event pre-build

after starting VS, unless it restarts. It seems like the easiest way is to just do it in a post-checkout

hook in the repository git

as stated @ConfusedSushi

.

I just tested the solution and it worked well. The details are as follows.

Create a git hook post-checkout

(filename is simple post-checkout

) and put it in GIT_DIR/.git/hooks

. It invokes the batch file set-branch.bat

.

#!/bin/bash

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

      

The batch file set-branch.bat

looks like this. And also put it in GIT_DIR/.git/hooks

.

@echo off

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

      

And then install Output directory

as OP:

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

      

Now, every time the branch is modified with git check

, the environment variable will be set branch

. And you need to restart Visual Studio

to get the value of the environment variable
. It just works the way you want it to.



Solution 2

Due to OP's comment, another solution is to let visual studio use the same folder, but move the output / intermediate directories in the hook after checking.

Just create a git hook post-checkout

with the following scripts. And replace my test folder below with Test/Test/Debug

your own real folder. And it can be an absolute directory or linked to a git repository.
... Folder assembly will be added branch name

as a suffix, if it is not the current branch.

#!/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

      

[Updated] . For the edited question, since precompiled headers always change when switching branches, projects are always recompiled. This is actually a solution, but a little dangerous .

VS

detects the modified time

source file to decide if it needs to be recompiled. So what can we do to change modified time

to deceptionVS

. We can do this with the command touch

.

But it's hard to decide what time is right. To make it practical, we can select a file that does not change when switching branches, and is relatively stable, and set the modified time

precompiled headers the same as the selected file. We can also do this in a hook post-checkout

.

touch -r some_stable_chosen_file precompiled_header

      

But we have to remember that this is unsafe because it can also ignore real changes in precompiled headers. We have to manually deal with this.

+4


source


You can set up the hook after checkout in git. This hook can run a batch file that identifies the current branch and passes this to an environment variable. You must use SETX to set a constant environment variable. In MsBuild-Files, you can use environment variables. So your suggested project setup should work then. Of course, you can also implement your hook in your favorite language using a batch file instead.



+1


source


This is a solution based on Landys answer that I actually use to avoid having to restart visual studio to reload the new environment variable value.

The script just uses the branches of the / <branch> directory for the intermediate / output directories of the branches. In the interception after scanning, the previous directories are moved to the archive, and the necessary ones are moved to their place.

#!/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

      

+1


source







All Articles