diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9a2d2dd4..78f7a5e3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,9 @@ Feature enhancements:
 
 Bug fixes:
 
+* [BUG #373](https://github.com/BurntSushi/ripgrep/issues/373),
+  [BUG #1098](https://github.com/BurntSushi/ripgrep/issues/1098):
+  `**` is now accepted as valid syntax anywhere in a glob.
 * [BUG #1106](https://github.com/BurntSushi/ripgrep/issues/1106):
   `--files-with-matches` and `--files-without-match` work with one file.
 * [BUG #1093](https://github.com/BurntSushi/ripgrep/pull/1093):
diff --git a/globset/src/glob.rs b/globset/src/glob.rs
index 53d44e15..eccfb2d3 100644
--- a/globset/src/glob.rs
+++ b/globset/src/glob.rs
@@ -837,40 +837,49 @@ impl<'a> Parser<'a> {
 
     fn parse_star(&mut self) -> Result<(), Error> {
         let prev = self.prev;
-        if self.chars.peek() != Some(&'*') {
+        if self.peek() != Some('*') {
             self.push_token(Token::ZeroOrMore)?;
             return Ok(());
         }
         assert!(self.bump() == Some('*'));
         if !self.have_tokens()? {
-            self.push_token(Token::RecursivePrefix)?;
-            let next = self.bump();
-            if !next.map(is_separator).unwrap_or(true) {
-                return Err(self.error(ErrorKind::InvalidRecursive));
+            if !self.peek().map_or(true, is_separator) {
+                self.push_token(Token::ZeroOrMore)?;
+                self.push_token(Token::ZeroOrMore)?;
+            } else {
+                self.push_token(Token::RecursivePrefix)?;
+                assert!(self.bump().map_or(true, is_separator));
             }
             return Ok(());
         }
 
         if !prev.map(is_separator).unwrap_or(false) {
             if self.stack.len() <= 1
-                || (prev != Some(',') && prev != Some('{')) {
-                return Err(self.error(ErrorKind::InvalidRecursive));
+                || (prev != Some(',') && prev != Some('{'))
+            {
+                self.push_token(Token::ZeroOrMore)?;
+                self.push_token(Token::ZeroOrMore)?;
+                return Ok(());
             }
         }
         let is_suffix =
-            match self.chars.peek() {
+            match self.peek() {
                 None => {
                     assert!(self.bump().is_none());
                     true
                 }
-                Some(&',') | Some(&'}') if self.stack.len() >= 2 => {
+                Some(',') | Some('}') if self.stack.len() >= 2 => {
                     true
                 }
-                Some(&c) if is_separator(c) => {
+                Some(c) if is_separator(c) => {
                     assert!(self.bump().map(is_separator).unwrap_or(false));
                     false
                 }
-                _ => return Err(self.error(ErrorKind::InvalidRecursive)),
+                _ => {
+                    self.push_token(Token::ZeroOrMore)?;
+                    self.push_token(Token::ZeroOrMore)?;
+                    return Ok(());
+                }
             };
         match self.pop_token()? {
             Token::RecursivePrefix => {
@@ -976,6 +985,10 @@ impl<'a> Parser<'a> {
         self.cur = self.chars.next();
         self.cur
     }
+
+    fn peek(&mut self) -> Option<char> {
+        self.chars.peek().map(|&ch| ch)
+    }
 }
 
 #[cfg(test)]
@@ -1161,13 +1174,6 @@ mod tests {
     syntax!(cls20, "[^a]", vec![classn('a', 'a')]);
     syntax!(cls21, "[^a-z]", vec![classn('a', 'z')]);
 
-    syntaxerr!(err_rseq1, "a**", ErrorKind::InvalidRecursive);
-    syntaxerr!(err_rseq2, "**a", ErrorKind::InvalidRecursive);
-    syntaxerr!(err_rseq3, "a**b", ErrorKind::InvalidRecursive);
-    syntaxerr!(err_rseq4, "***", ErrorKind::InvalidRecursive);
-    syntaxerr!(err_rseq5, "/a**", ErrorKind::InvalidRecursive);
-    syntaxerr!(err_rseq6, "/**a", ErrorKind::InvalidRecursive);
-    syntaxerr!(err_rseq7, "/a**b", ErrorKind::InvalidRecursive);
     syntaxerr!(err_unclosed1, "[", ErrorKind::UnclosedClass);
     syntaxerr!(err_unclosed2, "[]", ErrorKind::UnclosedClass);
     syntaxerr!(err_unclosed3, "[!", ErrorKind::UnclosedClass);
@@ -1228,6 +1234,13 @@ mod tests {
     toregex!(re25, "**/b", r"^(?:/?|.*/)b$");
     toregex!(re26, "**/**/b", r"^(?:/?|.*/)b$");
     toregex!(re27, "**/**/**/b", r"^(?:/?|.*/)b$");
+    toregex!(re28, "a**", r"^a.*.*$");
+    toregex!(re29, "**a", r"^.*.*a$");
+    toregex!(re30, "a**b", r"^a.*.*b$");
+    toregex!(re31, "***", r"^.*.*.*$");
+    toregex!(re32, "/a**", r"^/a.*.*$");
+    toregex!(re33, "/**a", r"^/.*.*a$");
+    toregex!(re34, "/a**b", r"^/a.*.*b$");
 
     matches!(match1, "a", "a");
     matches!(match2, "a*b", "a_b");
diff --git a/globset/src/lib.rs b/globset/src/lib.rs
index 8d26e187..7196b8f2 100644
--- a/globset/src/lib.rs
+++ b/globset/src/lib.rs
@@ -143,8 +143,13 @@ pub struct Error {
 /// The kind of error that can occur when parsing a glob pattern.
 #[derive(Clone, Debug, Eq, PartialEq)]
 pub enum ErrorKind {
-    /// Occurs when a use of `**` is invalid. Namely, `**` can only appear
-    /// adjacent to a path separator, or the beginning/end of a glob.
+    /// **DEPRECATED**.
+    ///
+    /// This error used to occur for consistency with git's glob specification,
+    /// but the specification now accepts all uses of `**`. When `**` does not
+    /// appear adjacent to a path separator or at the beginning/end of a glob,
+    /// it is now treated as two consecutive `*` patterns. As such, this error
+    /// is no longer used.
     InvalidRecursive,
     /// Occurs when a character class (e.g., `[abc]`) is not closed.
     UnclosedClass,
diff --git a/ignore/src/dir.rs b/ignore/src/dir.rs
index 30f4cb87..3ba0ede8 100644
--- a/ignore/src/dir.rs
+++ b/ignore/src/dir.rs
@@ -869,7 +869,7 @@ mod tests {
     #[test]
     fn errored() {
         let td = tmpdir("ignore-test-");
-        wfile(td.path().join(".gitignore"), "f**oo");
+        wfile(td.path().join(".gitignore"), "{foo");
 
         let (_, err) = IgnoreBuilder::new().build().add_child(td.path());
         assert!(err.is_some());
@@ -878,8 +878,8 @@ mod tests {
     #[test]
     fn errored_both() {
         let td = tmpdir("ignore-test-");
-        wfile(td.path().join(".gitignore"), "f**oo");
-        wfile(td.path().join(".ignore"), "fo**o");
+        wfile(td.path().join(".gitignore"), "{foo");
+        wfile(td.path().join(".ignore"), "{bar");
 
         let (_, err) = IgnoreBuilder::new().build().add_child(td.path());
         assert_eq!(2, partial(err.expect("an error")).len());
@@ -889,7 +889,7 @@ mod tests {
     fn errored_partial() {
         let td = tmpdir("ignore-test-");
         mkdirp(td.path().join(".git"));
-        wfile(td.path().join(".gitignore"), "f**oo\nbar");
+        wfile(td.path().join(".gitignore"), "{foo\nbar");
 
         let (ig, err) = IgnoreBuilder::new().build().add_child(td.path());
         assert!(err.is_some());
@@ -899,7 +899,7 @@ mod tests {
     #[test]
     fn errored_partial_and_ignore() {
         let td = tmpdir("ignore-test-");
-        wfile(td.path().join(".gitignore"), "f**oo\nbar");
+        wfile(td.path().join(".gitignore"), "{foo\nbar");
         wfile(td.path().join(".ignore"), "!bar");
 
         let (ig, err) = IgnoreBuilder::new().build().add_child(td.path());
diff --git a/tests/regression.rs b/tests/regression.rs
index 8435f174..b8dc26d0 100644
--- a/tests/regression.rs
+++ b/tests/regression.rs
@@ -569,6 +569,14 @@ rgtest!(r1064, |dir: Dir, mut cmd: TestCommand| {
     eqnice!("input:abc\n", cmd.arg("a(.*c)").stdout());
 });
 
+// See: https://github.com/BurntSushi/ripgrep/issues/1174
+rgtest!(r1098, |dir: Dir, mut cmd: TestCommand| {
+    dir.create_dir(".git");
+    dir.create(".gitignore", "a**b");
+    dir.create("afoob", "test");
+    cmd.arg("test").assert_err();
+});
+
 // See: https://github.com/BurntSushi/ripgrep/issues/1130
 rgtest!(r1130, |dir: Dir, mut cmd: TestCommand| {
     dir.create("foo", "test");