Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

.gitconfig includeif not available inside container #2084

Open
brettmillerb opened this issue Dec 23, 2019 · 22 comments
Open

.gitconfig includeif not available inside container #2084

brettmillerb opened this issue Dec 23, 2019 · 22 comments
Assignees
Labels
containers Issue in vscode-remote containers feature-request Request for new features or functionality

Comments

@brettmillerb
Copy link

  • VSCode Version:
    Version: 1.41.0-insider
    Commit: 599c076d91be1374cf51004cec610f3bcaf4c9cd
    Date: 2019-11-22T07:19:06.796Z
    Electron: 6.1.5
    Chrome: 76.0.3809.146
    Node.js: 12.4.0
    V8: 7.6.303.31-electron.0

  • Local OS Version:
    OS: Darwin x64 18.7.0

  • Remote OS Version:
    Debian 9 (mcr.microsoft.com/powershell)

  • Remote Extension/Connection Type: Docker

Steps to Reproduce:

  1. includeif in gitconfig is not honoured inside the developement container.

Local .gitconfig contains

[includeIf "gitdir/i:~/git/gitpersonal/"]
	path = ~/.gitconfig-personal

git config --list --show-origin

Local

file:/Users/brett.miller/.gitconfig     user.name=Brett Miller
file:/Users/brett.miller/.gitconfig     user.email=brett.miller@org.com
file:/Users/brett.miller/.gitconfig     includeif.gitdir/i:~/git/gitpersonal/.path=~/.gitconfig-personal
file:/Users/brett.miller/.gitconfig-personal    user.name=Brett Miller
file:/Users/brett.miller/.gitconfig-personal    user.email=brett@millerb.co.uk
file:/Users/brett.miller/.gitconfig     core.editor=code-insiders --wait

Devcontainer

file:/root/.gitconfig   user.name=Brett Miller
file:/root/.gitconfig   user.email=brett.miller@org.com
file:/root/.gitconfig   includeif.gitdir/i:~/git/gitpersonal/.path=~/.gitconfig-personal
file:/root/.gitconfig   core.editor=code-insiders --wait

Seen #1811 but didn't think it was the same thing.

@chrmarti chrmarti added containers Issue in vscode-remote containers feature-request Request for new features or functionality labels Jan 6, 2020
@sanmai-NL
Copy link

@brettmillerb Are the included files accessible from the container, though?

@brettmillerb
Copy link
Author

@brettmillerb Are the included files accessible from the container, though?

Not natively, they'd need to be copied into the container.

I think I had a look at the time to see if there was a COPY for the .gitconfig but couldn't find how the logic was derived between global, repo config copy.

@sanmai-NL
Copy link

Please do not copy this kind of stuff, you may end up baking an image with sensitive information inside it.

I use this in devcontainer.json:

{
    "mounts": ["source=${localEnv:HOME}${localEnv:USERPROFILE}/.config/git,target=/root/.config/git,type=bind,consistency=cached,readonly"],
}

The includeIf directive works if you control where you mount your project inside the container. If you emulate the full path, it should work. However, this kind of config is developer-specific, and you wouldn't want to change devcontainer.json with such details. So instead I just configure those few settings you list there as working copy-local settings (git config ....).

@brettmillerb
Copy link
Author

Please do not copy this kind of stuff, you may end up baking an image with sensitive information inside it.

I use this in devcontainer.json:

{
    "mounts": ["source=${localEnv:HOME}${localEnv:USERPROFILE}/.config/git,target=/root/.config/git,type=bind,consistency=cached,readonly"],
}

If I have to remember to set a mount in the devcontainer.json then it kind of negates the reasons I'm using includeif in the first place and I'd be better setting repo specific settings

The includeIf directive works if you control where you mount your project inside the container. If you emulate the full path, it should work. However, this kind of config is developer-specific, and you wouldn't want to change devcontainer.json with such details.

I generally only use local docker containers for developing projects rather than using SSH etc

So instead I just configure those few settings you list there as working copy-local settings (git config ....).

Not sure what you mean by copy-local settings?

I mainly use includeif so I don't forget to set my user and email config on repos so if the only option was to set something on a per repo basis e.g. devcontainer.json then I'll just stick to using git cli in an external terminal rather than the vscode integrations.

Appreciate this isn't everyone's usecase buts it's definitely a limitation

