190

I am trying to stage a project from a working directory to a server (same machine). Using the following code:

gulp.src([
    'index.php',
    'css/**',
    'js/**',
    'src/**',
])
.pipe(gulp.dest('/var/www/'));

I would expect to see all the files copied. However it flattens the dir structure - all directories are copied but every file is placed in the root /var/www

Gulp seems like a great build tool but copying items should be a simple process surely?

3
  • 11
    To any new viewers reading this question, it should be noted that the highest voted answer doesn't work to solve the original question specification of not flattening directories. It does solve problems people are having with not all the files inside a directory from being copied, so that's useful!
    – M1ke
    Commented Sep 11, 2015 at 8:10
  • 2
    By not flattening, do you mean that you want 'css', 'js', and 'src' directories to be present in /var/www/? You could try {css,js,src}/**/* Commented May 14, 2016 at 14:42
  • I know that glob expansion does work inside gulp, but I'd be confused if that worked differently to each item as an individual line in a list - as glob expansion is basically just intended to expand to a list before execution.
    – M1ke
    Commented May 16, 2016 at 12:03

4 Answers 4

348

The following works without flattening the folder structure:

gulp.src(['input/folder/**/*']).pipe(gulp.dest('output/folder'));

The '**/*' is the important part. That expression is a glob which is a powerful file selection tool. For example, for copying only .js files use: 'input/folder/**/*.js'

6
  • 2
    think you forgot to add the gulp.dest. Should be .pipe(gulp.dest('output/folder')); Commented Dec 16, 2014 at 0:09
  • 3
    How do you do this with a specific file extension?
    – CatDadCode
    Commented Mar 19, 2015 at 22:40
  • 3
    May you edit the answer to provide an example for the original set of files? I am unsure how this is more appropriate but I'd be happy to look at how it works compared to the {base:"."} method.
    – M1ke
    Commented Mar 26, 2015 at 10:08
  • 2
    It is important to note that the base default is "folder" as given in this answer. In other words, the base starts where the glob pattern begins. This helped me to understand where my files would end up and is also why you don't need the **/* in the gulp.dest parameter. Gulp takes everything in the glob and puts it in the dest folder with the same structure. Commented Sep 22, 2015 at 22:46
  • 4
    This doesn't fully answer the question being asked. It's a nice solution for how to correctly copy recursively, but it doesn't answer how to modify the base directory.
    – ty1824
    Commented Oct 1, 2015 at 8:56
183

Turns out that to copy a complete directory structure gulp needs to be provided with a base for your gulp.src() method.

So gulp.src( [ files ], { "base" : "." }) can be used in the structure above to copy all the directories recursively.

If, like me, you may forget this then try:

gulp.copy=function(src,dest){
    return gulp.src(src, {base:"."})
        .pipe(gulp.dest(dest));
};
2
  • 1
    Add "cwd" configuration to set current working directory.
    – Skarllot
    Commented Apr 1, 2016 at 4:07
  • 5
    If base is still confusing you, take a look at stackoverflow.com/a/35848322/11912 which does a great job of explaining it. Commented Oct 12, 2017 at 2:41
64

So - the solution of providing a base works given that all of the paths have the same base path. But if you want to provide different base paths, this still won't work.

One way I solved this problem was by making the beginning of the path relative. For your case:

gulp.src([
    'index.php',
    '*css/**/*',
    '*js/**/*',
    '*src/**/*',
])
.pipe(gulp.dest('/var/www/'));

The reason this works is that Gulp sets the base to be the end of the first explicit chunk - the leading * causes it to set the base at the cwd (which is the result that we all want!)

This only works if you can ensure your folder structure won't have certain paths that could match twice. For example, if you had randomjs/ at the same level as js, you would end up matching both.

This is the only way that I have found to include these as part of a top-level gulp.src function. It would likely be simple to create a plugin/function that could separate out each of those globs so you could specify the base directory for them, however.

4
  • I think that having to start with multiple base paths probably goes beyond the scope of the question. From my original question I was moving the files to an absolute path, but the problem still occurred, that without specifying a base, all files from all my globs were copied into a single directory without their existing hierarchy being followed.
    – M1ke
    Commented Oct 1, 2015 at 8:02
  • 2
    @M1ke It is true, the main point of your question wasn't directed at varying base paths. However, you mentioned However it flattens the dir structure - all directories are copied but every file is placed in the root /var/www, and this is actually how I found your question - I was searching for a solution of how to copy recursively with different base paths. Essentially, this solution works for your case without having to specify a default base, but also for a multi-base path case, as long as you can ensure that the leading star matches nothing :)
    – ty1824
    Commented Oct 1, 2015 at 8:52
  • 6
    This answer is exceptional. It deals specifically with copying a path from an arbitrary start point, eg. src could be 'assets/subdir/*fonts/*' to copy the fonts dir.
    – Wtower
    Commented Feb 24, 2016 at 16:18
  • I did some digging, and found that to eliminate the chance of mismatches, you can use @(css)/**/*, for example. This will keep the folder structure but @() means it'll only match for that folder specifically (you could also provide several folders). See glob's documentation for more info. npmjs.com/package/glob Commented Sep 21, 2021 at 20:03
-4

If you want to copy the entire contents of a folder recursively into another folder, you can execute the following windows command from gulp:

xcopy /path/to/srcfolder /path/to/destfolder /s /e /y

The /y option at the end is to suppress the overwrite confirmation message.

In Linux, you can execute the following command from gulp:

cp -R /path/to/srcfolder /path/to/destfolder

you can use gulp-exec or gulp-run plugin to execute system commands from gulp.

Related Links:

  1. xcopy usage

  2. gulp-exec and gulp-run

1
  • 8
    The issue with falling back to shell here is that you'd lose the ability to run other commands on the stream, such as compression or analytics tools.
    – M1ke
    Commented Sep 25, 2015 at 10:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.