diff --git a/src/bin/cargo.rs b/src/bin/cargo.rs
index 72db84d251d..62556279d59 100644
--- a/src/bin/cargo.rs
+++ b/src/bin/cargo.rs
@@ -69,6 +69,7 @@ macro_rules! each_subcommand{
         $mac!(generate_lockfile);
         $mac!(git_checkout);
         $mac!(help);
+        $mac!(init);
         $mac!(install);
         $mac!(locate_project);
         $mac!(login);
diff --git a/src/bin/init.rs b/src/bin/init.rs
new file mode 100644
index 00000000000..c5e4cb66d47
--- /dev/null
+++ b/src/bin/init.rs
@@ -0,0 +1,53 @@
+use std::env;
+
+use cargo::ops;
+use cargo::util::{CliResult, Config};
+
+#[derive(RustcDecodable)]
+struct Options {
+    flag_verbose: bool,
+    flag_quiet: bool,
+    flag_color: Option<String>,
+    flag_bin: bool,
+    arg_path: Option<String>,
+    flag_name: Option<String>,
+    flag_vcs: Option<ops::VersionControl>,
+}
+
+pub const USAGE: &'static str = "
+Create a new cargo package in current directory
+
+Usage:
+    cargo init [options] [<path>]
+    cargo init -h | --help
+
+Options:
+    -h, --help          Print this message
+    --vcs VCS           Initialize a new repository for the given version
+                        control system (git or hg) or do not initialize any version
+                        control at all (none) overriding a global configuration.
+    --bin               Use a binary instead of a library template
+    --name NAME         Set the resulting package name
+    -v, --verbose       Use verbose output
+    -q, --quiet         No output printed to stdout
+    --color WHEN        Coloring: auto, always, never
+";
+
+pub fn execute(options: Options, config: &Config) -> CliResult<Option<()>> {
+    debug!("executing; cmd=cargo-init; args={:?}", env::args().collect::<Vec<_>>());
+    try!(config.shell().set_verbosity(options.flag_verbose, options.flag_quiet));
+    try!(config.shell().set_color_config(options.flag_color.as_ref().map(|s| &s[..])));
+
+    let Options { flag_bin, arg_path, flag_name, flag_vcs, .. } = options;
+
+    let opts = ops::NewOptions {
+        version_control: flag_vcs,
+        bin: flag_bin,
+        path: &arg_path.unwrap_or(format!(".")),
+        name: flag_name.as_ref().map(|s| s.as_ref()),
+    };
+
+    try!(ops::init(opts, config));
+    Ok(None)
+}
+
diff --git a/src/cargo/ops/cargo_new.rs b/src/cargo/ops/cargo_new.rs
index 18cfeb88ff2..a855403d1ee 100644
--- a/src/cargo/ops/cargo_new.rs
+++ b/src/cargo/ops/cargo_new.rs
@@ -2,6 +2,7 @@ use std::env;
 use std::fs;
 use std::io::prelude::*;
 use std::path::Path;
+use std::collections::BTreeMap;
 
 use rustc_serialize::{Decodable, Decoder};
 
@@ -24,6 +25,19 @@ pub struct NewOptions<'a> {
     pub name: Option<&'a str>,
 }
 