@sanmai-NL
Copy link

Please do not copy this kind of stuff, you may end up baking an image with sensitive information inside it.
I use this in devcontainer.json:

{
    "mounts": ["source=${localEnv:HOME}${localEnv:USERPROFILE}/.config/git,target=/root/.config/git,type=bind,consistency=cached,readonly"],
}

If I have to remember to set a mount in the devcontainer.json then it kind of negates the reasons I'm using includeif in the first place and I'd be better setting repo specific settings

I don't think so. Since you would have to reconfigure your per-repo settings on every clone, rather than once upstream per repo (and only for repos that should support both VS code dev containers and conditional Git config).

The includeIf directive works if you control where you mount your project inside the container. If you emulate the full path, it should work. However, this kind of config is developer-specific, and you wouldn't want to change devcontainer.json with such details.

I generally only use local docker containers for developing projects rather than using SSH etc

So instead I just configure those few settings you list there as working copy-local settings (git config ....).

Not sure what you mean by copy-local settings?

What you called repo specific settings.

I mainly use includeif so I don't forget to set my user and email config on repos so if the only option was to set something on a per repo basis e.g. devcontainer.json then I'll just stick to using git cli in an external terminal rather than the vscode integrations.

Appreciate this isn't everyone's usecase buts it's definitely a limitation

A bit more integrated would be to use a local terminal in a second Visual Studio Code window.

@sanmai-NL
Copy link

My robust, standard solution for this is to alter the conditional to only require a subdirectory that marks it as a Git hosting service/instance, instead of forcing it the be under the home directory.

~/.git/config

[user]
useConfigOnly = true

[includeIf "gitdir/i:devel/github/"]
path = github.gitconfig

I think VS Code should not apply additional logic to fix up path references in the Git config, and I believe this issue can be closed based on e.g. my solution. @brettmillerb, can you confirm to @chrmarti?

@brettmillerb
Copy link
Author

@sanmai-NL I've just ended up not using the git functionality inside of vscode and use local terminal to interact with git.

I can try and test this at some point to see if it's a better workflow.

@DC4JG
Copy link

DC4JG commented Sep 16, 2021

I'm currently stuck on this very issue.

I want to use the VSCode devcontainer support to offer developers a comfortable way of setting up the environment., extensions, etc. after they cloned the repository.

It works for trivial single user git configs but if an advanced multi user git config is encountered with usage of includeIf the whole git support inside the container breaks due to VSCode ignoring those other conditional include files, resulting in an incomplete git configuration.

The whole problem and missing support seems to be rooted even deeper than VSCode itself, since there is no way to export the currently active git configuration of a directory. git config --list shows the currently active settings but drops the ini file format, hence can't be used without extensive custom parsing to restore a valid gitconfig file.

This leaves the following options, all not desirable:

  • Force all developers to not use conditional git configs
  • Drop in-container git support and fall back to e.g. a parallel second non-containered VSCode instance for git usage
  • Extensive custom scripting to create valid local repository git configs prior to container invocation

Is there any less annoying solution or workaround available for this issue? 🤔

@chrmarti
Copy link
Contributor

You could use a dotfiles repository to bring in your own .gitconfig and files to include.

@sanmai-NL
Copy link

@DC4JG What doesn't work for you about the solution I outlined?

@DC4JG
Copy link

DC4JG commented Sep 19, 2021

@sanmai-NL I tried your conditional include without the explicit home path for the repository and config file but it made no difference for me. It still won't copy/set the included gitconfig file into the devcontainer. I don't have a path issue inside the container but that container creation not respects/fixes the active includes and breaks the config once inside it.
Maybe I'm missing your point, could you elaborate?

Rough explanation of my test setup:

~/
  .gitconfig // includes foo.config if in ~/foo
  foo.config // sets user name/email

~/foo/
  .git/ // normal git init
  .devcontainer/ // container setup

It takes ~/.gitconfig and ~/foo/.git/config into consideration for the container but the included foo.config is ignored.

It successfully sets the conditionals when checked in the foo folder in WSL2 via git config --list --show-origin but when I reopen the container there is only the include statement from the global git config left, missing the other file's configuration.


My goal is to not force any specific setup or required configurations upon the container user but if possible just take whatever they configured for git and is actually active/valid in the folder of the repository like foo from above example and shift it over to the container to be seamlessly integrated into normal OS/tooling/VSCode(Extensions)/Git/SSH/GPG... setup. Below my targeted workflow.

  • setup (advanced) git credentials and SSH key for access
  • git clone repository (with .devcontainer folder)
  • (open folder in VSCode if not already used for cloning)
  • click notification to reopen in container
  • (wait for Docker...) have a full IDE setup available and ready to work

This would greatly unify the developer environments, make onboarding much easier, keep the native operating system clutter free, enable easy unification of e.g. formatter, linting and other extensions configs and many other things which normally tend to cost a lot of time and effort to setup and slightly differ afterwards between people like person A installed X then Y but person B installed Y before X. If this whole process is encapsulated once, it can even be moved to remote servers/cloud if local machine resources become a limiting factor in the future.


We choose to go to the DevContainer in this setup and do the other things, not because they are easy, but because they are hard, because that goal will serve the organization and measure the best of our engineering and developer skills, because that challenge is one that we are willing to accept, one we are unwilling to postpone, and one which we intend to win, and the management, too.

@codemedic
Copy link

codemedic commented Dec 9, 2021

A workaround that seems to work is adding the below code to initializeCommand in devcontainer.json (on Linux / bash shell)

cd "${localWorkspaceFolder}" && git config --local user.name "$(git config user.name)" && git config --local user.email "$(git config user.email)"

The JSON fragment with quote escaping would be

"initializeCommand": "cd \"${localWorkspaceFolder}\" && git config --local user.email \"$(git config user.email)\" && git config --local user.name \"$(git config user.name)\""

It works only for gitdir patterns and not for onbranch based includes.

@andrealmar
Copy link

In my case the following error is occurring:

ERROR: for hello_world_devcontainer_app_1  Cannot start service app: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: error mounting "/host_mnt/Users/andrealmar/.gitconfig" to rootfs at "/root/.gitconfig": mount /host_mnt/Users/andrealmar/.gitconfig:/root/.gitconfig (via /proc/self/fd/14), flags: 0x5000: not a directory: unknown: Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host path exists and is the expected type

VSCode expects a directory not a file. If I delete the file and create the directory then git in my local machine complains that I don't have a .gitconfig file.

@jbouchery
Copy link

Hi !

Same problem here, i'm using includeIf to use different email addresses and ssh keys but cannot use git within the container. I'll continue to use git outside the container for the moment.

@blieusong
Copy link

Hi,

same issue. Since the "included" git config files are not bond to the container, the includeIf fails.

Two possibilities?

  1. binding all "includedIf" files to the container (forcing relocating them to a same directory for simplicity)
  2. processing the includeIf before binding to the container?

Sorry I can only suggest... I don't code in javascript or typescript.

@yongkanm
Copy link

yongkanm commented Jun 28, 2023

Update: To handle whitespacce characters in the workspace path or workspace folder name, ${localWorkspaceFolder} and ${containerWorkspaceFolder} need to be escaped.

Inspired by @codemedic's solution, here is a workaround to make the process a little more generic:

In devcontainer.json, add:

{
    "initializeCommand": "git config -l > \"${localWorkspaceFolder}\"/.devcontainer/.gitconfig.all && git config --local -l > \"${localWorkspaceFolder}\"/.devcontainer/.gitconfig.local",
    "postAttachCommand": "cd \"${containerWorkspaceFolder}\"/.devcontainer && /bin/bash ./attach.sh"
}

Create file .devcontainer/attach.sh:

#!/bin/bash

LOCAL_GITCONFIG="./.gitconfig.local"
ALL_GITCONFIG="./.gitconfig.all"

if [[ -f "$LOCAL_GITCONFIG" && -f "$ALL_GITCONFIG" ]]; then
  while IFS= read -r line
  do
    if ! grep -Fxq "$line" $LOCAL_GITCONFIG
    then
      key=$(echo $line | cut -d '=' -f 1)
      value=$(echo $line | cut -d '=' -f 2-)
      git config --file ~/.gitconfig "$key" "$value"
    fi
  done < $ALL_GITCONFIG
  rm -rf "$LOCAL_GITCONFIG" "$ALL_GITCONFIG"
fi

The code above adds all git config that is nonlocal to ~/.gitconfig in devcontainer. Two temporary files (./.gitconfig.local and./.gitconfig.all) are created to store git config.