+struct SourceFileInformation {
+    relative_path: String,
+    target_name: String,
+    bin: bool,
+}
+
+struct MkOptions<'a> {
+    version_control: Option<VersionControl>,
+    path: &'a Path,
+    name: &'a str,
+    source_files: Vec<SourceFileInformation>,
+}
+
 impl Decodable for VersionControl {
     fn decode<D: Decoder>(d: &mut D) -> Result<VersionControl, D::Error> {
         Ok(match &try!(d.read_str())[..] {
@@ -44,38 +58,234 @@ struct CargoNewConfig {
     version_control: Option<VersionControl>,
 }
 
-pub fn new(opts: NewOptions, config: &Config) -> CargoResult<()> {
-    let path = config.cwd().join(opts.path);
-    if fs::metadata(&path).is_ok() {
-        bail!("destination `{}` already exists", path.display())
+fn get_name<'a>(path: &'a Path, opts: &'a NewOptions, config: &Config) -> CargoResult<&'a str> {
+    if let Some(name) = opts.name {
+        return Ok(name);
     }
-    let name = match opts.name {
-        Some(name) => name,
-        None => {
-            let dir_name = try!(path.file_name().and_then(|s| s.to_str()).chain_error(|| {
-                human(&format!("cannot create a project with a non-unicode name: {:?}",
-                               path.file_name().unwrap()))
-            }));
-            if opts.bin {
-                dir_name
-            } else {
-                let new_name = strip_rust_affixes(dir_name);
-                if new_name != dir_name {
-                    let message = format!(
-                        "note: package will be named `{}`; use --name to override",
-                        new_name);
-                    try!(config.shell().say(&message, BLACK));
-                }
-                new_name
-            }
+    
+    if path.file_name().is_none() {
+        bail!("cannot auto-detect project name from path {:?} ; use --name to override",
+                              path.as_os_str());
+    }
+    
+    let dir_name = try!(path.file_name().and_then(|s| s.to_str()).chain_error(|| {
+        human(&format!("cannot create a project with a non-unicode name: {:?}",
+                       path.file_name().unwrap()))
+    }));
+    
+    if opts.bin {
+        Ok(dir_name)
+    } else {
+        let new_name = strip_rust_affixes(dir_name);
+        if new_name != dir_name {
+            let message = format!(
+                "note: package will be named `{}`; use --name to override",
+                new_name);
+            try!(config.shell().say(&message, BLACK));
         }
-    };
+        Ok(new_name)
+    }
+}
+
+fn check_name(name: &str) -> CargoResult<()> {
     for c in name.chars() {
         if c.is_alphanumeric() { continue }
         if c == '_' || c == '-' { continue }
-        bail!("Invalid character `{}` in crate name: `{}`", c, name)
+        bail!("Invalid character `{}` in crate name: `{}`\n\
+               use --name to override crate name",
+              c, name)
+    }
+    Ok(())
+}
+
+fn detect_source_paths_and_types(project_path : &Path, 
+                                 project_name: &str, 
+                                 detected_files: &mut Vec<SourceFileInformation>,
+                                 ) -> CargoResult<()> {
+    let path = project_path;
+    let name = project_name;
+    
+    enum H {
+        Bin,
+        Lib,
+        Detect,
+    }
+    
+    struct Test {
+        proposed_path: String,
+        handling: H,
+    }
+        
+    let tests = vec![
+        Test { proposed_path: format!("src/main.rs"),     handling: H::Bin },
+        Test { proposed_path: format!("main.rs"),         handling: H::Bin },
+        Test { proposed_path: format!("src/{}.rs", name), handling: H::Detect },
+        Test { proposed_path: format!("{}.rs", name),     handling: H::Detect },
+        Test { proposed_path: format!("src/lib.rs"),      handling: H::Lib },
+        Test { proposed_path: format!("lib.rs"),          handling: H::Lib },
+    ];
+    
+    for i in tests {
+        let pp = i.proposed_path;
+        
+        // path/pp does not exist or is not a file
+        if !fs::metadata(&path.join(&pp)).map(|x| x.is_file()).unwrap_or(false) {
+            continue;
+        }
+        
+        let sfi = match i.handling {
+            H::Bin => {
+                SourceFileInformation { 
+                    relative_path: pp, 
+                    target_name: project_name.to_string(), 
+                    bin: true 
+                }
+            }
+            H::Lib => {
+                SourceFileInformation { 
+                    relative_path: pp, 
+                    target_name: project_name.to_string(), 
+                    bin: false
+                }
+            }
+            H::Detect => {
+                let content = try!(paths::read(&path.join(pp.clone())));
+                let isbin = content.contains("fn main");
+                SourceFileInformation { 
+                    relative_path: pp, 
+                    target_name: project_name.to_string(), 
+                    bin: isbin 
+                }
+            }
+        };
+        detected_files.push(sfi);
+    }
+    
+    // Check for duplicate lib attempt
+    
+    let mut previous_lib_relpath : Option<&str> = None;
+    let mut duplicates_checker : BTreeMap<&str, &SourceFileInformation> = BTreeMap::new();
+        
+    for i in detected_files {
+        if i.bin {
+            if let Some(x) = BTreeMap::get::<str>(&duplicates_checker, i.target_name.as_ref()) {
+                bail!("\
+multiple possible binary sources found:
+  {}
+  {}
+cannot automatically generate Cargo.toml as the main target would be ambiguous",
+                      &x.relative_path, &i.relative_path);
+            }
+            duplicates_checker.insert(i.target_name.as_ref(), i);
+        } else {
+            if let Some(plp) = previous_lib_relpath {
+                return Err(human(format!("cannot have a project with \
+                                         multiple libraries, \
+                                         found both `{}` and `{}`",
+                                         plp, i.relative_path)));
+            }
+            previous_lib_relpath = Some(&i.relative_path);
+        }
+    }
+    
+    Ok(())
+}
+
+fn plan_new_source_file(bin: bool, project_name: String) -> SourceFileInformation {
+    if bin {
+        SourceFileInformation { 
+             relative_path: "src/main.rs".to_string(),
+             target_name: project_name,
+             bin: true,
+        }
+    } else {
+        SourceFileInformation {
+             relative_path: "src/lib.rs".to_string(),
+             target_name: project_name,
+             bin: false,
+        }
     }
-    mk(config, &path, name, &opts).chain_error(|| {
+}
+
+pub fn new(opts: NewOptions, config: &Config) -> CargoResult<()> {
+    let path = config.cwd().join(opts.path);
+    if fs::metadata(&path).is_ok() {
+        bail!("destination `{}` already exists",
+              path.display())
+    }
+    
+    let name = try!(get_name(&path, &opts, config));
+    try!(check_name(name));
+
+    let mkopts = MkOptions {
+        version_control: opts.version_control,
+        path: &path,
+        name: name,
+        source_files: vec![plan_new_source_file(opts.bin, name.to_string())],
+    };
+    
+    mk(config, &mkopts).chain_error(|| {
+        human(format!("Failed to create project `{}` at `{}`",
+                      name, path.display()))
+    })
+}
+
+pub fn init(opts: NewOptions, config: &Config) -> CargoResult<()> {
+    let path = config.cwd().join(opts.path);
+    
+    let cargotoml_path = path.join("Cargo.toml");
+    if fs::metadata(&cargotoml_path).is_ok() {
+        bail!("`cargo init` cannot be run on existing Cargo projects")
+    }
+    
+    let name = try!(get_name(&path, &opts, config));
+    try!(check_name(name));
+    
+    let mut src_paths_types = vec![];
+    
+    try!(detect_source_paths_and_types(&path, name, &mut src_paths_types));
+    
+    if src_paths_types.len() == 0 {
+        src_paths_types.push(plan_new_source_file(opts.bin, name.to_string()));
+    } else {
+        // --bin option may be ignored if lib.rs or src/lib.rs present
+        // Maybe when doing `cargo init --bin` inside a library project stub,
+        // user may mean "initialize for library, but also add binary target"
+    }
+    
+    let mut version_control = opts.version_control;
+    
+    if version_control == None {
+        let mut num_detected_vsces = 0;
+        
+        if fs::metadata(&path.join(".git")).is_ok() {
+            version_control = Some(VersionControl::Git);
+            num_detected_vsces += 1;
+        }
+        
+        if fs::metadata(&path.join(".hg")).is_ok() {
+            version_control = Some(VersionControl::Hg);
+            num_detected_vsces += 1;
+        }
+        
+        // if none exists, maybe create git, like in `cargo new`
+        
+        if num_detected_vsces > 1 {
+            bail!("both .git and .hg directories found \
+                              and the ignore file can't be \
+                              filled in as a result, \
+                              specify --vcs to override detection");
+        }
+    }
+    
+    let mkopts = MkOptions {
+        version_control: version_control,
+        path: &path,
+        name: name,
+        source_files: src_paths_types,
+    };
+    
+    mk(config, &mkopts).chain_error(|| {
         human(format!("Failed to create project `{}` at `{}`",
                       name, path.display()))
     })
@@ -99,14 +309,13 @@ fn existing_vcs_repo(path: &Path, cwd: &Path) -> bool {
     GitRepo::discover(path, cwd).is_ok() || HgRepo::discover(path, cwd).is_ok()
 }
 
-fn mk(config: &Config, path: &Path, name: &str,
-      opts: &NewOptions) -> CargoResult<()> {
+fn mk(config: &Config, opts: &MkOptions) -> CargoResult<()> {
+    let path = opts.path;
+    let name = opts.name;
     let cfg = try!(global_config(config));
     let mut ignore = "target\n".to_string();
     let in_existing_vcs_repo = existing_vcs_repo(path.parent().unwrap(), config.cwd());
-    if !opts.bin {
-        ignore.push_str("Cargo.lock\n");
-    }
+    ignore.push_str("Cargo.lock\n");
 
     let vcs = match (opts.version_control, cfg.version_control, in_existing_vcs_repo) {
         (None, None, false) => VersionControl::Git,
@@ -117,15 +326,19 @@ fn mk(config: &Config, path: &Path, name: &str,
 
     match vcs {
         VersionControl::Git => {
-            try!(GitRepo::init(path, config.cwd()));
-            try!(paths::write(&path.join(".gitignore"), ignore.as_bytes()));
+            if !fs::metadata(&path.join(".git")).is_ok() {
+                try!(GitRepo::init(path, config.cwd()));
+            }
+            try!(paths::append(&path.join(".gitignore"), ignore.as_bytes()));
         },
         VersionControl::Hg => {
-            try!(HgRepo::init(path, config.cwd()));
-            try!(paths::write(&path.join(".hgignore"), ignore.as_bytes()));
+            if !fs::metadata(&path.join(".hg")).is_ok() {
+                try!(HgRepo::init(path, config.cwd()));
+            }
+            try!(paths::append(&path.join(".hgignore"), ignore.as_bytes()));
         },
         VersionControl::NoVcs => {
-            try!(fs::create_dir(path));
+            try!(fs::create_dir_all(path));
         },
     };
 
@@ -139,6 +352,32 @@ fn mk(config: &Config, path: &Path, name: &str,
         (Some(name), None, _, None) |
         (None, None, name, None) => name,
     };
+    
+    let mut cargotoml_path_specifier = String::new();
+    
+    // Calculare what [lib] and [[bin]]s do we need to append to Cargo.toml
+    
+    for i in &opts.source_files {
+        if i.bin {
+            if i.relative_path != "src/main.rs" {
+                cargotoml_path_specifier.push_str(&format!(r#"
+[[bin]]
+name = "{}"
+path = {}
+"#, i.target_name, toml::Value::String(i.relative_path.clone())));
+            }
+        } else {
+            if i.relative_path != "src/lib.rs" {
+                cargotoml_path_specifier.push_str(&format!(r#"
+[lib]
+name = "{}"
+path = {}
+"#, i.target_name, toml::Value::String(i.relative_path.clone())));
+            }
+        }
+    }
+
+    // Create Cargo.toml file with necessary [lib] and [[bin]] sections, if needed
 
     try!(paths::write(&path.join("Cargo.toml"), format!(
 r#"[package]
@@ -147,25 +386,40 @@ version = "0.1.0"
 authors = [{}]
 
 [dependencies]
-"#, name, toml::Value::String(author)).as_bytes()));
+{}"#, name, toml::Value::String(author), cargotoml_path_specifier).as_bytes()));
 
-    try!(fs::create_dir(&path.join("src")));
 
-    if opts.bin {
-        try!(paths::write(&path.join("src/main.rs"), b"\
+    // Create all specified source files 
+    // (with respective parent directories) 
+    // if they are don't exist
+
+    for i in &opts.source_files {
+        let path_of_source_file = path.join(i.relative_path.clone());
+        
+        if let Some(src_dir) = path_of_source_file.parent() {
+            try!(fs::create_dir_all(src_dir));
+        }
+    
+        let default_file_content : &[u8] = if i.bin {
+            b"\
 fn main() {
     println!(\"Hello, world!\");
 }
-"));
-    } else {
-        try!(paths::write(&path.join("src/lib.rs"), b"\
+"
+        } else {
+            b"\
 #[cfg(test)]
 mod test {
     #[test]
     fn it_works() {
     }
 }
-"));
+"
+        };
+    
+        if !fs::metadata(&path_of_source_file).map(|x| x.is_file()).unwrap_or(false) {
+            return paths::write(&path_of_source_file, default_file_content)
+        }
     }
 
     Ok(())
diff --git a/src/cargo/ops/mod.rs b/src/cargo/ops/mod.rs
index c8924833aa9..806d3921a6e 100644
--- a/src/cargo/ops/mod.rs
+++ b/src/cargo/ops/mod.rs
@@ -8,7 +8,7 @@ pub use self::cargo_rustc::{BuildOutput, BuildConfig, TargetConfig};
 pub use self::cargo_rustc::{CommandType, CommandPrototype, ExecEngine, ProcessEngine};
 pub use self::cargo_run::run;
 pub use self::cargo_install::{install, install_list, uninstall};
-pub use self::cargo_new::{new, NewOptions, VersionControl};
+pub use self::cargo_new::{new, init, NewOptions, VersionControl};
 pub use self::cargo_doc::{doc, DocOptions};
 pub use self::cargo_generate_lockfile::{generate_lockfile};
 pub use self::cargo_generate_lockfile::{update_lockfile};
diff --git a/src/cargo/util/paths.rs b/src/cargo/util/paths.rs
index 1f08ea6dd7d..2e9397df6c4 100644
--- a/src/cargo/util/paths.rs
+++ b/src/cargo/util/paths.rs
@@ -1,6 +1,7 @@
 use std::env;
 use std::ffi::{OsStr, OsString};
 use std::fs::File;
+use std::fs::OpenOptions;
 use std::io::prelude::*;
 use std::path::{Path, PathBuf, Component};
 
@@ -87,6 +88,21 @@ pub fn write(path: &Path, contents: &[u8]) -> CargoResult<()> {
     })
 }
 
+pub fn append(path: &Path, contents: &[u8]) -> CargoResult<()> {
+    (|| -> CargoResult<()> {
+        let mut f = try!(OpenOptions::new()
+                            .write(true)
+                            .append(true)
+                            .create(true)
+                            .open(path));
+
+        try!(f.write_all(contents));
+        Ok(())
+    }).chain_error(|| {
+        internal(format!("failed to write `{}`", path.display()))
+    })
+}
+
 #[cfg(unix)]
 pub fn path2bytes(path: &Path) -> CargoResult<&[u8]> {
     use std::os::unix::prelude::*;
diff --git a/tests/test_cargo_init.rs b/tests/test_cargo_init.rs
new file mode 100644
index 00000000000..f36ea06e9a9
--- /dev/null
+++ b/tests/test_cargo_init.rs
@@ -0,0 +1,315 @@
+use std::fs::{self, File};
+use std::io::prelude::*;
+use std::env;
+use tempdir::TempDir;
+use support::{execs, paths, cargo_dir};
+use hamcrest::{assert_that, existing_file, existing_dir, is_not};
+
+use cargo::util::{process, ProcessBuilder};
+
+fn setup() {
+}
+
+fn cargo_process(s: &str) -> ProcessBuilder {
+    let mut p = process(&cargo_dir().join("cargo"));
+    p.arg(s).cwd(&paths::root()).env("HOME", &paths::home());
+    return p;
+}
+
+test!(simple_lib {
+    assert_that(cargo_process("init").arg("--vcs").arg("none")
+                                    .env("USER", "foo"),
+                execs().with_status(0));
+
+    assert_that(&paths::root().join("Cargo.toml"), existing_file());
+    assert_that(&paths::root().join("src/lib.rs"), existing_file());
+    assert_that(&paths::root().join(".gitignore"), is_not(existing_file()));
+
+    assert_that(cargo_process("build"),
+                execs().with_status(0));
+});
+
+test!(simple_bin {
+    let path = paths::root().join("foo");
+    fs::create_dir(&path).unwrap();
+    assert_that(cargo_process("init").arg("--bin").arg("--vcs").arg("none")
+                                    .env("USER", "foo").cwd(&path),
+                execs().with_status(0));
+
+    assert_that(&paths::root().join("foo/Cargo.toml"), existing_file());
+    assert_that(&paths::root().join("foo/src/main.rs"), existing_file());
+
+    assert_that(cargo_process("build").cwd(&path),
+                execs().with_status(0));
+    assert_that(&paths::root().join(&format!("foo/target/debug/foo{}",
+                                             env::consts::EXE_SUFFIX)),
+                existing_file());
+});
+
+fn bin_already_exists(explicit: bool, rellocation: &str) {
+    let path = paths::root().join("foo");
+    fs::create_dir_all(&path.join("src")).unwrap();
+    
+    let sourcefile_path = path.join(rellocation);
+    
+    let content = br#"
+        fn main() {
+            println!("Hello, world 2!");
+        }
+    "#;
+    
+    File::create(&sourcefile_path).unwrap().write_all(content).unwrap();
+    
+    if explicit {
+        assert_that(cargo_process("init").arg("--bin").arg("--vcs").arg("none")
+                                        .env("USER", "foo").cwd(&path),
+                    execs().with_status(0));
+    } else {
+        assert_that(cargo_process("init").arg("--vcs").arg("none")
+                                        .env("USER", "foo").cwd(&path),
+                    execs().with_status(0));
+    }
+
+    assert_that(&paths::root().join("foo/Cargo.toml"), existing_file());
+    assert_that(&paths::root().join("foo/src/lib.rs"), is_not(existing_file()));
+    
+    // Check that our file is not overwritten
+    let mut new_content = Vec::new();
+    File::open(&sourcefile_path).unwrap().read_to_end(&mut new_content).unwrap();
+    assert_eq!(Vec::from(content as &[u8]), new_content);
+}
+
+test!(bin_already_exists_explicit {
+    bin_already_exists(true, "src/main.rs")
+});
+
+test!(bin_already_exists_implicit {
+    bin_already_exists(false, "src/main.rs")
+});
+
+test!(bin_already_exists_explicit_nosrc {
+    bin_already_exists(true, "main.rs")
+});
+
+test!(bin_already_exists_implicit_nosrc {
+    bin_already_exists(false, "main.rs")
+});
+
+test!(bin_already_exists_implicit_namenosrc {
+    bin_already_exists(false, "foo.rs")
+});
+
+test!(bin_already_exists_implicit_namesrc {
+    bin_already_exists(false, "src/foo.rs")
+});
+
+test!(confused_by_multiple_lib_files {
+    let path = paths::root().join("foo");
+    fs::create_dir_all(&path.join("src")).unwrap();
+    
+    let sourcefile_path1 = path.join("src/lib.rs");
+    
+    File::create(&sourcefile_path1).unwrap().write_all(br#"
+        fn qqq () {
+            println!("Hello, world 2!");
+        }
+    "#).unwrap();
+    
+    let sourcefile_path2 = path.join("lib.rs");
+    
+    File::create(&sourcefile_path2).unwrap().write_all(br#"
+        fn qqq () {
+            println!("Hello, world 3!");
+        }
+    "#).unwrap();
+    
+    assert_that(cargo_process("init").arg("--vcs").arg("none")
+                                    .env("USER", "foo").cwd(&path),
+                execs().with_status(101).with_stderr("\
+cannot have a project with multiple libraries, found both `src/lib.rs` and `lib.rs`
+"));
+    
+    assert_that(&paths::root().join("foo/Cargo.toml"), is_not(existing_file()));
+});
+
+
+test!(multibin_project_name_clash {
+    let path = paths::root().join("foo");
+    fs::create_dir(&path).unwrap();
+    
+    let sourcefile_path1 = path.join("foo.rs");
+    
+    File::create(&sourcefile_path1).unwrap().write_all(br#"
+        fn main () {
+            println!("Hello, world 2!");
+        }
+    "#).unwrap();
+    
+    let sourcefile_path2 = path.join("main.rs");
+    
+    File::create(&sourcefile_path2).unwrap().write_all(br#"
+        fn main () {
+            println!("Hello, world 3!");
+        }
+    "#).unwrap();
+    
+    assert_that(cargo_process("init").arg("--vcs").arg("none")
+                                    .env("USER", "foo").cwd(&path),
+                execs().with_status(101).with_stderr("\
+multiple possible binary sources found:
+  main.rs
+  foo.rs
+cannot automatically generate Cargo.toml as the main target would be ambiguous
+"));
+                
+    assert_that(&paths::root().join("foo/Cargo.toml"), is_not(existing_file()));
+});
+
+fn lib_already_exists(rellocation: &str) {
+    let path = paths::root().join("foo");
+    fs::create_dir_all(&path.join("src")).unwrap();
+    
+    let sourcefile_path = path.join(rellocation);
+    
+    let content = br#"
+        pub fn qqq() {}
+    "#;
+    
+    File::create(&sourcefile_path).unwrap().write_all(content).unwrap();
+    
+    assert_that(cargo_process("init").arg("--vcs").arg("none")
+                                    .env("USER", "foo").cwd(&path),
+                execs().with_status(0));
+
+    assert_that(&paths::root().join("foo/Cargo.toml"), existing_file());
+    assert_that(&paths::root().join("foo/src/main.rs"), is_not(existing_file()));
+    
+    // Check that our file is not overwritten
+    let mut new_content = Vec::new();
+    File::open(&sourcefile_path).unwrap().read_to_end(&mut new_content).unwrap();
+    assert_eq!(Vec::from(content as &[u8]), new_content);
+}
+
+test!(lib_already_exists_src {
+    lib_already_exists("src/lib.rs")
+});
+
+test!(lib_already_exists_nosrc {
+    lib_already_exists("lib.rs")
+});
+
+test!(simple_git {
+    assert_that(cargo_process("init").arg("--vcs").arg("git")
+                                    .env("USER", "foo"),
+                execs().with_status(0));
+
+    assert_that(&paths::root().join("Cargo.toml"), existing_file());
+    assert_that(&paths::root().join("src/lib.rs"), existing_file());
+    assert_that(&paths::root().join(".git"), existing_dir());
+    assert_that(&paths::root().join(".gitignore"), existing_file());
+});
+
+test!(auto_git {
+    let td = TempDir::new("cargo").unwrap();
+    let foo = &td.path().join("foo");
+    fs::create_dir_all(&foo).unwrap();
+    assert_that(cargo_process("init").cwd(foo.clone())
+                                     .env("USER", "foo"),
+                execs().with_status(0));
+
+    assert_that(&foo.join("Cargo.toml"), existing_file());
+    assert_that(&foo.join("src/lib.rs"), existing_file());
+    assert_that(&foo.join(".git"), existing_dir());
+    assert_that(&foo.join(".gitignore"), existing_file());
+});
+
+test!(invalid_dir_name {
+    let foo = &paths::root().join("foo.bar");
+    fs::create_dir_all(&foo).unwrap();
+    assert_that(cargo_process("init").cwd(foo.clone())
+                                     .env("USER", "foo"),
+                execs().with_status(101).with_stderr("\
+Invalid character `.` in crate name: `foo.bar`
+use --name to override crate name
+"));
+
+    assert_that(&foo.join("Cargo.toml"), is_not(existing_file()));
+});
+
+test!(git_autodetect {
+    fs::create_dir(&paths::root().join(".git")).unwrap();
+    
+    assert_that(cargo_process("init")
+                                    .env("USER", "foo"),
+                execs().with_status(0));
+    
+
+    assert_that(&paths::root().join("Cargo.toml"), existing_file());
+    assert_that(&paths::root().join("src/lib.rs"), existing_file());
+    assert_that(&paths::root().join(".git"), existing_dir());
+    assert_that(&paths::root().join(".gitignore"), existing_file());
+});
+
+
+test!(mercurial_autodetect {
+    fs::create_dir(&paths::root().join(".hg")).unwrap();
+    
+    assert_that(cargo_process("init")
+                                    .env("USER", "foo"),
+                execs().with_status(0));
+    
+
+    assert_that(&paths::root().join("Cargo.toml"), existing_file());
+    assert_that(&paths::root().join("src/lib.rs"), existing_file());
+    assert_that(&paths::root().join(".git"), is_not(existing_dir()));
+    assert_that(&paths::root().join(".hgignore"), existing_file());
+});
+
+test!(gitignore_appended_not_replaced {
+    fs::create_dir(&paths::root().join(".git")).unwrap();
+    
+    File::create(&paths::root().join(".gitignore")).unwrap().write_all(b"qqqqqq\n").unwrap();
+    
+    assert_that(cargo_process("init")
+                                    .env("USER", "foo"),
+                execs().with_status(0));
+    
+
+    assert_that(&paths::root().join("Cargo.toml"), existing_file());
+    assert_that(&paths::root().join("src/lib.rs"), existing_file());
+    assert_that(&paths::root().join(".git"), existing_dir());
+    assert_that(&paths::root().join(".gitignore"), existing_file());
+    
+    let mut contents = String::new();
+    File::open(&paths::root().join(".gitignore")).unwrap().read_to_string(&mut contents).unwrap();
+    assert!(contents.contains(r#"qqqqqq"#));
+});
+
+test!(with_argument {
+    assert_that(cargo_process("init").arg("foo").arg("--vcs").arg("none")
+                                     .env("USER", "foo"),
+                execs().with_status(0));
+    assert_that(&paths::root().join("foo/Cargo.toml"), existing_file());
+});
+
+
+test!(unknown_flags {
+    assert_that(cargo_process("init").arg("foo").arg("--flag"),
+                execs().with_status(1)
+                       .with_stderr("\
+Unknown flag: '--flag'
+
+Usage:
+    cargo init [options] [<path>]
+    cargo init -h | --help
+"));
+});
+
+#[cfg(not(windows))]
+test!(no_filename {
+    assert_that(cargo_process("init").arg("/"),
+                execs().with_status(101)
+                       .with_stderr("\
+cannot auto-detect project name from path \"/\" ; use --name to override
+"));
+});
diff --git a/tests/test_cargo_new.rs b/tests/test_cargo_new.rs
index 8c61d05ae27..63868112fcd 100644
--- a/tests/test_cargo_new.rs
+++ b/tests/test_cargo_new.rs
@@ -94,7 +94,9 @@ test!(existing {
 test!(invalid_characters {
     assert_that(cargo_process("new").arg("foo.rs"),
                 execs().with_status(101)
-                       .with_stderr("Invalid character `.` in crate name: `foo.rs`"));
+                       .with_stderr("\
+Invalid character `.` in crate name: `foo.rs`
+use --name to override crate name"));
 });
 
 test!(rust_prefix_stripped {
diff --git a/tests/tests.rs b/tests/tests.rs
index 761fee61bb0..a435f91b860 100644
--- a/tests/tests.rs
+++ b/tests/tests.rs
@@ -49,6 +49,7 @@ mod test_cargo_features;
 mod test_cargo_fetch;
 mod test_cargo_freshness;
 mod test_cargo_generate_lockfile;
+mod test_cargo_init;
 mod test_cargo_install;
 mod test_cargo_new;
 mod test_cargo_package;