Note: This workaround only passes the git config into devcontainer. If your git config needs other files (e.g., need IdentityFile to specify the correct SSH key (see #5207)), other workarounds are required.

@shtamura
Copy link

On Mac OS, if you want to use the gitconfig environment (using ssh authentication + signed commit) specified by includeIf in the devcontainer environment, you can do it as follows.

  1. Follow the steps below to add the ssh key to ssh-agent and install GPGTool

  2. Make adjustments using the following properties in devcontainer.json so that the path to gitdir and gitconfig specified in includeIf from the container is resolved in the same way as locally.

    • workspaceMount
    • workspaceFolder
    • mounts

This may be a late post, but I hope it helps someone.

@fclad
Copy link

fclad commented Jul 31, 2024

Here's a variant of @yongkanm's solution that I am using in my setups. Posting it here in case it can help others.

Add the following lines to .devcontainer.json

{
  "initializeCommand": "git config -l --global --include > \"${localWorkspaceFolder}\"/.gitconfig.global",
  "postAttachCommand": "while IFS='=' read -r key value; do git config --global \"$key\" \"$value\"; done < \"${containerWorkspaceFolder}\"/.gitconfig.global; rm -f \"${containerWorkspaceFolder}\"/.gitconfig.global"
}

Explanation:

  • The initializeCommand runs outside the container. It exports the global git configuration with all applicable include directives to a temporary .gitconfig.global file in the workspace folder.
  • The postAttachCommand imports that configuration (as global) inside the devcontainer and deletes the temporary file.

Tested on MacOS host with Linux-based devcontainer.

@fclad
Copy link

fclad commented Aug 12, 2024

@azutmp , good point! This was only tested on a MacOS host. I've now edited the previous post to indicate that.

It seems from your error that the initializeCommand needs to be tweaked to run on Windows, but I don't know how. :-(

@stewartadam
Copy link
Member

stewartadam commented Aug 14, 2024

Bumping into this as well.

devcontainer is already building .gitconfig in the container; it would make sense that it also parse the global configuration with includes when doing so, and then let Git resolve local configuration as usual.

We probably want to ignore some config entries like credential helpers which are OS-specific.

@stewartadam
Copy link
Member

stewartadam commented Aug 14, 2024

@azutmp , good point! This was only tested on a MacOS host. I've now edited the previous post to indicate that.

It seems from your error that the initializeCommand needs to be tweaked to run on Windows, but I don't know how. :-(

The error stems from having a file path in the command, since cmd.exe is interpreting the path separator as a argument flag to cmd.exe. Note the spec specifies that initializeCommand is run in the source code working directory, so we don't need the absolute pathing at all:

in devcontainer.json:

{
  // ...
  "initializeCommand": {
    "extractGitGlobals": "git config -l --global --include > .gitconfig.global",
    "extractGitLocals": "git config -l --local --include > .gitconfig.local"
  },
  "postAttachCommand": "/bin/bash .devcontainer/post-attach.sh",

In .devcontainer/post-attach.sh:

#!/bin/bash
set -eu

# Re-configures git global and local configuration with includes
# https://github.com/microsoft/vscode-remote-release/issues/2084
for conf in .gitconfig.global .gitconfig.local; do
  if [ -f $conf ]; then
    echo "*** Parsing ${conf##.gitconfig.} Git configuration export"
    while IFS='=' read -r key value; do
      case "$key" in
      user.name | user.email | user.signingkey | commit.gpgsign)
        echo "Set Git config ${key}=${value}"
        git config --global "$key" "$value"
        ;;
      esac
    done <"$conf"
    rm -f "$conf"
  fi
done

The post-attach.sh script is a little different than others posted prior:

  • It sets configuration entries from both the global and local configuration, in case users have configured Git to include configuration in the local repository (which also won't be made available in the devcontainer). We parse global first to continue to let local overrides take precedence.
  • Only the user.name, user.email, user.signingkey, and commit.gpgsign properties are set - remove the case block if you don't want this. For my users, copying all settings produced other difficulties (eg. difftool not being available) and it was simpler to just copy the bare minimum to get GPG signing working.

This is tested on both Windows and MacOS.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
containers Issue in vscode-remote containers feature-request Request for new features or functionality
Projects
None yet
Development

No branches or pull requests

13 participants