Re: [PATCH v2 00/34] Teach the sequencer to act as rebase -i's backend

2016-12-13 Thread Johannes Sixt

Am 13.12.2016 um 16:29 schrieb Johannes Schindelin:

base-commit: 8d7a455ed52e2a96debc080dfc011b6bb00db5d2
Published-As: https://github.com/dscho/git/releases/tag/sequencer-i-v2
Fetch-It-Via: git fetch https://github.com/dscho/git sequencer-i-v2


Thank you so much!

I would appreciate if you could publish a branch that contains the end 
game so that I can test it, too. Currently I am still using


 git://github.com/dscho/git interactive-rebase (fca871a3cf4d)

-- Hannes



Re: [PATCH v2 05/34] sequencer (rebase -i): learn about the 'verbose' mode

2016-12-13 Thread Junio C Hamano
Junio C Hamano  writes:

> Johannes Schindelin  writes:
> ...
>> +if (opts->verbose) {
>> +const char *argv[] = {
>> +"diff-tree", "--stat", NULL, NULL
>> +};
>> + ...
>> +run_command_v_opt(argv, RUN_GIT_CMD);
>> +strbuf_reset(&buf);
>> +}
>> +strbuf_release(&buf);
>>  }
>
> It's a bit curious that the previous step avoided running a separate
> process and instead did "diff-tree -p" all in C, but this one does not.
>
> I think it is because this one is outside the loop?

Nah, this guess of mine "The patch file generation done in 03/34
avoids spawn because it is in a loop" is off the mark.  It is done
before "edit" gives control back to the end user and it is not like
we write one patch file per iteration of the loop we want to get
maximum speed out of.



Re: Creating remote git repository?

2016-12-13 Thread Konstantin Khomoutov
On Wed, 14 Dec 2016 09:00:42 +0300
essam Ganadily  wrote:

> given that git is an old and mature product i wounder why there is no
> command line (git.exe in windows) way of creating a remote git
> repository?
> 
> "git remote create repo myreponame"
> 
> frankly speaking i know that our friends in the linux kernel project
> never felt the need to create remote repository because they probably
> rarely need that but i guess their merciful hearts could have some
> feeling for the rest of us?

Also asked and answered (by me) over there at git-users [1].

1. https://groups.google.com/d/msg/git-users/twgkOYV6kX4/FED559TPDQAJ



Creating remote git repository?

2016-12-13 Thread essam Ganadily
given that git is an old and mature product i wounder why there is no
command line (git.exe in windows) way of creating a remote git
repository?

"git remote create repo myreponame"

frankly speaking i know that our friends in the linux kernel project
never felt the need to create remote repository because they probably
rarely need that but i guess their merciful hearts could have some
feeling for the rest of us?


[PATCH v9 5/5] transport: add from_user parameter to is_transport_allowed

2016-12-13 Thread Brandon Williams
Add the from_user parameter to the 'is_transport_allowed' function.
This allows callers to query if a transport protocol is allowed, given
that the caller knows that the protocol is coming from the user (1) or
not from the user (0) such as redirects in libcurl.  If unknown a -1
should be provided which falls back to reading `GIT_PROTOCOL_FROM_USER`
to determine if the protocol came from the user.

Signed-off-by: Brandon Williams 
---
 http.c  | 14 +++---
 transport.c |  8 +---
 transport.h | 13 ++---
 3 files changed, 22 insertions(+), 13 deletions(-)

diff --git a/http.c b/http.c
index f7c488a..2208269 100644
--- a/http.c
+++ b/http.c
@@ -489,17 +489,17 @@ static void set_curl_keepalive(CURL *c)
 }
 #endif
 
-static long get_curl_allowed_protocols(void)
+static long get_curl_allowed_protocols(int from_user)
 {
long allowed_protocols = 0;
 
-   if (is_transport_allowed("http"))
+   if (is_transport_allowed("http", from_user))
allowed_protocols |= CURLPROTO_HTTP;
-   if (is_transport_allowed("https"))
+   if (is_transport_allowed("https", from_user))
allowed_protocols |= CURLPROTO_HTTPS;
-   if (is_transport_allowed("ftp"))
+   if (is_transport_allowed("ftp", from_user))
allowed_protocols |= CURLPROTO_FTP;
-   if (is_transport_allowed("ftps"))
+   if (is_transport_allowed("ftps", from_user))
allowed_protocols |= CURLPROTO_FTPS;
 
return allowed_protocols;
@@ -588,9 +588,9 @@ static CURL *get_curl_handle(void)
 #endif
 #if LIBCURL_VERSION_NUM >= 0x071304
curl_easy_setopt(result, CURLOPT_REDIR_PROTOCOLS,
-get_curl_allowed_protocols());
+get_curl_allowed_protocols(0));
curl_easy_setopt(result, CURLOPT_PROTOCOLS,
-get_curl_allowed_protocols());
+get_curl_allowed_protocols(-1));
 #else
warning("protocol restrictions not applied to curl redirects because\n"
"your curl version is too old (>= 7.19.4)");
diff --git a/transport.c b/transport.c
index fbd799d..f50c31a 100644
--- a/transport.c
+++ b/transport.c
@@ -676,7 +676,7 @@ static enum protocol_allow_config get_protocol_config(const 
char *type)
return PROTOCOL_ALLOW_USER_ONLY;
 }
 
-int is_transport_allowed(const char *type)
+int is_transport_allowed(const char *type, int from_user)
 {
const struct string_list *whitelist = protocol_whitelist();
if (whitelist)
@@ -688,7 +688,9 @@ int is_transport_allowed(const char *type)
case PROTOCOL_ALLOW_NEVER:
return 0;
case PROTOCOL_ALLOW_USER_ONLY:
-   return git_env_bool("GIT_PROTOCOL_FROM_USER", 1);
+   if (from_user < 0)
+   from_user = git_env_bool("GIT_PROTOCOL_FROM_USER", 1);
+   return from_user;
}
 
die("BUG: invalid protocol_allow_config type");
@@ -696,7 +698,7 @@ int is_transport_allowed(const char *type)
 
 void transport_check_allowed(const char *type)
 {
-   if (!is_transport_allowed(type))
+   if (!is_transport_allowed(type, -1))
die("transport '%s' not allowed", type);
 }
 
diff --git a/transport.h b/transport.h
index 3396e1d..4f1c801 100644
--- a/transport.h
+++ b/transport.h
@@ -142,10 +142,17 @@ struct transport {
 struct transport *transport_get(struct remote *, const char *);
 
 /*
- * Check whether a transport is allowed by the environment. Type should
- * generally be the URL scheme, as described in Documentation/git.txt
+ * Check whether a transport is allowed by the environment.
+ *
+ * Type should generally be the URL scheme, as described in
+ * Documentation/git.txt
+ *
+ * from_user specifies if the transport was given by the user.  If unknown pass
+ * a -1 to read from the environment to determine if the transport was given by
+ * the user.
+ *
  */
-int is_transport_allowed(const char *type);
+int is_transport_allowed(const char *type, int from_user);
 
 /*
  * Check whether a transport is allowed by the environment,
-- 
2.8.0.rc3.226.g39d4020



[PATCH v9 4/5] http: create function to get curl allowed protocols

2016-12-13 Thread Brandon Williams
Move the creation of an allowed protocols whitelist to a helper
function.

Signed-off-by: Brandon Williams 
---
 http.c | 31 ---
 1 file changed, 20 insertions(+), 11 deletions(-)

diff --git a/http.c b/http.c
index 034426e..f7c488a 100644
--- a/http.c
+++ b/http.c
@@ -489,10 +489,25 @@ static void set_curl_keepalive(CURL *c)
 }
 #endif
 
+static long get_curl_allowed_protocols(void)
+{
+   long allowed_protocols = 0;
+
+   if (is_transport_allowed("http"))
+   allowed_protocols |= CURLPROTO_HTTP;
+   if (is_transport_allowed("https"))
+   allowed_protocols |= CURLPROTO_HTTPS;
+   if (is_transport_allowed("ftp"))
+   allowed_protocols |= CURLPROTO_FTP;
+   if (is_transport_allowed("ftps"))
+   allowed_protocols |= CURLPROTO_FTPS;
+
+   return allowed_protocols;
+}
+
 static CURL *get_curl_handle(void)
 {
CURL *result = curl_easy_init();
-   long allowed_protocols = 0;
 
if (!result)
die("curl_easy_init failed");
@@ -572,16 +587,10 @@ static CURL *get_curl_handle(void)
curl_easy_setopt(result, CURLOPT_POST301, 1);
 #endif
 #if LIBCURL_VERSION_NUM >= 0x071304
-   if (is_transport_allowed("http"))
-   allowed_protocols |= CURLPROTO_HTTP;
-   if (is_transport_allowed("https"))
-   allowed_protocols |= CURLPROTO_HTTPS;
-   if (is_transport_allowed("ftp"))
-   allowed_protocols |= CURLPROTO_FTP;
-   if (is_transport_allowed("ftps"))
-   allowed_protocols |= CURLPROTO_FTPS;
-   curl_easy_setopt(result, CURLOPT_REDIR_PROTOCOLS, allowed_protocols);
-   curl_easy_setopt(result, CURLOPT_PROTOCOLS, allowed_protocols);
+   curl_easy_setopt(result, CURLOPT_REDIR_PROTOCOLS,
+get_curl_allowed_protocols());
+   curl_easy_setopt(result, CURLOPT_PROTOCOLS,
+get_curl_allowed_protocols());
 #else
warning("protocol restrictions not applied to curl redirects because\n"
"your curl version is too old (>= 7.19.4)");
-- 
2.8.0.rc3.226.g39d4020



[PATCH v9 3/5] http: always warn if libcurl version is too old

2016-12-13 Thread Brandon Williams
Now that there are default "known-good" and "known-bad" protocols which
are allowed/disallowed by 'is_transport_allowed' we should always warn
the user that older versions of libcurl can't respect the allowed
protocols for redirects.

Signed-off-by: Brandon Williams 
---
 http.c  | 5 ++---
 transport.c | 5 -
 transport.h | 6 --
 3 files changed, 2 insertions(+), 14 deletions(-)

diff --git a/http.c b/http.c
index 5cd3ffd..034426e 100644
--- a/http.c
+++ b/http.c
@@ -583,9 +583,8 @@ static CURL *get_curl_handle(void)
curl_easy_setopt(result, CURLOPT_REDIR_PROTOCOLS, allowed_protocols);
curl_easy_setopt(result, CURLOPT_PROTOCOLS, allowed_protocols);
 #else
-   if (transport_restrict_protocols())
-   warning("protocol restrictions not applied to curl redirects 
because\n"
-   "your curl version is too old (>= 7.19.4)");
+   warning("protocol restrictions not applied to curl redirects because\n"
+   "your curl version is too old (>= 7.19.4)");
 #endif
 
if (getenv("GIT_CURL_VERBOSE"))
diff --git a/transport.c b/transport.c
index e1ba78b..fbd799d 100644
--- a/transport.c
+++ b/transport.c
@@ -700,11 +700,6 @@ void transport_check_allowed(const char *type)
die("transport '%s' not allowed", type);
 }
 
-int transport_restrict_protocols(void)
-{
-   return !!protocol_whitelist();
-}
-
 struct transport *transport_get(struct remote *remote, const char *url)
 {
const char *helper;
diff --git a/transport.h b/transport.h
index c681408..3396e1d 100644
--- a/transport.h
+++ b/transport.h
@@ -153,12 +153,6 @@ int is_transport_allowed(const char *type);
  */
 void transport_check_allowed(const char *type);
 
-/*
- * Returns true if the user has attempted to turn on protocol
- * restrictions at all.
- */
-int transport_restrict_protocols(void);
-
 /* Transport options which apply to git:// and scp-style URLs */
 
 /* The program to use on the remote side to send a pack */
-- 
2.8.0.rc3.226.g39d4020



[PATCH v9 2/5] transport: add protocol policy config option

2016-12-13 Thread Brandon Williams
Previously the `GIT_ALLOW_PROTOCOL` environment variable was used to
specify a whitelist of protocols to be used in clone/fetch/push
commands.  This patch introduces new configuration options for more
fine-grained control for allowing/disallowing protocols.  This also has
the added benefit of allowing easier construction of a protocol
whitelist on systems where setting an environment variable is
non-trivial.

Now users can specify a policy to be used for each type of protocol via
the 'protocol..allow' config option.  A default policy for all
unconfigured protocols can be set with the 'protocol.allow' config
option.  If no user configured default is made git will allow known-safe
protocols (http, https, git, ssh, file), disallow known-dangerous
protocols (ext), and have a default policy of `user` for all other
protocols.

The supported policies are `always`, `never`, and `user`.  The `user`
policy can be used to configure a protocol to be usable when explicitly
used by a user, while disallowing it for commands which run
clone/fetch/push commands without direct user intervention (e.g.
recursive initialization of submodules).  Commands which can potentially
clone/fetch/push from untrusted repositories without user intervention
can export `GIT_PROTOCOL_FROM_USER` with a value of '0' to prevent
protocols configured to the `user` policy from being used.

Fix remote-ext tests to use the new config to allow the ext
protocol to be tested.

Based on a patch by Jeff King 

Signed-off-by: Brandon Williams 
---
 Documentation/config.txt |  46 ++
 Documentation/git.txt|  38 +---
 git-submodule.sh |  12 ++--
 t/lib-proto-disable.sh   | 130 +--
 t/t5509-fetch-push-namespaces.sh |   1 +
 t/t5802-connect-helper.sh|   1 +
 transport.c  |  75 +-
 7 files changed, 264 insertions(+), 39 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 8153336..50d3d06 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -2260,6 +2260,52 @@ pretty.::
Note that an alias with the same name as a built-in format
will be silently ignored.
 
+protocol.allow::
+   If set, provide a user defined default policy for all protocols which
+   don't explicitly have a policy (`protocol..allow`).  By default,
+   if unset, known-safe protocols (http, https, git, ssh, file) have a
+   default policy of `always`, known-dangerous protocols (ext) have a
+   default policy of `never`, and all other protocols have a default
+   policy of `user`.  Supported policies:
++
+--
+
+* `always` - protocol is always able to be used.
+
+* `never` - protocol is never able to be used.
+
+* `user` - protocol is only able to be used when `GIT_PROTOCOL_FROM_USER` is
+  either unset or has a value of 1.  This policy should be used when you want a
+  protocol to be directly usable by the user but don't want it used by 
commands which
+  execute clone/fetch/push commands without user input, e.g. recursive
+  submodule initialization.
+
+--
+
+protocol..allow::
+   Set a policy to be used by protocol `` with clone/fetch/push
+   commands. See `protocol.allow` above for the available policies.
++
+The protocol names currently used by git are:
++
+--
+  - `file`: any local file-based path (including `file://` URLs,
+or local paths)
+
+  - `git`: the anonymous git protocol over a direct TCP
+connection (or proxy, if configured)
+
+  - `ssh`: git over ssh (including `host:path` syntax,
+`ssh://`, etc).
+
+  - `http`: git over http, both "smart http" and "dumb http".
+Note that this does _not_ include `https`; if you want to configure
+both, you must do so individually.
+
+  - any external helpers are named by their protocol (e.g., use
+`hg` to allow the `git-remote-hg` helper)
+--
+
 pull.ff::
By default, Git does not create an extra merge commit when merging
a commit that is a descendant of the current commit. Instead, the
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 923aa49..d9fb937 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -1129,30 +1129,20 @@ of clones and fetches.
cloning a repository to make a backup).
 
 `GIT_ALLOW_PROTOCOL`::
-   If set, provide a colon-separated list of protocols which are
-   allowed to be used with fetch/push/clone. This is useful to
-   restrict recursive submodule initialization from an untrusted
-   repository. Any protocol not mentioned will be disallowed (i.e.,
-   this is a whitelist, not a blacklist). If the variable is not
-   set at all, all protocols are enabled.  The protocol names
-   currently used by git are:
-
- - `file`: any local file-based path (including `file://` URLs,
-   or local paths)
-
- - `git`: the anonymous git protocol over a direct TCP
-

[PATCH v9 0/5] transport protocol policy configuration

2016-12-13 Thread Brandon Williams
Only difference between v8 and v9 is that v9 has been rebased ontop of Jeff's
http-walker-limit-redirect series 'jk/http-walker-limit-redirect'.

Brandon Williams (5):
  lib-proto-disable: variable name fix
  transport: add protocol policy config option
  http: always warn if libcurl version is too old
  http: create function to get curl allowed protocols
  transport: add from_user parameter to is_transport_allowed

 Documentation/config.txt |  46 +
 Documentation/git.txt|  38 ---
 git-submodule.sh |  12 ++--
 http.c   |  36 ++
 t/lib-proto-disable.sh   | 142 ---
 t/t5509-fetch-push-namespaces.sh |   1 +
 t/t5802-connect-helper.sh|   1 +
 transport.c  |  84 ---
 transport.h  |  19 +++---
 9 files changed, 305 insertions(+), 74 deletions(-)

-- 
2.8.0.rc3.226.g39d4020



[PATCH v9 1/5] lib-proto-disable: variable name fix

2016-12-13 Thread Brandon Williams
The test_proto function assigns the positional parameters to named
variables, but then still refers to "$desc" as "$1". Using $desc is
more readable and less error-prone.

Signed-off-by: Brandon Williams 
---
 t/lib-proto-disable.sh | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/t/lib-proto-disable.sh b/t/lib-proto-disable.sh
index b0917d9..be88e9a 100644
--- a/t/lib-proto-disable.sh
+++ b/t/lib-proto-disable.sh
@@ -9,7 +9,7 @@ test_proto () {
proto=$2
url=$3
 
-   test_expect_success "clone $1 (enabled)" '
+   test_expect_success "clone $desc (enabled)" '
rm -rf tmp.git &&
(
GIT_ALLOW_PROTOCOL=$proto &&
@@ -18,7 +18,7 @@ test_proto () {
)
'
 
-   test_expect_success "fetch $1 (enabled)" '
+   test_expect_success "fetch $desc (enabled)" '
(
cd tmp.git &&
GIT_ALLOW_PROTOCOL=$proto &&
@@ -27,7 +27,7 @@ test_proto () {
)
'
 
-   test_expect_success "push $1 (enabled)" '
+   test_expect_success "push $desc (enabled)" '
(
cd tmp.git &&
GIT_ALLOW_PROTOCOL=$proto &&
@@ -36,7 +36,7 @@ test_proto () {
)
'
 
-   test_expect_success "push $1 (disabled)" '
+   test_expect_success "push $desc (disabled)" '
(
cd tmp.git &&
GIT_ALLOW_PROTOCOL=none &&
@@ -45,7 +45,7 @@ test_proto () {
)
'
 
-   test_expect_success "fetch $1 (disabled)" '
+   test_expect_success "fetch $desc (disabled)" '
(
cd tmp.git &&
GIT_ALLOW_PROTOCOL=none &&
@@ -54,7 +54,7 @@ test_proto () {
)
'
 
-   test_expect_success "clone $1 (disabled)" '
+   test_expect_success "clone $desc (disabled)" '
rm -rf tmp.git &&
(
GIT_ALLOW_PROTOCOL=none &&
-- 
2.8.0.rc3.226.g39d4020



Re: What's cooking in git.git (Dec 2016, #03; Tue, 13)

2016-12-13 Thread Stefan Beller
> * sb/submodule-embed-gitdir (2016-12-12) 6 commits
>  - submodule: add absorb-git-dir function
>  - move connect_work_tree_and_git_dir to dir.h
>  - worktree: check if a submodule uses worktrees
>  - test-lib-functions.sh: teach test_commit -C 
>  - submodule helper: support super prefix
>  - submodule: use absolute path for computing relative path connecting
>  (this branch uses nd/worktree-list-fixup; is tangled with nd/worktree-move.)
>
>  A new submodule helper "git submodule embedgitdirs" to make it
>  easier to move embedded .git/ directory for submodules in a
>  superproject to .git/modules/ (and point the latter with the former
>  that is turned into a "gitdir:" file) has been added.
>
>  Is this now pretty much done and ready for 'next'?

I consider it good and it had a fair amount of reviews already,
so I would think it is ready for next.


Re: What's cooking in git.git (Dec 2016, #03; Tue, 13)

2016-12-13 Thread Brandon Williams
On 12/13, Junio C Hamano wrote:
> * bw/realpath-wo-chdir (2016-12-12) 4 commits
>  - real_path: have callers use real_pathdup and strbuf_realpath
>  - real_path: create real_pathdup
>  - real_path: convert real_path_internal to strbuf_realpath
>  - real_path: resolve symlinks by hand
> 
>  The implementation of "real_path()" was to go there with chdir(2)
>  and call getcwd(3), but this obviously wouldn't be usable in a
>  threaded environment.  Rewrite it to manually resolve relative
>  paths including symbolic links in path components.
> 
>  What's the donness of the topic?  Is this ready for 'next'?

Unless others have any additional comments I think it should be
ready for next.

> * bw/transport-protocol-policy (2016-12-05) 5 commits
>  - transport: add from_user parameter to is_transport_allowed
>  - http: create function to get curl allowed protocols
>  - http: always warn if libcurl version is too old
>  - transport: add protocol policy config option
>  - lib-proto-disable: variable name fix
> 
>  Finer-grained control of what protocols are allowed for transports
>  during clone/fetch/push have been enabled via a new configuration
>  mechanism.
> 
>  What's the doneness of this topic?  Did we agree that it should be
>  rebased on top of Peff's http-walker-limit-redirect series?

Yes I believe we agreed it should be rebased on Peff's series.  I can do
that and send out another version.

-- 
Brandon Williams


What's cooking in git.git (Dec 2016, #03; Tue, 13)

2016-12-13 Thread Junio C Hamano
Here are the topics that have been cooking.  Commits prefixed with
'-' are only in 'pu' (proposed updates) while commits prefixed with
'+' are in 'next'.  The ones marked with '.' do not appear in any of
the integration branches, but I am still holding onto them.

A few topics were merged to 'master' and are meant for 'maint' to be
in the first maintenance release for 2.11.x series.

You can find the changes described here in the integration branches
of the repositories listed at

http://git-blame.blogspot.com/p/git-public-repositories.html

--
[Graduated to "master"]

* ew/svn-fixes (2016-12-12) 2 commits
  (merged to 'next' on 2016-12-12 at 91ed5b3cf3)
 + git-svn: document useLogAuthor and addAuthorFrom config keys
 + git-svn: allow "0" in SVN path components

 Meant eventually for 'maint'.


* js/mingw-isatty (2016-12-11) 1 commit
  (merged to 'next' on 2016-12-12 at 60c1da6676)
 + mingw: intercept isatty() to handle /dev/null as Git expects it

 We often decide if a session is interactive by checking if the
 standard I/O streams are connected to a TTY, but isatty() that
 comes with Windows incorrectly returned true if it is used on NUL
 (i.e. an equivalent to /dev/null). This has been fixed.

 Meant eventually for 'maint'.

--
[New Topics]

* bw/realpath-wo-chdir (2016-12-12) 4 commits
 - real_path: have callers use real_pathdup and strbuf_realpath
 - real_path: create real_pathdup
 - real_path: convert real_path_internal to strbuf_realpath
 - real_path: resolve symlinks by hand

 The implementation of "real_path()" was to go there with chdir(2)
 and call getcwd(3), but this obviously wouldn't be usable in a
 threaded environment.  Rewrite it to manually resolve relative
 paths including symbolic links in path components.

 What's the donness of the topic?  Is this ready for 'next'?


* jk/quote-env-path-list-component (2016-12-13) 4 commits
 - t5547-push-quarantine: run the path separator test on Windows, too
 - tmp-objdir: quote paths we add to alternates
 - alternates: accept double-quoted paths
 - Merge branch 'jk/alt-odb-cleanup' into jk/quote-env-path-list-component

 A recent update to receive-pack to make it easier to drop garbage
 objects made it clear that GIT_ALTERNATE_OBJECT_DIRECTORIES cannot
 have a pathname with a colon in it (no surprise!), and this in turn
 made it impossible to push into a repository at such a path.  This
 has been fixed by introducing a quoting mechanism used when
 appending such a path to the colon-separated list.

 Will merge to 'next'.


* js/normalize-path-copy-ceil (2016-12-13) 1 commit
 - normalize_path_copy(): fix pushing to //server/share/dir paths on Windows

 A pathname that begins with "//" or "\\" on Windows is special but
 path normalization logic was unaware of it.

 Will merge to 'next', but I'd appreciate a second set of eyes on this.

--
[Stalled]

* jc/retire-compaction-heuristics (2016-11-02) 3 commits
 - SQUASH???
 - SQUASH???
 - diff: retire the original experimental "compaction" heuristics

 Waiting for a reroll.


* jc/abbrev-autoscale-config (2016-11-01) 1 commit
 - config.abbrev: document the new default that auto-scales

 Waiting for a reroll.


* jk/nofollow-attr-ignore (2016-11-02) 5 commits
 - exclude: do not respect symlinks for in-tree .gitignore
 - attr: do not respect symlinks for in-tree .gitattributes
 - exclude: convert "check_index" into a flags field
 - attr: convert "macro_ok" into a flags field
 - add open_nofollow() helper

 As we do not follow symbolic links when reading control files like
 .gitignore and .gitattributes from the index, match the behaviour
 and not follow symbolic links when reading them from the working
 tree.  This also tightens security a bit by not leaking contents of
 an unrelated file in the error messages when it is pointed at by
 one of these files that is a symbolic link.

 Perhaps we want to cover .gitmodules too with the same mechanism?


* nd/worktree-move (2016-11-28) 11 commits
 . worktree remove: new command
 . worktree move: refuse to move worktrees with submodules
 . worktree move: accept destination as directory
 . worktree move: new command
 . worktree.c: add update_worktree_location()
 . worktree.c: add validate_worktree()
 . copy.c: convert copy_file() to copy_dir_recursively()
 . copy.c: style fix
 . copy.c: convert bb_(p)error_msg to error(_errno)
 . copy.c: delete unused code in copy_file()
 . copy.c: import copy_file() from busybox
 (this branch uses nd/worktree-list-fixup; is tangled with 
sb/submodule-embed-gitdir.)

 "git worktree" learned move and remove subcommands.

 Reported to break builds on Windows.


* jc/bundle (2016-03-03) 6 commits
 - index-pack: --clone-bundle option
 - Merge branch 'jc/index-pack' into jc/bundle
 - bundle v3: the beginning
 - bundle: keep a copy of bundle file name in the in-core bundle header
 - bundle: plu

Re: [PATCH v2 0/6] unicode_width.h: update the width tables to Unicode 9.0

2016-12-13 Thread Junio C Hamano
Thanks. Very much appreciated.


Re: Proposal for an increased `gitk` cohesion with `git stash`.

2016-12-13 Thread Uxío Prego
Dearest all,

am sorry my previous message did not enter the list (cross my fingers this 
will). I won't be pasting it verbatim because shame on me it leaked zombie 
processes (but that part got silently dropped out by kind Paul).

In case anyone could be interested in the topic, and because a thorough reply 
will take me some time, my most recent edit of this is hosted at 
https://gist.githubusercontent.com/uprego/d8c3c059c56ebb911974bb905157a81e/raw/6a08d9e0ce9c2b1decd4ed92acc924961c7f7769/gitk%2520multi%2520stash%2520patch.
 All problems shown I still think is a nice start (of course p.o.c / pre alpha) 
if anyone ever wanted to get this working or even fix the current problems it 
has.

As Paul recommend I'll be reworking and giving a patch against a rev of his 
upstream.

I'm going to try his code tips to improve non obvious design choices, and (even 
he doesn’t commented it and seems to me most important) really put an extra 
effort in not changing the behaviour of `gitk` (i.e. started without '--all').

Then some testing against large repos, github.com/cartodb/cartodb then 
github.com/odoo/oodo finally Linux; will be done.

The performance issue Paul points to, I don't think is impacting me, but now I 
reckon (just as one example) there are people who develop using IDEs that leave 
garbaged unuseful stashes, and that has to be taken into account as scenario. 
And the large repos. But this file event handlers thing is something that will 
make me lag to fix it, even surprised me because the remaining of the 
subroutines that I patched are just doing the same I typed, I just replicated 
near source (general revs processing) because I have no idea Tcl, even do not 
give a shit, but have to say Tcl is fun C: and an interesting discovery though. 
I hope that was not a trick to get me into improving the performance of the 
near loop that process ALL involved revs (and the similar for refs)! I'm old 
and tired to get into performance hacking. 

I guess you know, the underworked grep must be an easy solve, probably 
excluding ' refs/stash' because a branch named 'refs/stash' is allowed but not 
a branch named ' refs/stash' (IDK which version I was trying but I will try 
both 1.x.y and 2.x.y in time).

Finally... if you don't leverage stashing too much, what is the practice? 
committing ephemeral to later reset and recommit? I hope I don't just needed a 
lesson on git-reset instead of all this.

Please pardon my potentially mangler mail client. Yours sincerely, regards and 
thanks for your time,

> On 12 Dec 2016, at 10:36, Paul Mackerras  wrote:
> 
> Hi Uxio,
> 
> On Thu, Sep 08, 2016 at 03:41:29PM +0200, Uxío Prego wrote:
>> Hello, please forgive me for not introducing me.
>> 
>> +---+
>> |Description|
>> +---+
>> 
>> Patch for showing all stashes in `gitk`.
>> 
>> +---+
>> |The problem|
>> +---+
>> 
>> Being `gitk` one of the best tools for navigating and understanding graphs
>> of git repo revs, I got used to have it for home use, some years ago, soon
>> for office use too.
>> 
>> At some point I got used to invoke always `gitk --all` in order to keep
>> tracking of tags when using the program for building, when possible, stable
>> versions of any GNU/Linux software I would want to use.
>> 
>> It seems `gitk --all` uses `git show-ref` for showing remotes information.
>> A side effect of this is that the most recent stash gets shown in `gitk
>> --all`. After learning what the stash was, I got used to it.
>> 
>> Later, when at jobs, I got used to have a stash on all working branch tips.
>> So I often would have several stashes in `git stash list` but only the last
>> one in `gitk --all`. That annoyed me for about a year, finally I got
>> working in `gitk` to show a stash status more similar to what `git stash
>> list` shows.
>> 
>> +---+
>> |The feature|
>> +---+
>> 
>> Show all stashes in `gitk` instead of only the last one.
> 
> This seems like a good feature, although I don't use stashes myself.
> 
>> +--+
>> |Why it's desirable|
>> +--+
>> 
>> In order to have better visual control when working on repos that have
>> several active branches and there are needed quick context changes between
>> them with the features that `git stash [apply [STASHNAME]| list | pop
>> [STASHNAME]| push | save | show [[-p] STASHNAME]]`.
>> 
>> In order to have a better cohesion between the mentioned features and `gitk
>> --all`.
>> 
>> ++
>> |Caveats and side effects|
>> ++
>> 
>> With this patch several side effects happen:
>> 
>> * Stashes are shown even invoking `gitk`, not only when running `gitk
>> --all`. If this is a problem, I can keep working in the patch to avoid this.
>> 
>> * The most recent stash, which was previously shown as 'stash' because its
>> corresponding `git show-ref` output line reads 'refs/stash', gets shown as
>> 'stash@{0}'. Not removing lines with 'stash' when calling `gi

[PATCHv3] git-p4 worktree support

2016-12-13 Thread Luke Diamand
Support for git-p4 worktrees.

Adds test cases for using git from a worktree, and
specifying the git directory either with the --git-dir
command-line option, or with $ENV{GIT_DIR}.

Luke Diamand (1):
  git-p4: support git worktrees

 git-p4.py | 17 +
 t/t9800-git-p4-basic.sh   | 20 
 t/t9806-git-p4-options.sh | 32 
 3 files changed, 65 insertions(+), 4 deletions(-)

-- 
2.8.2.703.g78b384c.dirty



Re: [PATCHv3] git-p4: support git worktrees

2016-12-13 Thread Junio C Hamano
Luke Diamand  writes:

> git-p4 would attempt to find the git directory using
> its own specific code, which did not know about git
> worktrees.
>
> Rework it to use "git rev-parse --git-dir" instead.
>
> Add test cases for worktree usage and specifying
> git directory via --git-dir and $GIT_DIR.
>
> Signed-off-by: Luke Diamand 
> ---
>  git-p4.py | 17 +
>  t/t9800-git-p4-basic.sh   | 20 
>  t/t9806-git-p4-options.sh | 32 
>  3 files changed, 65 insertions(+), 4 deletions(-)
>
> diff --git a/git-p4.py b/git-p4.py
> index fd5ca52..6a1f65f 100755
> --- a/git-p4.py
> +++ b/git-p4.py
> @@ -85,6 +85,16 @@ def p4_build_cmd(cmd):
>  real_cmd += cmd
>  return real_cmd
>  
> +def git_dir(path):
> +""" Return TRUE if the given path is a git directory (/path/to/dir/.git).
> +This won't automatically add ".git" to a directory.
> +"""
> +d = read_pipe(["git", "--git-dir", path, "rev-parse", "--git-dir"], 
> True).strip()
> +if not d or len(d) == 0:
> +return None
> +else:
> +return d
> +
>  def chdir(path, is_client_path=False):
>  """Do chdir to the given path, and set the PWD environment
> variable for use by P4.  It does not look at getcwd() output.
> @@ -563,10 +573,7 @@ def currentGitBranch():
>  return read_pipe(["git", "name-rev", "HEAD"]).split(" ")[1].strip()
>  
>  def isValidGitDir(path):
> -if (os.path.exists(path + "/HEAD")
> -and os.path.exists(path + "/refs") and os.path.exists(path + 
> "/objects")):
> -return True;
> -return False
> +return git_dir(path) != None
>  
>  def parseRevision(ref):
>  return read_pipe("git rev-parse %s" % ref).strip()
> @@ -3682,6 +3689,7 @@ def main():
>  if cmd.gitdir == None:
>  cmd.gitdir = os.path.abspath(".git")
>  if not isValidGitDir(cmd.gitdir):
> +# "rev-parse --git-dir" without arguments will try $PWD/.git
>  cmd.gitdir = read_pipe("git rev-parse --git-dir").strip()
>  if os.path.exists(cmd.gitdir):
>  cdup = read_pipe("git rev-parse --show-cdup").strip()
> @@ -3694,6 +3702,7 @@ def main():
>  else:
>  die("fatal: cannot locate git repository at %s" % cmd.gitdir)
>  
> +# so git commands invoked from the P4 workspace will succeed
>  os.environ["GIT_DIR"] = cmd.gitdir

The real fix has become surprisingly short and "feels right".

Will queue. Thanks.



[PATCH v2 5/6] update_unicode.sh: remove the plane filter

2016-12-13 Thread Beat Bolli
The uniset upstream has accepted my patches that eliminate the Unicode
plane offsets from the output in '--32' mode.

Remove the corresponding filter in update_unicode.sh.

This also fixes the issue that the plane offsets were not removed from
the second uniset call.

Signed-off-by: Beat Bolli 
---
 contrib/update-unicode/update_unicode.sh | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/contrib/update-unicode/update_unicode.sh 
b/contrib/update-unicode/update_unicode.sh
index 56871a1..e05db92 100755
--- a/contrib/update-unicode/update_unicode.sh
+++ b/contrib/update-unicode/update_unicode.sh
@@ -25,8 +25,7 @@ fi &&
 UNICODE_DIR=. && export UNICODE_DIR &&
 cat >$UNICODEWIDTH_H <<-EOF
 static const struct interval zero_width[] = {
-   $(uniset/uniset --32 cat:Me,Mn,Cf + U+1160..U+11FF - U+00AD |
- grep -v plane)
+   $(uniset/uniset --32 cat:Me,Mn,Cf + U+1160..U+11FF - U+00AD)
 };
 static const struct interval double_width[] = {
$(uniset/uniset --32 eaw:F,W)
-- 
2.7.2


[PATCH v2 3/6] update_unicode.sh: pin the uniset repo to a known good commit

2016-12-13 Thread Beat Bolli
The uniset upstream has added more commits that for example change the
hexadecimal output in '--32' mode to decimal. Let's pin the repo to a
commit that still outputs the width tables in the format we want.

Signed-off-by: Beat Bolli 
---
 contrib/update-unicode/update_unicode.sh | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/contrib/update-unicode/update_unicode.sh 
b/contrib/update-unicode/update_unicode.sh
index ff664ec..9f1bf31 100755
--- a/contrib/update-unicode/update_unicode.sh
+++ b/contrib/update-unicode/update_unicode.sh
@@ -15,7 +15,8 @@ if ! test -f EastAsianWidth.txt; then
wget http://www.unicode.org/Public/UCD/latest/ucd/EastAsianWidth.txt
 fi &&
 if ! test -d uniset; then
-   git clone https://github.com/depp/uniset.git
+   git clone https://github.com/depp/uniset.git &&
+   ( cd uniset && git checkout 4b186196dd )
 fi &&
 (
cd uniset &&
-- 
2.7.2


[PATCH v2 1/6] update_unicode.sh: move it into contrib/update-unicode

2016-12-13 Thread Beat Bolli
As it's used only by a tiny minority of the Git developer population,
this script does not belong into the main Git source directory.

Move it into contrib/ and adjust the paths to account for the new
location.

Signed-off-by: Beat Bolli 
---
 .gitignore   |  1 -
 contrib/update-unicode/.gitignore|  3 +++
 contrib/update-unicode/README| 20 
 contrib/update-unicode/update_unicode.sh | 38 ++
 update_unicode.sh| 40 
 5 files changed, 61 insertions(+), 41 deletions(-)
 create mode 100644 contrib/update-unicode/.gitignore
 create mode 100644 contrib/update-unicode/README
 create mode 100755 contrib/update-unicode/update_unicode.sh
 delete mode 100755 update_unicode.sh

diff --git a/.gitignore b/.gitignore
index f96e50e..ae0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -204,7 +204,6 @@
 /config.mak.autogen
 /config.mak.append
 /configure
-/unicode
 /tags
 /TAGS
 /cscope*
diff --git a/contrib/update-unicode/.gitignore 
b/contrib/update-unicode/.gitignore
new file mode 100644
index 000..b0ebc6a
--- /dev/null
+++ b/contrib/update-unicode/.gitignore
@@ -0,0 +1,3 @@
+uniset/
+UnicodeData.txt
+EastAsianWidth.txt
diff --git a/contrib/update-unicode/README b/contrib/update-unicode/README
new file mode 100644
index 000..b9e2fc8
--- /dev/null
+++ b/contrib/update-unicode/README
@@ -0,0 +1,20 @@
+TL;DR: Run update_unicode.sh after the publication of a new Unicode
+standard and commit the resulting unicode_widths.h file.
+
+The long version
+
+
+The Git source code ships the file unicode_widths.h which contains
+tables of zero and double width Unicode code points, respectively.
+These tables are generated using update_unicode.sh in this directory.
+update_unicode.sh itself uses a third-party tool, uniset, to query two
+Unicode data files for the interesting code points.
+
+On first run, update_unicode.sh clones uniset from Github and builds it.
+This requires a current-ish version of autoconf (2.69 works per December
+2016).
+
+On each run, update_unicode.sh checks whether more recent Unicode data
+files are available from the Unicode consortium, and rebuilds the header
+unicode_widths.h with the new data. The new header can then be
+committed.
diff --git a/contrib/update-unicode/update_unicode.sh 
b/contrib/update-unicode/update_unicode.sh
new file mode 100755
index 000..7b90126
--- /dev/null
+++ b/contrib/update-unicode/update_unicode.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+#See http://www.unicode.org/reports/tr44/
+#
+#Me Enclosing_Mark  an enclosing combining mark
+#Mn Nonspacing_Mark a nonspacing combining mark (zero advance width)
+#Cf Format  a format control character
+#
+cd "$(dirname "$0")"
+UNICODEWIDTH_H=$(git rev-parse --show-toplevel)/unicode_width.h
+(
+   if ! test -f UnicodeData.txt; then
+   wget 
http://www.unicode.org/Public/UCD/latest/ucd/UnicodeData.txt
+   fi &&
+   if ! test -f EastAsianWidth.txt; then
+   wget 
http://www.unicode.org/Public/UCD/latest/ucd/EastAsianWidth.txt
+   fi &&
+   if ! test -d uniset; then
+   git clone https://github.com/depp/uniset.git
+   fi &&
+   (
+   cd uniset &&
+   if ! test -x uniset; then
+   autoreconf -i &&
+   ./configure --enable-warnings=-Werror CFLAGS='-O0 -ggdb'
+   fi &&
+   make
+   ) &&
+   UNICODE_DIR=. && export UNICODE_DIR &&
+   cat >$UNICODEWIDTH_H <<-EOF
+   static const struct interval zero_width[] = {
+   $(uniset/uniset --32 cat:Me,Mn,Cf + U+1160..U+11FF - U+00AD |
+ grep -v plane)
+   };
+   static const struct interval double_width[] = {
+   $(uniset/uniset --32 eaw:F,W)
+   };
+   EOF
+)
diff --git a/update_unicode.sh b/update_unicode.sh
deleted file mode 100755
index 27af77c..000
--- a/update_unicode.sh
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/bin/sh
-#See http://www.unicode.org/reports/tr44/
-#
-#Me Enclosing_Mark  an enclosing combining mark
-#Mn Nonspacing_Mark a nonspacing combining mark (zero advance width)
-#Cf Format  a format control character
-#
-UNICODEWIDTH_H=../unicode_width.h
-if ! test -d unicode; then
-   mkdir unicode
-fi &&
-( cd unicode &&
-   if ! test -f UnicodeData.txt; then
-   wget 
http://www.unicode.org/Public/UCD/latest/ucd/UnicodeData.txt
-   fi &&
-   if ! test -f EastAsianWidth.txt; then
-   wget 
http://www.unicode.org/Public/UCD/latest/ucd/EastAsianWidth.txt
-   fi &&
-   if ! test -d uniset; then
-   git clone https://github.com/depp/uniset.git
-   fi &&
-   (
-   cd uniset &&
-   if ! test -x uniset; then
-   autoreconf -i &&
-   ./configure --enable-warnings=-Werror CFLAGS='-O0 

[PATCH v2 4/6] update-unicode.sh: automatically download newer definition files

2016-12-13 Thread Beat Bolli
Checking just for the unicode data files' existence is not sufficient;
we should also download them if a newer version exists on the Unicode
consortium's servers. Option -N of wget does this nicely for us.

Reviewed-by: Torsten Bögershausen 
Signed-off-by: Beat Bolli 
---
 contrib/update-unicode/update_unicode.sh | 8 ++--
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/contrib/update-unicode/update_unicode.sh 
b/contrib/update-unicode/update_unicode.sh
index 9f1bf31..56871a1 100755
--- a/contrib/update-unicode/update_unicode.sh
+++ b/contrib/update-unicode/update_unicode.sh
@@ -8,12 +8,8 @@
 cd "$(dirname "$0")"
 UNICODEWIDTH_H=$(git rev-parse --show-toplevel)/unicode_width.h
 
-if ! test -f UnicodeData.txt; then
-   wget http://www.unicode.org/Public/UCD/latest/ucd/UnicodeData.txt
-fi &&
-if ! test -f EastAsianWidth.txt; then
-   wget http://www.unicode.org/Public/UCD/latest/ucd/EastAsianWidth.txt
-fi &&
+wget -N http://www.unicode.org/Public/UCD/latest/ucd/UnicodeData.txt \
+   http://www.unicode.org/Public/UCD/latest/ucd/EastAsianWidth.txt &&
 if ! test -d uniset; then
git clone https://github.com/depp/uniset.git &&
( cd uniset && git checkout 4b186196dd )
-- 
2.7.2


[PATCH v2 2/6] update_unicode.sh: remove an unnecessary subshell level

2016-12-13 Thread Beat Bolli
After the move into contrib/update-unicode, we no longer create the
unicode directory to have a clean working folder. Instead, the directory
of the script is used. This means that the subshell can be removed.

Signed-off-by: Beat Bolli 
---
 contrib/update-unicode/update_unicode.sh | 53 
 1 file changed, 26 insertions(+), 27 deletions(-)

diff --git a/contrib/update-unicode/update_unicode.sh 
b/contrib/update-unicode/update_unicode.sh
index 7b90126..ff664ec 100755
--- a/contrib/update-unicode/update_unicode.sh
+++ b/contrib/update-unicode/update_unicode.sh
@@ -7,32 +7,31 @@
 #
 cd "$(dirname "$0")"
 UNICODEWIDTH_H=$(git rev-parse --show-toplevel)/unicode_width.h
+
+if ! test -f UnicodeData.txt; then
+   wget http://www.unicode.org/Public/UCD/latest/ucd/UnicodeData.txt
+fi &&
+if ! test -f EastAsianWidth.txt; then
+   wget http://www.unicode.org/Public/UCD/latest/ucd/EastAsianWidth.txt
+fi &&
+if ! test -d uniset; then
+   git clone https://github.com/depp/uniset.git
+fi &&
 (
-   if ! test -f UnicodeData.txt; then
-   wget 
http://www.unicode.org/Public/UCD/latest/ucd/UnicodeData.txt
+   cd uniset &&
+   if ! test -x uniset; then
+   autoreconf -i &&
+   ./configure --enable-warnings=-Werror CFLAGS='-O0 -ggdb'
fi &&
-   if ! test -f EastAsianWidth.txt; then
-   wget 
http://www.unicode.org/Public/UCD/latest/ucd/EastAsianWidth.txt
-   fi &&
-   if ! test -d uniset; then
-   git clone https://github.com/depp/uniset.git
-   fi &&
-   (
-   cd uniset &&
-   if ! test -x uniset; then
-   autoreconf -i &&
-   ./configure --enable-warnings=-Werror CFLAGS='-O0 -ggdb'
-   fi &&
-   make
-   ) &&
-   UNICODE_DIR=. && export UNICODE_DIR &&
-   cat >$UNICODEWIDTH_H <<-EOF
-   static const struct interval zero_width[] = {
-   $(uniset/uniset --32 cat:Me,Mn,Cf + U+1160..U+11FF - U+00AD |
- grep -v plane)
-   };
-   static const struct interval double_width[] = {
-   $(uniset/uniset --32 eaw:F,W)
-   };
-   EOF
-)
+   make
+) &&
+UNICODE_DIR=. && export UNICODE_DIR &&
+cat >$UNICODEWIDTH_H <<-EOF
+static const struct interval zero_width[] = {
+   $(uniset/uniset --32 cat:Me,Mn,Cf + U+1160..U+11FF - U+00AD |
+ grep -v plane)
+};
+static const struct interval double_width[] = {
+   $(uniset/uniset --32 eaw:F,W)
+};
+EOF
-- 
2.7.2


[PATCH v2 0/6] unicode_width.h: update the width tables to Unicode 9.0

2016-12-13 Thread Beat Bolli
This is v2 of my Unicode 9.0 series. After a short discussion [1], we
decided to move the generator script into contrib. This is what this
series now does first. The script is then updated in contrib.

Diff to v1:
- complete commit reordering
- fix nits in the commit messages

.gitignore   |   1 -
contrib/update-unicode/.gitignore|   3 ++
contrib/update-unicode/README|  20 +++
contrib/update-unicode/update_unicode.sh |  33 ++
unicode_width.h  | 131 
++-
update_unicode.sh|  40 --
6 files changed, 163 insertions(+), 65 deletions(-)

[1] http://public-inbox.org/git/xmqqr35dm203@gitster.mtv.corp.google.com/


[PATCH v2 6/6] unicode_width.h: update the width tables to Unicode 9.0

2016-12-13 Thread Beat Bolli
Rerunning update-unicode.sh that we fixed in the previous commits
produces these new tables.

Signed-off-by: Beat Bolli 
---
 unicode_width.h | 131 +---
 1 file changed, 107 insertions(+), 24 deletions(-)

diff --git a/unicode_width.h b/unicode_width.h
index 47cdd23..02207be 100644
--- a/unicode_width.h
+++ b/unicode_width.h
@@ -25,7 +25,7 @@ static const struct interval zero_width[] = {
 { 0x0825, 0x0827 },
 { 0x0829, 0x082D },
 { 0x0859, 0x085B },
-{ 0x08E4, 0x0902 },
+{ 0x08D4, 0x0902 },
 { 0x093A, 0x093A },
 { 0x093C, 0x093C },
 { 0x0941, 0x0948 },
@@ -120,6 +120,7 @@ static const struct interval zero_width[] = {
 { 0x17C9, 0x17D3 },
 { 0x17DD, 0x17DD },
 { 0x180B, 0x180E },
+{ 0x1885, 0x1886 },
 { 0x18A9, 0x18A9 },
 { 0x1920, 0x1922 },
 { 0x1927, 0x1928 },
@@ -158,7 +159,7 @@ static const struct interval zero_width[] = {
 { 0x1CF4, 0x1CF4 },
 { 0x1CF8, 0x1CF9 },
 { 0x1DC0, 0x1DF5 },
-{ 0x1DFC, 0x1DFF },
+{ 0x1DFB, 0x1DFF },
 { 0x200B, 0x200F },
 { 0x202A, 0x202E },
 { 0x2060, 0x2064 },
@@ -171,13 +172,13 @@ static const struct interval zero_width[] = {
 { 0x3099, 0x309A },
 { 0xA66F, 0xA672 },
 { 0xA674, 0xA67D },
-{ 0xA69F, 0xA69F },
+{ 0xA69E, 0xA69F },
 { 0xA6F0, 0xA6F1 },
 { 0xA802, 0xA802 },
 { 0xA806, 0xA806 },
 { 0xA80B, 0xA80B },
 { 0xA825, 0xA826 },
-{ 0xA8C4, 0xA8C4 },
+{ 0xA8C4, 0xA8C5 },
 { 0xA8E0, 0xA8F1 },
 { 0xA926, 0xA92D },
 { 0xA947, 0xA951 },
@@ -204,7 +205,7 @@ static const struct interval zero_width[] = {
 { 0xABED, 0xABED },
 { 0xFB1E, 0xFB1E },
 { 0xFE00, 0xFE0F },
-{ 0xFE20, 0xFE2D },
+{ 0xFE20, 0xFE2F },
 { 0xFEFF, 0xFEFF },
 { 0xFFF9, 0xFFFB },
 { 0x101FD, 0x101FD },
@@ -228,16 +229,21 @@ static const struct interval zero_width[] = {
 { 0x11173, 0x11173 },
 { 0x11180, 0x11181 },
 { 0x111B6, 0x111BE },
+{ 0x111CA, 0x111CC },
 { 0x1122F, 0x11231 },
 { 0x11234, 0x11234 },
 { 0x11236, 0x11237 },
+{ 0x1123E, 0x1123E },
 { 0x112DF, 0x112DF },
 { 0x112E3, 0x112EA },
-{ 0x11301, 0x11301 },
+{ 0x11300, 0x11301 },
 { 0x1133C, 0x1133C },
 { 0x11340, 0x11340 },
 { 0x11366, 0x1136C },
 { 0x11370, 0x11374 },
+{ 0x11438, 0x1143F },
+{ 0x11442, 0x11444 },
+{ 0x11446, 0x11446 },
 { 0x114B3, 0x114B8 },
 { 0x114BA, 0x114BA },
 { 0x114BF, 0x114C0 },
@@ -245,6 +251,7 @@ static const struct interval zero_width[] = {
 { 0x115B2, 0x115B5 },
 { 0x115BC, 0x115BD },
 { 0x115BF, 0x115C0 },
+{ 0x115DC, 0x115DD },
 { 0x11633, 0x1163A },
 { 0x1163D, 0x1163D },
 { 0x1163F, 0x11640 },
@@ -252,6 +259,16 @@ static const struct interval zero_width[] = {
 { 0x116AD, 0x116AD },
 { 0x116B0, 0x116B5 },
 { 0x116B7, 0x116B7 },
+{ 0x1171D, 0x1171F },
+{ 0x11722, 0x11725 },
+{ 0x11727, 0x1172B },
+{ 0x11C30, 0x11C36 },
+{ 0x11C38, 0x11C3D },
+{ 0x11C3F, 0x11C3F },
+{ 0x11C92, 0x11CA7 },
+{ 0x11CAA, 0x11CB0 },
+{ 0x11CB2, 0x11CB3 },
+{ 0x11CB5, 0x11CB6 },
 { 0x16AF0, 0x16AF4 },
 { 0x16B30, 0x16B36 },
 { 0x16F8F, 0x16F92 },
@@ -262,31 +279,59 @@ static const struct interval zero_width[] = {
 { 0x1D185, 0x1D18B },
 { 0x1D1AA, 0x1D1AD },
 { 0x1D242, 0x1D244 },
+{ 0x1DA00, 0x1DA36 },
+{ 0x1DA3B, 0x1DA6C },
+{ 0x1DA75, 0x1DA75 },
+{ 0x1DA84, 0x1DA84 },
+{ 0x1DA9B, 0x1DA9F },
+{ 0x1DAA1, 0x1DAAF },
+{ 0x1E000, 0x1E006 },
+{ 0x1E008, 0x1E018 },
+{ 0x1E01B, 0x1E021 },
+{ 0x1E023, 0x1E024 },
+{ 0x1E026, 0x1E02A },
 { 0x1E8D0, 0x1E8D6 },
+{ 0x1E944, 0x1E94A },
 { 0xE0001, 0xE0001 },
 { 0xE0020, 0xE007F },
 { 0xE0100, 0xE01EF }
 };
 static const struct interval double_width[] = {
-{ /* plane */ 0x0, 0x1C },
-{ /* plane */ 0x1C, 0x21 },
-{ /* plane */ 0x21, 0x22 },
-{ /* plane */ 0x22, 0x23 },
-{ /* plane */ 0x0, 0x0 },
-{ /* plane */ 0x0, 0x0 },
-{ /* plane */ 0x0, 0x0 },
-{ /* plane */ 0x0, 0x0 },
-{ /* plane */ 0x0, 0x0 },
-{ /* plane */ 0x0, 0x0 },
-{ /* plane */ 0x0, 0x0 },
-{ /* plane */ 0x0, 0x0 },
-{ /* plane */ 0x0, 0x0 },
-{ /* plane */ 0x0, 0x0 },
-{ /* plane */ 0x0, 0x0 },
-{ /* plane */ 0x0, 0x0 },
-{ /* plane */ 0x0, 0x0 },
 { 0x1100, 0x115F },
+{ 0x231A, 0x231B },
 { 0x2329, 0x232A },
+{ 0x23E9, 0x23EC },
+{ 0x23F0, 0x23F0 },
+{ 0x23F3, 0x23F3 },
+{ 0x25FD, 0x25FE },
+{ 0x2614, 0x2615 },
+{ 0x2648, 0x2653 },
+{ 0x267F, 0x267F },
+{ 0x2693, 0x2693 },
+{ 0x26A1, 0x26A1 },
+{ 0x26AA, 0x26AB },
+{ 0x26BD, 0x26BE },
+{ 0x26C4, 0x26C5 },
+{ 0x26CE, 0x26CE },
+{ 0x26D4, 0x26D4 },
+{ 0x26EA, 0x26EA },
+{ 0x26F2, 0x26F3 },
+{ 0x26F5, 0x26F5 },
+{ 0x26FA, 0x26FA },
+{ 0x26FD, 0x26FD },
+{ 0x2705, 0x2705 },
+{ 0x270A, 0x270B },
+{ 0x2728, 0x2728 },
+{ 0x274C, 0x274C },
+{ 0x274E, 0x274E },
+{ 0x2753, 0x2755 },
+{ 0x2757, 0x2757 },
+{ 0x2795, 0x2797 },
+{ 0x27B0, 0x27B0 },
+{ 0x27BF, 0x27BF },
+{ 0x2B1B, 0x2B1C },
+{ 0x2B50, 0x2B50 },
+{ 0x2B55, 0x2B55 },
 { 0x2E80, 0x2E99 },
 { 0x2E9B, 0x2EF3 },
 { 0x2F00, 0x2FD5 },
@@ -313,11 +358,49 @@ static const struct interval double_width[] = {
 { 0xFE68, 0xFE6B },
 { 0xFF01, 0xFF60 },
 { 0xFFE0, 0xFFE6 },
+{ 0x16FE0, 0x16FE0 },
+{ 0x17000, 0x187EC },
+{ 0x18800, 0x18AF2 },
 { 0x1B000, 0x1B001 },
+{ 0x1F004, 0x1F004 },
+{ 0x1F0CF, 0x1F0

[PATCH v3 10/16] pathspec: factor global magic into its own function

2016-12-13 Thread Brandon Williams
Create helper functions to read the global magic environment variables
in additon to factoring out the global magic gathering logic into its
own function.

Signed-off-by: Brandon Williams 
---
 pathspec.c | 127 +
 1 file changed, 78 insertions(+), 49 deletions(-)

diff --git a/pathspec.c b/pathspec.c
index d44f4b6..10ce9c1 100644
--- a/pathspec.c
+++ b/pathspec.c
@@ -87,6 +87,75 @@ static void prefix_magic(struct strbuf *sb, int prefixlen, 
unsigned magic)
strbuf_addf(sb, ",prefix:%d)", prefixlen);
 }
 
+static inline int get_literal_global(void)
+{
+   static int literal = -1;
+
+   if (literal < 0)
+   literal = git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT, 0);
+
+   return literal;
+}
+
+static inline int get_glob_global(void)
+{
+   static int glob = -1;
+
+   if (glob < 0)
+   glob = git_env_bool(GIT_GLOB_PATHSPECS_ENVIRONMENT, 0);
+
+   return glob;
+}
+
+static inline int get_noglob_global(void)
+{
+   static int noglob = -1;
+
+   if (noglob < 0)
+   noglob = git_env_bool(GIT_NOGLOB_PATHSPECS_ENVIRONMENT, 0);
+
+   return noglob;
+}
+
+static inline int get_icase_global(void)
+{
+   static int icase = -1;
+
+   if (icase < 0)
+   icase = git_env_bool(GIT_ICASE_PATHSPECS_ENVIRONMENT, 0);
+
+   return icase;
+}
+
+static int get_global_magic(int element_magic)
+{
+   int global_magic = 0;
+
+   if (get_literal_global())
+   global_magic |= PATHSPEC_LITERAL;
+
+   /* --glob-pathspec is overridden by :(literal) */
+   if (get_glob_global() && !(element_magic & PATHSPEC_LITERAL))
+   global_magic |= PATHSPEC_GLOB;
+
+   if (get_glob_global() && get_noglob_global())
+   die(_("global 'glob' and 'noglob' pathspec settings are 
incompatible"));
+
+   if (get_icase_global())
+   global_magic |= PATHSPEC_ICASE;
+
+   if ((global_magic & PATHSPEC_LITERAL) &&
+   (global_magic & ~PATHSPEC_LITERAL))
+   die(_("global 'literal' pathspec setting is incompatible "
+ "with all other global pathspec settings"));
+
+   /* --noglob-pathspec adds :(literal) _unless_ :(glob) is specified */
+   if (get_noglob_global() && !(element_magic & PATHSPEC_GLOB))
+   global_magic |= PATHSPEC_LITERAL;
+
+   return global_magic;
+}
+
 /*
  * Take an element of a pathspec and check for magic signatures.
  * Append the result to the prefix. Return the magic bitmap.
@@ -104,46 +173,12 @@ static unsigned prefix_pathspec(struct pathspec_item 
*item, unsigned flags,
const char *prefix, int prefixlen,
const char *elt)
 {
-   static int literal_global = -1;
-   static int glob_global = -1;
-   static int noglob_global = -1;
-   static int icase_global = -1;
-   unsigned magic = 0, element_magic = 0, global_magic = 0;
+   unsigned magic = 0, element_magic = 0;
const char *copyfrom = elt;
char *match;
int i, pathspec_prefix = -1;
 
-   if (literal_global < 0)
-   literal_global = 
git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT, 0);
-   if (literal_global)
-   global_magic |= PATHSPEC_LITERAL;
-
-   if (glob_global < 0)
-   glob_global = git_env_bool(GIT_GLOB_PATHSPECS_ENVIRONMENT, 0);
-   if (glob_global)
-   global_magic |= PATHSPEC_GLOB;
-
-   if (noglob_global < 0)
-   noglob_global = git_env_bool(GIT_NOGLOB_PATHSPECS_ENVIRONMENT, 
0);
-
-   if (glob_global && noglob_global)
-   die(_("global 'glob' and 'noglob' pathspec settings are 
incompatible"));
-
-
-   if (icase_global < 0)
-   icase_global = git_env_bool(GIT_ICASE_PATHSPECS_ENVIRONMENT, 0);
-   if (icase_global)
-   global_magic |= PATHSPEC_ICASE;
-
-   if ((global_magic & PATHSPEC_LITERAL) &&
-   (global_magic & ~PATHSPEC_LITERAL))
-   die(_("global 'literal' pathspec setting is incompatible "
- "with all other global pathspec settings"));
-
-   if (flags & PATHSPEC_LITERAL_PATH)
-   global_magic = 0;
-
-   if (elt[0] != ':' || literal_global ||
+   if (elt[0] != ':' || get_literal_global() ||
(flags & PATHSPEC_LITERAL_PATH)) {
; /* nothing to do */
} else if (elt[1] == '(') {
@@ -207,15 +242,11 @@ static unsigned prefix_pathspec(struct pathspec_item 
*item, unsigned flags,
 
magic |= element_magic;
 
-   /* --noglob-pathspec adds :(literal) _unless_ :(glob) is specified */
-   if (noglob_global && !(magic & PATHSPEC_GLOB))
-   global_magic |= PATHSPEC_LITERAL;
-
-   /* --glob-pathspec is overridden by :(literal) */
-   if ((global_magic & PATHSPEC_GLOB) && (magic & PATHSPEC_LITERAL))
-   globa

[PATCH v3 11/16] pathspec: create parse_short_magic function

2016-12-13 Thread Brandon Williams
Factor out the logic responsible for parsing short magic into its own
function.

Signed-off-by: Brandon Williams 
---
 pathspec.c | 54 --
 1 file changed, 36 insertions(+), 18 deletions(-)

diff --git a/pathspec.c b/pathspec.c
index 10ce9c1..94ec201 100644
--- a/pathspec.c
+++ b/pathspec.c
@@ -157,6 +157,41 @@ static int get_global_magic(int element_magic)
 }
 
 /*
+ * Parse the pathspec element looking for short magic
+ *
+ * saves all magic in 'magic'
+ * returns the position in 'elem' after all magic has been parsed
+ */
+static const char *parse_short_magic(unsigned *magic, const char *elem)
+{
+   const char *pos;
+
+   for (pos = elem + 1; *pos && *pos != ':'; pos++) {
+   char ch = *pos;
+   int i;
+
+   if (!is_pathspec_magic(ch))
+   break;
+
+   for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {
+   if (pathspec_magic[i].mnemonic == ch) {
+   *magic |= pathspec_magic[i].bit;
+   break;
+   }
+   }
+
+   if (ARRAY_SIZE(pathspec_magic) <= i)
+   die(_("Unimplemented pathspec magic '%c' in '%s'"),
+   ch, elem);
+   }
+
+   if (*pos == ':')
+   pos++;
+
+   return pos;
+}
+
+/*
  * Take an element of a pathspec and check for magic signatures.
  * Append the result to the prefix. Return the magic bitmap.
  *
@@ -220,24 +255,7 @@ static unsigned prefix_pathspec(struct pathspec_item 
*item, unsigned flags,
copyfrom++;
} else {
/* shorthand */
-   for (copyfrom = elt + 1;
-*copyfrom && *copyfrom != ':';
-copyfrom++) {
-   char ch = *copyfrom;
-
-   if (!is_pathspec_magic(ch))
-   break;
-   for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)
-   if (pathspec_magic[i].mnemonic == ch) {
-   element_magic |= pathspec_magic[i].bit;
-   break;
-   }
-   if (ARRAY_SIZE(pathspec_magic) <= i)
-   die(_("Unimplemented pathspec magic '%c' in 
'%s'"),
-   ch, elt);
-   }
-   if (*copyfrom == ':')
-   copyfrom++;
+   copyfrom = parse_short_magic(&element_magic, elt);
}
 
magic |= element_magic;
-- 
2.8.0.rc3.226.g39d4020



[PATCH v3 16/16] pathspec: rename prefix_pathspec to init_pathspec_item

2016-12-13 Thread Brandon Williams
Give a more relevant name to the prefix_pathspec function as it does
more than just prefix a pathspec element.

Signed-off-by: Brandon Williams 
---
 pathspec.c | 24 +++-
 1 file changed, 7 insertions(+), 17 deletions(-)

diff --git a/pathspec.c b/pathspec.c
index 4ce2016..d4efcf6 100644
--- a/pathspec.c
+++ b/pathspec.c
@@ -297,21 +297,11 @@ static void strip_submodule_slash_expensive(struct 
pathspec_item *item)
 }
 
 /*
- * Take an element of a pathspec and check for magic signatures.
- * Append the result to the prefix. Return the magic bitmap.
- *
- * For now, we only parse the syntax and throw out anything other than
- * "top" magic.
- *
- * NEEDSWORK: This needs to be rewritten when we start migrating
- * get_pathspec() users to use the "struct pathspec" interface.  For
- * example, a pathspec element may be marked as case-insensitive, but
- * the prefix part must always match literally, and a single stupid
- * string cannot express such a case.
+ * Perform the initialization of a pathspec_item based on a pathspec element.
  */
-static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,
-   const char *prefix, int prefixlen,
-   const char *elt)
+static void init_pathspec_item(struct pathspec_item *item, unsigned flags,
+  const char *prefix, int prefixlen,
+  const char *elt)
 {
unsigned magic = 0, element_magic = 0;
const char *copyfrom = elt;
@@ -329,6 +319,8 @@ static unsigned prefix_pathspec(struct pathspec_item *item, 
unsigned flags,
magic |= get_global_magic(element_magic);
}
 
+   item->magic = magic;
+
if (pathspec_prefix >= 0 &&
(prefixlen || (prefix && *prefix)))
die("BUG: 'prefix' magic is supposed to be used at worktree's 
root");
@@ -401,7 +393,6 @@ static unsigned prefix_pathspec(struct pathspec_item *item, 
unsigned flags,
/* sanity checks, pathspec matchers assume these are sane */
assert(item->nowildcard_len <= item->len &&
   item->prefix <= item->len);
-   return magic;
 }
 
 static int pathspec_item_cmp(const void *a_, const void *b_)
@@ -500,8 +491,7 @@ void parse_pathspec(struct pathspec *pathspec,
for (i = 0; i < n; i++) {
entry = argv[i];
 
-   item[i].magic = prefix_pathspec(item + i, flags,
-   prefix, prefixlen, entry);
+   init_pathspec_item(item + i, flags, prefix, prefixlen, entry);
 
if (item[i].magic & PATHSPEC_EXCLUDE)
nr_exclude++;
-- 
2.8.0.rc3.226.g39d4020



[PATCH v3 14/16] pathspec: create strip submodule slash helpers

2016-12-13 Thread Brandon Williams
Factor out the logic responsible for stripping the trailing slash on
pathspecs referencing submodules into its own function.

Signed-off-by: Brandon Williams 
---
 pathspec.c | 68 ++
 1 file changed, 42 insertions(+), 26 deletions(-)

diff --git a/pathspec.c b/pathspec.c
index a0fec49..6fd4b8e 100644
--- a/pathspec.c
+++ b/pathspec.c
@@ -258,6 +258,44 @@ static const char *parse_element_magic(unsigned *magic, 
int *prefix_len,
return parse_short_magic(magic, elem);
 }
 
+static void strip_submodule_slash_cheap(struct pathspec_item *item)
+{
+   if (item->len >= 1 && item->match[item->len - 1] == '/') {
+   int i = cache_name_pos(item->match, item->len - 1);
+
+   if (i >= 0 && S_ISGITLINK(active_cache[i]->ce_mode)) {
+   item->len--;
+   item->match[item->len] = '\0';
+   }
+   }
+}
+
+static void strip_submodule_slash_expensive(struct pathspec_item *item)
+{
+   int i;
+
+   for (i = 0; i < active_nr; i++) {
+   struct cache_entry *ce = active_cache[i];
+   int ce_len = ce_namelen(ce);
+
+   if (!S_ISGITLINK(ce->ce_mode))
+   continue;
+
+   if (item->len <= ce_len || item->match[ce_len] != '/' ||
+   memcmp(ce->name, item->match, ce_len))
+   continue;
+
+   if (item->len == ce_len + 1) {
+   /* strip trailing slash */
+   item->len--;
+   item->match[item->len] = '\0';
+   } else {
+   die(_("Pathspec '%s' is in submodule '%.*s'"),
+   item->original, ce_len, ce->name);
+   }
+   }
+}
+
 /*
  * Take an element of a pathspec and check for magic signatures.
  * Append the result to the prefix. Return the magic bitmap.
@@ -278,7 +316,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item, 
unsigned flags,
unsigned magic = 0, element_magic = 0;
const char *copyfrom = elt;
char *match;
-   int i, pathspec_prefix = -1;
+   int pathspec_prefix = -1;
 
/* PATHSPEC_LITERAL_PATH ignores magic */
if (flags & PATHSPEC_LITERAL_PATH) {
@@ -329,33 +367,11 @@ static unsigned prefix_pathspec(struct pathspec_item 
*item, unsigned flags,
item->len = strlen(item->match);
item->prefix = prefixlen;
 
-   if ((flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP) &&
-   (item->len >= 1 && item->match[item->len - 1] == '/') &&
-   (i = cache_name_pos(item->match, item->len - 1)) >= 0 &&
-   S_ISGITLINK(active_cache[i]->ce_mode)) {
-   item->len--;
-   match[item->len] = '\0';
-   }
+   if (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP)
+   strip_submodule_slash_cheap(item);
 
if (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE)
-   for (i = 0; i < active_nr; i++) {
-   struct cache_entry *ce = active_cache[i];
-   int ce_len = ce_namelen(ce);
-
-   if (!S_ISGITLINK(ce->ce_mode))
-   continue;
-
-   if (item->len <= ce_len || match[ce_len] != '/' ||
-   memcmp(ce->name, match, ce_len))
-   continue;
-   if (item->len == ce_len + 1) {
-   /* strip trailing slash */
-   item->len--;
-   match[item->len] = '\0';
-   } else
-   die (_("Pathspec '%s' is in submodule '%.*s'"),
-elt, ce_len, ce->name);
-   }
+   strip_submodule_slash_expensive(item);
 
if (magic & PATHSPEC_LITERAL)
item->nowildcard_len = item->len;
-- 
2.8.0.rc3.226.g39d4020



[PATCH v3 12/16] pathspec: create parse_long_magic function

2016-12-13 Thread Brandon Williams
Factor out the logic responsible for parsing long magic into its own
function.  As well as hoist the prefix check logic outside of the inner
loop as there isn't anything that needs to be done after matching
"prefix:".

Signed-off-by: Brandon Williams 
---
 pathspec.c | 92 ++
 1 file changed, 57 insertions(+), 35 deletions(-)

diff --git a/pathspec.c b/pathspec.c
index 94ec201..c77be17 100644
--- a/pathspec.c
+++ b/pathspec.c
@@ -157,6 +157,60 @@ static int get_global_magic(int element_magic)
 }
 
 /*
+ * Parse the pathspec element looking for long magic
+ *
+ * saves all magic in 'magic'
+ * if prefix magic is used, save the prefix length in 'prefix_len'
+ * returns the position in 'elem' after all magic has been parsed
+ */
+static const char *parse_long_magic(unsigned *magic, int *prefix_len,
+   const char *elem)
+{
+   const char *pos;
+   const char *nextat;
+
+   for (pos = elem + 2; *pos && *pos != ')'; pos = nextat) {
+   size_t len = strcspn(pos, ",)");
+   int i;
+
+   if (pos[len] == ',')
+   nextat = pos + len + 1; /* handle ',' */
+   else
+   nextat = pos + len; /* handle ')' and '\0' */
+
+   if (!len)
+   continue;
+
+   if (starts_with(pos, "prefix:")) {
+   char *endptr;
+   *prefix_len = strtol(pos + 7, &endptr, 10);
+   if (endptr - pos != len)
+   die(_("invalid parameter for pathspec magic 
'prefix'"));
+   continue;
+   }
+
+   for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {
+   if (strlen(pathspec_magic[i].name) == len &&
+   !strncmp(pathspec_magic[i].name, pos, len)) {
+   *magic |= pathspec_magic[i].bit;
+   break;
+   }
+   }
+
+   if (ARRAY_SIZE(pathspec_magic) <= i)
+   die(_("Invalid pathspec magic '%.*s' in '%s'"),
+   (int) len, pos, elem);
+   }
+
+   if (*pos != ')')
+   die(_("Missing ')' at the end of pathspec magic in '%s'"),
+   elem);
+   pos++;
+
+   return pos;
+}
+
+/*
  * Parse the pathspec element looking for short magic
  *
  * saves all magic in 'magic'
@@ -218,41 +272,9 @@ static unsigned prefix_pathspec(struct pathspec_item 
*item, unsigned flags,
; /* nothing to do */
} else if (elt[1] == '(') {
/* longhand */
-   const char *nextat;
-   for (copyfrom = elt + 2;
-*copyfrom && *copyfrom != ')';
-copyfrom = nextat) {
-   size_t len = strcspn(copyfrom, ",)");
-   if (copyfrom[len] == ',')
-   nextat = copyfrom + len + 1;
-   else
-   /* handle ')' and '\0' */
-   nextat = copyfrom + len;
-   if (!len)
-   continue;
-   for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {
-   if (strlen(pathspec_magic[i].name) == len &&
-   !strncmp(pathspec_magic[i].name, copyfrom, 
len)) {
-   element_magic |= pathspec_magic[i].bit;
-   break;
-   }
-   if (starts_with(copyfrom, "prefix:")) {
-   char *endptr;
-   pathspec_prefix = strtol(copyfrom + 7,
-&endptr, 10);
-   if (endptr - copyfrom != len)
-   die(_("invalid parameter for 
pathspec magic 'prefix'"));
-   /* "i" would be wrong, but it does not 
matter */
-   break;
-   }
-   }
-   if (ARRAY_SIZE(pathspec_magic) <= i)
-   die(_("Invalid pathspec magic '%.*s' in '%s'"),
-   (int) len, copyfrom, elt);
-   }
-   if (*copyfrom != ')')
-   die(_("Missing ')' at the end of pathspec magic in 
'%s'"), elt);
-   copyfrom++;
+   copyfrom = parse_long_magic(&element_magic,
+   &pathspec_prefix,
+   elt);
} else {
/* shorthand */
copyfrom = parse_short_

[PATCH v3 15/16] pathspec: small readability changes

2016-12-13 Thread Brandon Williams
A few small changes to improve readability.  This is done by grouping related
assignments, adding blank lines, ensuring lines are <80 characters, and
adding additional comments.

Signed-off-by: Brandon Williams 
---
 pathspec.c | 25 +++--
 1 file changed, 15 insertions(+), 10 deletions(-)

diff --git a/pathspec.c b/pathspec.c
index 6fd4b8e..4ce2016 100644
--- a/pathspec.c
+++ b/pathspec.c
@@ -67,11 +67,11 @@ static struct pathspec_magic {
char mnemonic; /* this cannot be ':'! */
const char *name;
 } pathspec_magic[] = {
-   { PATHSPEC_FROMTOP, '/', "top" },
-   { PATHSPEC_LITERAL,   0, "literal" },
-   { PATHSPEC_GLOB,   '\0', "glob" },
-   { PATHSPEC_ICASE,  '\0', "icase" },
-   { PATHSPEC_EXCLUDE, '!', "exclude" },
+   { PATHSPEC_FROMTOP,  '/', "top" },
+   { PATHSPEC_LITERAL, '\0', "literal" },
+   { PATHSPEC_GLOB,'\0', "glob" },
+   { PATHSPEC_ICASE,   '\0', "icase" },
+   { PATHSPEC_EXCLUDE,  '!', "exclude" },
 };
 
 static void prefix_magic(struct strbuf *sb, int prefixlen, unsigned magic)
@@ -336,6 +336,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item, 
unsigned flags,
if ((magic & PATHSPEC_LITERAL) && (magic & PATHSPEC_GLOB))
die(_("%s: 'literal' and 'glob' are incompatible"), elt);
 
+   /* Create match string which will be used for pathspec matching */
if (pathspec_prefix >= 0) {
match = xstrdup(copyfrom);
prefixlen = pathspec_prefix;
@@ -343,11 +344,16 @@ static unsigned prefix_pathspec(struct pathspec_item 
*item, unsigned flags,
match = xstrdup(copyfrom);
prefixlen = 0;
} else {
-   match = prefix_path_gently(prefix, prefixlen, &prefixlen, 
copyfrom);
+   match = prefix_path_gently(prefix, prefixlen,
+  &prefixlen, copyfrom);
if (!match)
die(_("%s: '%s' is outside repository"), elt, copyfrom);
}
+
item->match = match;
+   item->len = strlen(item->match);
+   item->prefix = prefixlen;
+
/*
 * Prefix the pathspec (keep all magic) and assign to
 * original. Useful for passing to another command.
@@ -364,8 +370,6 @@ static unsigned prefix_pathspec(struct pathspec_item *item, 
unsigned flags,
} else {
item->original = xstrdup(elt);
}
-   item->len = strlen(item->match);
-   item->prefix = prefixlen;
 
if (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP)
strip_submodule_slash_cheap(item);
@@ -373,13 +377,14 @@ static unsigned prefix_pathspec(struct pathspec_item 
*item, unsigned flags,
if (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE)
strip_submodule_slash_expensive(item);
 
-   if (magic & PATHSPEC_LITERAL)
+   if (magic & PATHSPEC_LITERAL) {
item->nowildcard_len = item->len;
-   else {
+   } else {
item->nowildcard_len = simple_length(item->match);
if (item->nowildcard_len < prefixlen)
item->nowildcard_len = prefixlen;
}
+
item->flags = 0;
if (magic & PATHSPEC_GLOB) {
/*
-- 
2.8.0.rc3.226.g39d4020



[PATCH v3 13/16] pathspec: create parse_element_magic helper

2016-12-13 Thread Brandon Williams
Factor out the logic responsible for the magic in a pathspec element
into its own function.

Also avoid calling into the parsing functions when
`PATHSPEC_LITERAL_PATH` is specified since it causes magic to be
ignored and all paths to be treated as literals.

Signed-off-by: Brandon Williams 
---
 pathspec.c | 37 -
 1 file changed, 20 insertions(+), 17 deletions(-)

diff --git a/pathspec.c b/pathspec.c
index c77be17..a0fec49 100644
--- a/pathspec.c
+++ b/pathspec.c
@@ -245,6 +245,19 @@ static const char *parse_short_magic(unsigned *magic, 
const char *elem)
return pos;
 }
 
+static const char *parse_element_magic(unsigned *magic, int *prefix_len,
+  const char *elem)
+{
+   if (elem[0] != ':' || get_literal_global())
+   return elem; /* nothing to do */
+   else if (elem[1] == '(')
+   /* longhand */
+   return parse_long_magic(magic, prefix_len, elem);
+   else
+   /* shorthand */
+   return parse_short_magic(magic, elem);
+}
+
 /*
  * Take an element of a pathspec and check for magic signatures.
  * Append the result to the prefix. Return the magic bitmap.
@@ -267,26 +280,16 @@ static unsigned prefix_pathspec(struct pathspec_item 
*item, unsigned flags,
char *match;
int i, pathspec_prefix = -1;
 
-   if (elt[0] != ':' || get_literal_global() ||
-   (flags & PATHSPEC_LITERAL_PATH)) {
-   ; /* nothing to do */
-   } else if (elt[1] == '(') {
-   /* longhand */
-   copyfrom = parse_long_magic(&element_magic,
-   &pathspec_prefix,
-   elt);
-   } else {
-   /* shorthand */
-   copyfrom = parse_short_magic(&element_magic, elt);
-   }
-
-   magic |= element_magic;
-
/* PATHSPEC_LITERAL_PATH ignores magic */
-   if (flags & PATHSPEC_LITERAL_PATH)
+   if (flags & PATHSPEC_LITERAL_PATH) {
magic = PATHSPEC_LITERAL;
-   else
+   } else {
+   copyfrom = parse_element_magic(&element_magic,
+  &pathspec_prefix,
+  elt);
+   magic |= element_magic;
magic |= get_global_magic(element_magic);
+   }
 
if (pathspec_prefix >= 0 &&
(prefixlen || (prefix && *prefix)))
-- 
2.8.0.rc3.226.g39d4020



[PATCH v3 01/16] mv: remove use of deprecated 'get_pathspec()'

2016-12-13 Thread Brandon Williams
Convert the 'internal_copy_pathspec()' function to 'prefix_path()'
instead of using the deprecated 'get_pathspec()' interface.  Also,
rename 'internal_copy_pathspec()' to 'internal_prefix_pathspec()' to be
more descriptive of what the funciton is actually doing.

In addition to this, fix a memory leak caused by only duplicating some
of the pathspec elements.  Instead always duplicate all of the the
pathspec elements as an intermediate step (with modificationed based on
the passed in flags).  This way the intermediate strings can then be
freed after getting the result from 'prefix_path()'.

Signed-off-by: Brandon Williams 
---
 builtin/mv.c | 50 +++---
 1 file changed, 31 insertions(+), 19 deletions(-)

diff --git a/builtin/mv.c b/builtin/mv.c
index 2f43877..4e86dc5 100644
--- a/builtin/mv.c
+++ b/builtin/mv.c
@@ -4,6 +4,7 @@
  * Copyright (C) 2006 Johannes Schindelin
  */
 #include "builtin.h"
+#include "pathspec.h"
 #include "lockfile.h"
 #include "dir.h"
 #include "cache-tree.h"
@@ -19,31 +20,42 @@ static const char * const builtin_mv_usage[] = {
 #define DUP_BASENAME 1
 #define KEEP_TRAILING_SLASH 2
 
-static const char **internal_copy_pathspec(const char *prefix,
-  const char **pathspec,
-  int count, unsigned flags)
+static const char **internal_prefix_pathspec(const char *prefix,
+const char **pathspec,
+int count, unsigned flags)
 {
int i;
const char **result;
+   int prefixlen = prefix ? strlen(prefix) : 0;
ALLOC_ARRAY(result, count + 1);
-   COPY_ARRAY(result, pathspec, count);
-   result[count] = NULL;
+
+   /* Create an intermediate copy of the pathspec based on the flags */
for (i = 0; i < count; i++) {
-   int length = strlen(result[i]);
+   int length = strlen(pathspec[i]);
int to_copy = length;
+   char *it;
while (!(flags & KEEP_TRAILING_SLASH) &&
-  to_copy > 0 && is_dir_sep(result[i][to_copy - 1]))
+  to_copy > 0 && is_dir_sep(pathspec[i][to_copy - 1]))
to_copy--;
-   if (to_copy != length || flags & DUP_BASENAME) {
-   char *it = xmemdupz(result[i], to_copy);
-   if (flags & DUP_BASENAME) {
-   result[i] = xstrdup(basename(it));
-   free(it);
-   } else
-   result[i] = it;
+
+   it = xmemdupz(pathspec[i], to_copy);
+   if (flags & DUP_BASENAME) {
+   result[i] = xstrdup(basename(it));
+   free(it);
+   } else {
+   result[i] = it;
}
}
-   return get_pathspec(prefix, result);
+   result[count] = NULL;
+
+   /* Prefix the pathspec and free the old intermediate strings */
+   for (i = 0; i < count; i++) {
+   const char *match = prefix_path(prefix, prefixlen, result[i]);
+   free((char *) result[i]);
+   result[i] = match;
+   }
+
+   return result;
 }
 
 static const char *add_slash(const char *path)
@@ -130,7 +142,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
if (read_cache() < 0)
die(_("index file corrupt"));
 
-   source = internal_copy_pathspec(prefix, argv, argc, 0);
+   source = internal_prefix_pathspec(prefix, argv, argc, 0);
modes = xcalloc(argc, sizeof(enum update_mode));
/*
 * Keep trailing slash, needed to let
@@ -140,16 +152,16 @@ int cmd_mv(int argc, const char **argv, const char 
*prefix)
flags = KEEP_TRAILING_SLASH;
if (argc == 1 && is_directory(argv[0]) && !is_directory(argv[1]))
flags = 0;
-   dest_path = internal_copy_pathspec(prefix, argv + argc, 1, flags);
+   dest_path = internal_prefix_pathspec(prefix, argv + argc, 1, flags);
submodule_gitfile = xcalloc(argc, sizeof(char *));
 
if (dest_path[0][0] == '\0')
/* special case: "." was normalized to "" */
-   destination = internal_copy_pathspec(dest_path[0], argv, argc, 
DUP_BASENAME);
+   destination = internal_prefix_pathspec(dest_path[0], argv, 
argc, DUP_BASENAME);
else if (!lstat(dest_path[0], &st) &&
S_ISDIR(st.st_mode)) {
dest_path[0] = add_slash(dest_path[0]);
-   destination = internal_copy_pathspec(dest_path[0], argv, argc, 
DUP_BASENAME);
+   destination = internal_prefix_pathspec(dest_path[0], argv, 
argc, DUP_BASENAME);
} else {
if (argc != 1)
die(_("destination '%s' is not a directory"), 
dest_path[0]);
-- 

[PATCH v3 06/16] pathspec: copy and free owned memory

2016-12-13 Thread Brandon Williams
The 'original' string entry in a pathspec_item is only duplicated some
of the time, instead always make a copy of the original and take
ownership of the memory.

Since both 'match' and 'original' string entries in a pathspec_item are
owned by the pathspec struct, they need to be freed when clearing the
pathspec struct (in 'clear_pathspec()') and duplicated when copying the
pathspec struct (in 'copy_pathspec()').

Also change the type of 'match' and 'original' to 'char *' in order to
more explicitly show the ownership of the memory.

Signed-off-by: Brandon Williams 
---
 pathspec.c | 22 ++
 pathspec.h |  4 ++--
 2 files changed, 20 insertions(+), 6 deletions(-)

diff --git a/pathspec.c b/pathspec.c
index 1f918cb..8f367f0 100644
--- a/pathspec.c
+++ b/pathspec.c
@@ -259,8 +259,9 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
}
strbuf_addstr(&sb, match);
item->original = strbuf_detach(&sb, NULL);
-   } else
-   item->original = elt;
+   } else {
+   item->original = xstrdup(elt);
+   }
item->len = strlen(item->match);
item->prefix = prefixlen;
 
@@ -388,8 +389,8 @@ void parse_pathspec(struct pathspec *pathspec,
die("BUG: PATHSPEC_PREFER_CWD requires arguments");
 
pathspec->items = item = xcalloc(1, sizeof(*item));
-   item->match = prefix;
-   item->original = prefix;
+   item->match = xstrdup(prefix);
+   item->original = xstrdup(prefix);
item->nowildcard_len = item->len = strlen(prefix);
item->prefix = item->len;
pathspec->nr = 1;
@@ -453,13 +454,26 @@ void parse_pathspec(struct pathspec *pathspec,
 
 void copy_pathspec(struct pathspec *dst, const struct pathspec *src)
 {
+   int i;
+
*dst = *src;
ALLOC_ARRAY(dst->items, dst->nr);
COPY_ARRAY(dst->items, src->items, dst->nr);
+
+   for (i = 0; i < dst->nr; i++) {
+   dst->items[i].match = xstrdup(src->items[i].match);
+   dst->items[i].original = xstrdup(src->items[i].original);
+   }
 }
 
 void clear_pathspec(struct pathspec *pathspec)
 {
+   int i;
+
+   for (i = 0; i < pathspec->nr; i++) {
+   free(pathspec->items[i].match);
+   free(pathspec->items[i].original);
+   }
free(pathspec->items);
pathspec->items = NULL;
 }
diff --git a/pathspec.h b/pathspec.h
index 70a592e..49fd823 100644
--- a/pathspec.h
+++ b/pathspec.h
@@ -25,8 +25,8 @@ struct pathspec {
unsigned magic;
int max_depth;
struct pathspec_item {
-   const char *match;
-   const char *original;
+   char *match;
+   char *original;
unsigned magic;
int len, prefix;
int nowildcard_len;
-- 
2.8.0.rc3.226.g39d4020



[PATCH v3 07/16] pathspec: remove unused variable from unsupported_magic

2016-12-13 Thread Brandon Williams
Removed unused variable 'n' from the 'unsupported_magic()' function.

Signed-off-by: Brandon Williams 
---
 pathspec.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/pathspec.c b/pathspec.c
index 8f367f0..ec0d590 100644
--- a/pathspec.c
+++ b/pathspec.c
@@ -333,8 +333,8 @@ static void NORETURN unsupported_magic(const char *pattern,
   unsigned short_magic)
 {
struct strbuf sb = STRBUF_INIT;
-   int i, n;
-   for (n = i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {
+   int i;
+   for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {
const struct pathspec_magic *m = pathspec_magic + i;
if (!(magic & m->bit))
continue;
@@ -344,7 +344,6 @@ static void NORETURN unsupported_magic(const char *pattern,
strbuf_addf(&sb, "'%c'", m->mnemonic);
else
strbuf_addf(&sb, "'%s'", m->name);
-   n++;
}
/*
 * We may want to substitute "this command" with a command
-- 
2.8.0.rc3.226.g39d4020



[PATCH v3 05/16] pathspec: remove the deprecated get_pathspec function

2016-12-13 Thread Brandon Williams
Now that all callers of the old 'get_pathspec' interface have been
migrated to use the new pathspec struct interface it can be removed
from the codebase.

Since there are no more users of the '_raw' field in the pathspec struct
it can also be removed.  This patch also removes the old functionality
of modifying the const char **argv array that was passed into
parse_pathspec.  Instead the constructed 'match' string (which is a
pathspec element with the prefix prepended) is only stored in its
corresponding pathspec_item entry.

Signed-off-by: Brandon Williams 
---
 Documentation/technical/api-setup.txt |  2 --
 cache.h   |  1 -
 pathspec.c| 42 +++
 pathspec.h|  1 -
 4 files changed, 3 insertions(+), 43 deletions(-)

diff --git a/Documentation/technical/api-setup.txt 
b/Documentation/technical/api-setup.txt
index 540e455..eb1fa98 100644
--- a/Documentation/technical/api-setup.txt
+++ b/Documentation/technical/api-setup.txt
@@ -27,8 +27,6 @@ parse_pathspec(). This function takes several arguments:
 
 - prefix and args come from cmd_* functions
 
-get_pathspec() is obsolete and should never be used in new code.
-
 parse_pathspec() helps catch unsupported features and reject them
 politely. At a lower level, different pathspec-related functions may
 not support the same set of features. Such pathspec-sensitive
diff --git a/cache.h b/cache.h
index a50a61a..0f80e01 100644
--- a/cache.h
+++ b/cache.h
@@ -514,7 +514,6 @@ extern void set_git_work_tree(const char *tree);
 
 #define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
 
-extern const char **get_pathspec(const char *prefix, const char **pathspec);
 extern void setup_work_tree(void);
 extern const char *setup_git_directory_gently(int *);
 extern const char *setup_git_directory(void);
diff --git a/pathspec.c b/pathspec.c
index 22ca74a..1f918cb 100644
--- a/pathspec.c
+++ b/pathspec.c
@@ -103,7 +103,7 @@ static void prefix_short_magic(struct strbuf *sb, int 
prefixlen,
  */
 static unsigned prefix_pathspec(struct pathspec_item *item,
unsigned *p_short_magic,
-   const char **raw, unsigned flags,
+   unsigned flags,
const char *prefix, int prefixlen,
const char *elt)
 {
@@ -240,7 +240,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
if (!match)
die(_("%s: '%s' is outside repository"), elt, copyfrom);
}
-   *raw = item->match = match;
+   item->match = match;
/*
 * Prefix the pathspec (keep all magic) and assign to
 * original. Useful for passing to another command.
@@ -381,8 +381,6 @@ void parse_pathspec(struct pathspec *pathspec,
 
/* No arguments with prefix -> prefix pathspec */
if (!entry) {
-   static const char *raw[2];
-
if (flags & PATHSPEC_PREFER_FULL)
return;
 
@@ -394,10 +392,7 @@ void parse_pathspec(struct pathspec *pathspec,
item->original = prefix;
item->nowildcard_len = item->len = strlen(prefix);
item->prefix = item->len;
-   raw[0] = prefix;
-   raw[1] = NULL;
pathspec->nr = 1;
-   pathspec->_raw = raw;
return;
}
 
@@ -415,7 +410,6 @@ void parse_pathspec(struct pathspec *pathspec,
pathspec->nr = n;
ALLOC_ARRAY(pathspec->items, n);
item = pathspec->items;
-   pathspec->_raw = argv;
prefixlen = prefix ? strlen(prefix) : 0;
 
for (i = 0; i < n; i++) {
@@ -423,7 +417,7 @@ void parse_pathspec(struct pathspec *pathspec,
entry = argv[i];
 
item[i].magic = prefix_pathspec(item + i, &short_magic,
-   argv + i, flags,
+   flags,
prefix, prefixlen, entry);
if ((flags & PATHSPEC_LITERAL_PATH) &&
!(magic_mask & PATHSPEC_LITERAL))
@@ -457,36 +451,6 @@ void parse_pathspec(struct pathspec *pathspec,
}
 }
 
-/*
- * N.B. get_pathspec() is deprecated in favor of the "struct pathspec"
- * based interface - see pathspec.c:parse_pathspec().
- *
- * Arguments:
- *  - prefix - a path relative to the root of the working tree
- *  - pathspec - a list of paths underneath the prefix path
- *
- * Iterates over pathspec, prepending each path with prefix,
- * and return the resulting list.
- *
- * If pathspec is empty, return a singleton list containing prefix.
- *
- * If pathspec and prefix are both empty, return an empty list.
- *
- * This is typically used by built-in commands such as add.c, in order
- * to normalize argv arguments provided to the built-in into a li

[PATCH v3 08/16] pathspec: always show mnemonic and name in unsupported_magic

2016-12-13 Thread Brandon Williams
For better clarity, always show the mnemonic and name of the unsupported
magic being used.  This lets users have a more clear understanding of
what magic feature isn't supported.  And if they supplied a mnemonic,
the user will be told what its corresponding name is which will allow
them to more easily search the man pages for that magic type.

This also avoids passing an extra parameter around the pathspec
initialization code.

Signed-off-by: Brandon Williams 
---
 pathspec.c | 21 +++--
 1 file changed, 7 insertions(+), 14 deletions(-)

diff --git a/pathspec.c b/pathspec.c
index ec0d590..609c58f 100644
--- a/pathspec.c
+++ b/pathspec.c
@@ -101,9 +101,7 @@ static void prefix_short_magic(struct strbuf *sb, int 
prefixlen,
  * the prefix part must always match literally, and a single stupid
  * string cannot express such a case.
  */
-static unsigned prefix_pathspec(struct pathspec_item *item,
-   unsigned *p_short_magic,
-   unsigned flags,
+static unsigned prefix_pathspec(struct pathspec_item *item, unsigned flags,
const char *prefix, int prefixlen,
const char *elt)
 {
@@ -210,7 +208,6 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
}
 
magic |= short_magic;
-   *p_short_magic = short_magic;
 
/* --noglob-pathspec adds :(literal) _unless_ :(glob) is specified */
if (noglob_global && !(magic & PATHSPEC_GLOB))
@@ -329,8 +326,7 @@ static int pathspec_item_cmp(const void *a_, const void *b_)
 }
 
 static void NORETURN unsupported_magic(const char *pattern,
-  unsigned magic,
-  unsigned short_magic)
+  unsigned magic)
 {
struct strbuf sb = STRBUF_INIT;
int i;
@@ -340,8 +336,9 @@ static void NORETURN unsupported_magic(const char *pattern,
continue;
if (sb.len)
strbuf_addch(&sb, ' ');
-   if (short_magic & m->bit)
-   strbuf_addf(&sb, "'%c'", m->mnemonic);
+
+   if (m->mnemonic)
+   strbuf_addf(&sb, "'(%c)%s'", m->mnemonic, m->name);
else
strbuf_addf(&sb, "'%s'", m->name);
}
@@ -413,11 +410,9 @@ void parse_pathspec(struct pathspec *pathspec,
prefixlen = prefix ? strlen(prefix) : 0;
 
for (i = 0; i < n; i++) {
-   unsigned short_magic;
entry = argv[i];
 
-   item[i].magic = prefix_pathspec(item + i, &short_magic,
-   flags,
+   item[i].magic = prefix_pathspec(item + i, flags,
prefix, prefixlen, entry);
if ((flags & PATHSPEC_LITERAL_PATH) &&
!(magic_mask & PATHSPEC_LITERAL))
@@ -425,9 +420,7 @@ void parse_pathspec(struct pathspec *pathspec,
if (item[i].magic & PATHSPEC_EXCLUDE)
nr_exclude++;
if (item[i].magic & magic_mask)
-   unsupported_magic(entry,
- item[i].magic & magic_mask,
- short_magic);
+   unsupported_magic(entry, item[i].magic & magic_mask);
 
if ((flags & PATHSPEC_SYMLINK_LEADING_PATH) &&
has_symlink_leading_path(item[i].match, item[i].len)) {
-- 
2.8.0.rc3.226.g39d4020



[PATCH v3 09/16] pathspec: simpler logic to prefix original pathspec elements

2016-12-13 Thread Brandon Williams
The logic used to prefix an original pathspec element with 'prefix'
magic is more general purpose and can be used for more than just short
magic.  Remove the extra code paths and rename 'prefix_short_magic' to
'prefix_magic' to better indicate that it can be used in more general
situations.

Also, slightly change the logic which decides when to prefix the
original element in order to prevent a pathspec of "." from getting
converted to "" (empty string).

Signed-off-by: Brandon Williams 
---
 pathspec.c | 33 +
 1 file changed, 13 insertions(+), 20 deletions(-)

diff --git a/pathspec.c b/pathspec.c
index 609c58f..d44f4b6 100644
--- a/pathspec.c
+++ b/pathspec.c
@@ -74,13 +74,12 @@ static struct pathspec_magic {
{ PATHSPEC_EXCLUDE, '!', "exclude" },
 };
 
-static void prefix_short_magic(struct strbuf *sb, int prefixlen,
-  unsigned short_magic)
+static void prefix_magic(struct strbuf *sb, int prefixlen, unsigned magic)
 {
int i;
strbuf_addstr(sb, ":(");
for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)
-   if (short_magic & pathspec_magic[i].bit) {
+   if (magic & pathspec_magic[i].bit) {
if (sb->buf[sb->len - 1] != '(')
strbuf_addch(sb, ',');
strbuf_addstr(sb, pathspec_magic[i].name);
@@ -109,8 +108,8 @@ static unsigned prefix_pathspec(struct pathspec_item *item, 
unsigned flags,
static int glob_global = -1;
static int noglob_global = -1;
static int icase_global = -1;
-   unsigned magic = 0, short_magic = 0, global_magic = 0;
-   const char *copyfrom = elt, *long_magic_end = NULL;
+   unsigned magic = 0, element_magic = 0, global_magic = 0;
+   const char *copyfrom = elt;
char *match;
int i, pathspec_prefix = -1;
 
@@ -164,7 +163,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item, 
unsigned flags,
for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {
if (strlen(pathspec_magic[i].name) == len &&
!strncmp(pathspec_magic[i].name, copyfrom, 
len)) {
-   magic |= pathspec_magic[i].bit;
+   element_magic |= pathspec_magic[i].bit;
break;
}
if (starts_with(copyfrom, "prefix:")) {
@@ -183,7 +182,6 @@ static unsigned prefix_pathspec(struct pathspec_item *item, 
unsigned flags,
}
if (*copyfrom != ')')
die(_("Missing ')' at the end of pathspec magic in 
'%s'"), elt);
-   long_magic_end = copyfrom;
copyfrom++;
} else {
/* shorthand */
@@ -196,7 +194,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item, 
unsigned flags,
break;
for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)
if (pathspec_magic[i].mnemonic == ch) {
-   short_magic |= pathspec_magic[i].bit;
+   element_magic |= pathspec_magic[i].bit;
break;
}
if (ARRAY_SIZE(pathspec_magic) <= i)
@@ -207,7 +205,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item, 
unsigned flags,
copyfrom++;
}
 
-   magic |= short_magic;
+   magic |= element_magic;
 
/* --noglob-pathspec adds :(literal) _unless_ :(glob) is specified */
if (noglob_global && !(magic & PATHSPEC_GLOB))
@@ -242,18 +240,13 @@ static unsigned prefix_pathspec(struct pathspec_item 
*item, unsigned flags,
 * Prefix the pathspec (keep all magic) and assign to
 * original. Useful for passing to another command.
 */
-   if (flags & PATHSPEC_PREFIX_ORIGIN) {
+   if ((flags & PATHSPEC_PREFIX_ORIGIN) &&
+   prefixlen && !literal_global) {
struct strbuf sb = STRBUF_INIT;
-   if (prefixlen && !literal_global) {
-   /* Preserve the actual prefix length of each pattern */
-   if (short_magic)
-   prefix_short_magic(&sb, prefixlen, short_magic);
-   else if (long_magic_end) {
-   strbuf_add(&sb, elt, long_magic_end - elt);
-   strbuf_addf(&sb, ",prefix:%d)", prefixlen);
-   } else
-   strbuf_addf(&sb, ":(prefix:%d)", prefixlen);
-   }
+
+   /* Preserve the actual prefix length of each pattern */
+   prefix_magic(&sb, prefixlen, element_magic);
+
strbuf_addstr(&sb, match

[PATCH v3 03/16] dir: convert fill_directory to use the pathspec struct interface

2016-12-13 Thread Brandon Williams
Convert 'fill_directory()' to use the pathspec struct interface from
using the '_raw' entry in the pathspec struct.

Signed-off-by: Brandon Williams 
---
 dir.c | 12 
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/dir.c b/dir.c
index aadf073..15f7c99 100644
--- a/dir.c
+++ b/dir.c
@@ -174,17 +174,21 @@ char *common_prefix(const struct pathspec *pathspec)
 
 int fill_directory(struct dir_struct *dir, const struct pathspec *pathspec)
 {
-   size_t len;
+   char *prefix;
+   size_t prefix_len;
 
/*
 * Calculate common prefix for the pathspec, and
 * use that to optimize the directory walk
 */
-   len = common_prefix_len(pathspec);
+   prefix = common_prefix(pathspec);
+   prefix_len = prefix ? strlen(prefix) : 0;
 
/* Read the directory and prune it */
-   read_directory(dir, pathspec->nr ? pathspec->_raw[0] : "", len, 
pathspec);
-   return len;
+   read_directory(dir, prefix, prefix_len, pathspec);
+
+   free(prefix);
+   return prefix_len;
 }
 
 int within_depth(const char *name, int namelen,
-- 
2.8.0.rc3.226.g39d4020



[PATCH v3 02/16] dir: remove struct path_simplify

2016-12-13 Thread Brandon Williams
Teach simplify_away() and exclude_matches_pathspec() to handle struct
pathspec directly, eliminating the need for the struct path_simplify.

Also renamed the len parameter to pathlen in exclude_matches_pathspec()
to match the parameter names used in simplify_away().

Signed-off-by: Brandon Williams 
---
 dir.c | 154 ++
 1 file changed, 60 insertions(+), 94 deletions(-)

diff --git a/dir.c b/dir.c
index bfa8c8a..aadf073 100644
--- a/dir.c
+++ b/dir.c
@@ -16,11 +16,6 @@
 #include "varint.h"
 #include "ewah/ewok.h"
 
-struct path_simplify {
-   int len;
-   const char *path;
-};
-
 /*
  * Tells read_directory_recursive how a file or directory should be treated.
  * Values are ordered by significance, e.g. if a directory contains both
@@ -50,7 +45,7 @@ struct cached_dir {
 
 static enum path_treatment read_directory_recursive(struct dir_struct *dir,
const char *path, int len, struct untracked_cache_dir *untracked,
-   int check_only, const struct path_simplify *simplify);
+   int check_only, const struct pathspec *pathspec);
 static int get_dtype(struct dirent *de, const char *path, int len);
 
 int fspathcmp(const char *a, const char *b)
@@ -1312,7 +1307,7 @@ static enum exist_status directory_exists_in_index(const 
char *dirname, int len)
 static enum path_treatment treat_directory(struct dir_struct *dir,
struct untracked_cache_dir *untracked,
const char *dirname, int len, int baselen, int exclude,
-   const struct path_simplify *simplify)
+   const struct pathspec *pathspec)
 {
/* The "len-1" is to strip the final '/' */
switch (directory_exists_in_index(dirname, len-1)) {
@@ -1341,7 +1336,7 @@ static enum path_treatment treat_directory(struct 
dir_struct *dir,
untracked = lookup_untracked(dir->untracked, untracked,
 dirname + baselen, len - baselen);
return read_directory_recursive(dir, dirname, len,
-   untracked, 1, simplify);
+   untracked, 1, pathspec);
 }
 
 /*
@@ -1349,24 +1344,25 @@ static enum path_treatment treat_directory(struct 
dir_struct *dir,
  * reading - if the path cannot possibly be in the pathspec,
  * return true, and we'll skip it early.
  */
-static int simplify_away(const char *path, int pathlen, const struct 
path_simplify *simplify)
+static int simplify_away(const char *path, int pathlen,
+const struct pathspec *pathspec)
 {
-   if (simplify) {
-   for (;;) {
-   const char *match = simplify->path;
-   int len = simplify->len;
+   int i;
 
-   if (!match)
-   break;
-   if (len > pathlen)
-   len = pathlen;
-   if (!memcmp(path, match, len))
-   return 0;
-   simplify++;
-   }
-   return 1;
+   if (!pathspec || !pathspec->nr)
+   return 0;
+
+   for (i = 0; i < pathspec->nr; i++) {
+   const struct pathspec_item *item = &pathspec->items[i];
+   int len = item->nowildcard_len;
+
+   if (len > pathlen)
+   len = pathlen;
+   if (!ps_strncmp(item, item->match, path, len))
+   return 0;
}
-   return 0;
+
+   return 1;
 }
 
 /*
@@ -1380,19 +1376,25 @@ static int simplify_away(const char *path, int pathlen, 
const struct path_simpli
  *   2. the path is a directory prefix of some element in the
  *  pathspec
  */
-static int exclude_matches_pathspec(const char *path, int len,
-   const struct path_simplify *simplify)
-{
-   if (simplify) {
-   for (; simplify->path; simplify++) {
-   if (len == simplify->len
-   && !memcmp(path, simplify->path, len))
-   return 1;
-   if (len < simplify->len
-   && simplify->path[len] == '/'
-   && !memcmp(path, simplify->path, len))
-   return 1;
-   }
+static int exclude_matches_pathspec(const char *path, int pathlen,
+   const struct pathspec *pathspec)
+{
+   int i;
+
+   if (!pathspec || !pathspec->nr)
+   return 0;
+
+   for (i = 0; i < pathspec->nr; i++) {
+   const struct pathspec_item *item = &pathspec->items[i];
+   int len = item->nowildcard_len;
+
+   if (len == pathlen &&
+   !ps_strncmp(item, item->match, path, pathlen))
+   return 1;
+   if (len > pathlen &&
+   item->match[pathlen] == '/' &&
+   !ps_strncmp(item, item->match, 

[PATCH v3 00/16] pathspec cleanup

2016-12-13 Thread Brandon Williams
Differences in v3:
* more readable strip submodule slash helper function which conforms to git's
  style guide. [14/16]
* instead of having create_simply() use struct pathspec directly, remove the
  struct path_simplify entirely and use struct pathspec directly in both
  simplify_away() and exclude_matches_pathspec(). [02/16]
* small style issues corrected from v2. [15/16]

Brandon Williams (16):
  mv: remove use of deprecated 'get_pathspec()'
  dir: remove struct path_simplify
  dir: convert fill_directory to use the pathspec struct interface
  ls-tree: convert show_recursive to use the pathspec struct interface
  pathspec: remove the deprecated get_pathspec function
  pathspec: copy and free owned memory
  pathspec: remove unused variable from unsupported_magic
  pathspec: always show mnemonic and name in unsupported_magic
  pathspec: simpler logic to prefix original pathspec elements
  pathspec: factor global magic into its own function
  pathspec: create parse_short_magic function
  pathspec: create parse_long_magic function
  pathspec: create parse_element_magic helper
  pathspec: create strip submodule slash helpers
  pathspec: small readability changes
  pathspec: rename prefix_pathspec to init_pathspec_item

 Documentation/technical/api-setup.txt |   2 -
 builtin/ls-tree.c |  16 +-
 builtin/mv.c  |  50 ++--
 cache.h   |   1 -
 dir.c | 166 +---
 pathspec.c| 476 +++---
 pathspec.h|   5 +-
 7 files changed, 369 insertions(+), 347 deletions(-)

--- interdiff on 'origin/bw/pathspec-cleanup'

diff --git a/dir.c b/dir.c
index a50b6f0..15f7c99 100644
--- a/dir.c
+++ b/dir.c
@@ -16,11 +16,6 @@
 #include "varint.h"
 #include "ewah/ewok.h"
 
-struct path_simplify {
-   int len;
-   const char *path;
-};
-
 /*
  * Tells read_directory_recursive how a file or directory should be treated.
  * Values are ordered by significance, e.g. if a directory contains both
@@ -50,7 +45,7 @@ struct cached_dir {
 
 static enum path_treatment read_directory_recursive(struct dir_struct *dir,
const char *path, int len, struct untracked_cache_dir *untracked,
-   int check_only, const struct path_simplify *simplify);
+   int check_only, const struct pathspec *pathspec);
 static int get_dtype(struct dirent *de, const char *path, int len);
 
 int fspathcmp(const char *a, const char *b)
@@ -1316,7 +1311,7 @@ static enum exist_status directory_exists_in_index(const 
char *dirname, int len)
 static enum path_treatment treat_directory(struct dir_struct *dir,
struct untracked_cache_dir *untracked,
const char *dirname, int len, int baselen, int exclude,
-   const struct path_simplify *simplify)
+   const struct pathspec *pathspec)
 {
/* The "len-1" is to strip the final '/' */
switch (directory_exists_in_index(dirname, len-1)) {
@@ -1345,7 +1340,7 @@ static enum path_treatment treat_directory(struct 
dir_struct *dir,
untracked = lookup_untracked(dir->untracked, untracked,
 dirname + baselen, len - baselen);
return read_directory_recursive(dir, dirname, len,
-   untracked, 1, simplify);
+   untracked, 1, pathspec);
 }
 
 /*
@@ -1353,24 +1348,25 @@ static enum path_treatment treat_directory(struct 
dir_struct *dir,
  * reading - if the path cannot possibly be in the pathspec,
  * return true, and we'll skip it early.
  */
-static int simplify_away(const char *path, int pathlen, const struct 
path_simplify *simplify)
+static int simplify_away(const char *path, int pathlen,
+const struct pathspec *pathspec)
 {
-   if (simplify) {
-   for (;;) {
-   const char *match = simplify->path;
-   int len = simplify->len;
+   int i;
 
-   if (!match)
-   break;
-   if (len > pathlen)
-   len = pathlen;
-   if (!memcmp(path, match, len))
-   return 0;
-   simplify++;
-   }
-   return 1;
+   if (!pathspec || !pathspec->nr)
+   return 0;
+
+   for (i = 0; i < pathspec->nr; i++) {
+   const struct pathspec_item *item = &pathspec->items[i];
+   int len = item->nowildcard_len;
+
+   if (len > pathlen)
+   len = pathlen;
+   if (!ps_strncmp(item, item->match, path, len))
+   return 0;
}
-   return 0;
+
+   return 1;
 }
 
 /*
@@ -1384,19 +1380,25 @@ static int simplify_away(const char *path, int pathlen, 
const struct path_simpli
  *   2. the path is a directory prefix of some element in the
  *

[PATCH v3 04/16] ls-tree: convert show_recursive to use the pathspec struct interface

2016-12-13 Thread Brandon Williams
Convert 'show_recursive()' to use the pathspec struct interface from
using the '_raw' entry in the pathspec struct.

Signed-off-by: Brandon Williams 
---
 builtin/ls-tree.c | 16 +++-
 1 file changed, 7 insertions(+), 9 deletions(-)

diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index 0e30d86..d7ebeb4 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -31,21 +31,18 @@ static const  char * const ls_tree_usage[] = {
 
 static int show_recursive(const char *base, int baselen, const char *pathname)
 {
-   const char **s;
+   int i;
 
if (ls_options & LS_RECURSIVE)
return 1;
 
-   s = pathspec._raw;
-   if (!s)
+   if (!pathspec.nr)
return 0;
 
-   for (;;) {
-   const char *spec = *s++;
+   for (i = 0; i < pathspec.nr; i++) {
+   const char *spec = pathspec.items[i].match;
int len, speclen;
 
-   if (!spec)
-   return 0;
if (strncmp(base, spec, baselen))
continue;
len = strlen(pathname);
@@ -59,6 +56,7 @@ static int show_recursive(const char *base, int baselen, 
const char *pathname)
continue;
return 1;
}
+   return 0;
 }
 
 static int show_tree(const unsigned char *sha1, struct strbuf *base,
@@ -175,8 +173,8 @@ int cmd_ls_tree(int argc, const char **argv, const char 
*prefix)
 * cannot be lifted until it is converted to use
 * match_pathspec() or tree_entry_interesting()
 */
-   parse_pathspec(&pathspec, PATHSPEC_GLOB | PATHSPEC_ICASE |
- PATHSPEC_EXCLUDE,
+   parse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC &
+ ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),
   PATHSPEC_PREFER_CWD,
   prefix, argv + 1);
for (i = 0; i < pathspec.nr; i++)
-- 
2.8.0.rc3.226.g39d4020



[PATCHv3] git-p4: support git worktrees

2016-12-13 Thread Luke Diamand
git-p4 would attempt to find the git directory using
its own specific code, which did not know about git
worktrees.

Rework it to use "git rev-parse --git-dir" instead.

Add test cases for worktree usage and specifying
git directory via --git-dir and $GIT_DIR.

Signed-off-by: Luke Diamand 
---
 git-p4.py | 17 +
 t/t9800-git-p4-basic.sh   | 20 
 t/t9806-git-p4-options.sh | 32 
 3 files changed, 65 insertions(+), 4 deletions(-)

diff --git a/git-p4.py b/git-p4.py
index fd5ca52..6a1f65f 100755
--- a/git-p4.py
+++ b/git-p4.py
@@ -85,6 +85,16 @@ def p4_build_cmd(cmd):
 real_cmd += cmd
 return real_cmd
 
+def git_dir(path):
+""" Return TRUE if the given path is a git directory (/path/to/dir/.git).
+This won't automatically add ".git" to a directory.
+"""
+d = read_pipe(["git", "--git-dir", path, "rev-parse", "--git-dir"], 
True).strip()
+if not d or len(d) == 0:
+return None
+else:
+return d
+
 def chdir(path, is_client_path=False):
 """Do chdir to the given path, and set the PWD environment
variable for use by P4.  It does not look at getcwd() output.
@@ -563,10 +573,7 @@ def currentGitBranch():
 return read_pipe(["git", "name-rev", "HEAD"]).split(" ")[1].strip()
 
 def isValidGitDir(path):
-if (os.path.exists(path + "/HEAD")
-and os.path.exists(path + "/refs") and os.path.exists(path + 
"/objects")):
-return True;
-return False
+return git_dir(path) != None
 
 def parseRevision(ref):
 return read_pipe("git rev-parse %s" % ref).strip()
@@ -3682,6 +3689,7 @@ def main():
 if cmd.gitdir == None:
 cmd.gitdir = os.path.abspath(".git")
 if not isValidGitDir(cmd.gitdir):
+# "rev-parse --git-dir" without arguments will try $PWD/.git
 cmd.gitdir = read_pipe("git rev-parse --git-dir").strip()
 if os.path.exists(cmd.gitdir):
 cdup = read_pipe("git rev-parse --show-cdup").strip()
@@ -3694,6 +3702,7 @@ def main():
 else:
 die("fatal: cannot locate git repository at %s" % cmd.gitdir)
 
+# so git commands invoked from the P4 workspace will succeed
 os.environ["GIT_DIR"] = cmd.gitdir
 
 if not cmd.run(args):
diff --git a/t/t9800-git-p4-basic.sh b/t/t9800-git-p4-basic.sh
index 0730f18..093e9bd 100755
--- a/t/t9800-git-p4-basic.sh
+++ b/t/t9800-git-p4-basic.sh
@@ -257,6 +257,26 @@ test_expect_success 'submit from detached head' '
)
 '
 
+test_expect_success 'submit from worktree' '
+   test_when_finished cleanup_git &&
+   git p4 clone --dest="$git" //depot &&
+   (
+   cd "$git" &&
+   git worktree add ../worktree-test
+   ) &&
+   (
+   cd "$git/../worktree-test" &&
+   test_commit "worktree-commit" &&
+   git config git-p4.skipSubmitEdit true &&
+   git p4 submit
+   ) &&
+   (
+   cd "$cli" &&
+   p4 sync &&
+   test_path_is_file worktree-commit.t
+   )
+'
+
 test_expect_success 'kill p4d' '
kill_p4d
 '
diff --git a/t/t9806-git-p4-options.sh b/t/t9806-git-p4-options.sh
index 254d428..1ab76c4 100755
--- a/t/t9806-git-p4-options.sh
+++ b/t/t9806-git-p4-options.sh
@@ -269,6 +269,38 @@ test_expect_success 'submit works with two branches' '
)
 '
 
+test_expect_success 'use --git-dir option and GIT_DIR' '
+   test_when_finished cleanup_git &&
+   git p4 clone //depot --destination="$git" &&
+   (
+   cd "$git" &&
+   git config git-p4.skipSubmitEdit true &&
+   test_commit first-change &&
+   git p4 submit --git-dir "$git"
+   ) &&
+   (
+   cd "$cli" &&
+   p4 sync &&
+   test_path_is_file first-change.t &&
+   echo "cli_file" >cli_file.t &&
+   p4 add cli_file.t &&
+   p4 submit -d "cli change"
+   ) &&
+   (git --git-dir "$git" p4 sync) &&
+   (cd "$git" && git checkout -q p4/master) &&
+   test_path_is_file "$git"/cli_file.t &&
+   (
+   cd "$cli" &&
+   echo "cli_file2" >cli_file2.t &&
+   p4 add cli_file2.t  &&
+   p4 submit -d "cli change2"
+   ) &&
+   (GIT_DIR="$git" git p4 sync) &&
+   (cd "$git" && git checkout -q p4/master) &&
+   test_path_is_file "$git"/cli_file2.t
+'
+
+
 test_expect_success 'kill p4d' '
kill_p4d
 '
-- 
2.8.2.703.g78b384c.dirty



Re: [PATCH 02/17] dir: convert create_simplify to use the pathspec struct interface

2016-12-13 Thread Brandon Williams
On 12/09, Brandon Williams wrote:
> On 12/09, Duy Nguyen wrote:
> > On Fri, Dec 9, 2016 at 1:19 AM, Brandon Williams  wrote:
> > > On 12/08, Duy Nguyen wrote:
> > >> On Thu, Dec 8, 2016 at 7:03 AM, Brandon Williams  
> > >> wrote:
> > >> > On 12/07, Duy Nguyen wrote:
> > >> >> On Wed, Dec 7, 2016 at 4:51 AM, Brandon Williams  
> > >> >> wrote:
> > >> >> > Convert 'create_simplify()' to use the pathspec struct interface 
> > >> >> > from
> > >> >> > using the '_raw' entry in the pathspec.
> > >> >>
> > >> >> It would be even better to kill this create_simplify() and let
> > >> >> simplify_away() handle struct pathspec directly.
> > >> >>
> > >> >> There is a bug in this code, that might have been found if we
> > >> >> simpify_away() handled pathspec directly: the memcmp() in
> > >> >> simplify_away() will not play well with :(icase) magic. My bad. If
> > >> >> :(icase) is used, the easiest/safe way is simplify nothing. Later on
> > >> >> maybe we can teach simplify_away() to do strncasecmp instead. We could
> > >> >> ignore exclude patterns there too (although not excluding is not a
> > >> >> bug).
> > >> >
> > >> > So are you implying that the simplify struct needs to be killed?  That
> > >> > way the pathspec struct itself is being passed around instead?
> > >>
> > >> Yes. simplify struct was a thing when pathspec was an array of char *.
> > >> At this point I think it can retire (when we have time to retire it)
> > >
> > > Alright, then for now I can leave this change as is and have a follow up
> > > series that kills the simplify struct.
> > 
> > Do let me know if you decide to drop it, so I can put it back in my backlog.
> 
> K will do
> 

This actually turned out to be more straight forward than I thought.
I'll reroll this series again (with a few other changes) and include
killing the simplify struct.

-- 
Brandon Williams


Re: [PATCH] fix pushing to //server/share/dir paths on Windows

2016-12-13 Thread Junio C Hamano
Johannes Sixt  writes:

> There is a change in behavior: \\server\share is not transformed
> into //server/share anymore, but all subsequent directory separators
> are rewritten to '/'. This should not make a difference; Windows can
> handle the mix.

I saw Dscho had a similar "windows can handle the mix" change in an
earlier development cycle, I think, and this is being consistent.

>  Another long-standing bug uncovered by the quarantine series.
>
>  Dscho, it looks like this could fix the original report at
>  https://github.com/git-for-windows/git/issues/979
>
>  This patch should cook well because of the change in behavior.
>  I would not be surprised if there is some fall-out.
>
>  The other bug I'm alluding to, I still have to investigate. I do
>  not think that it can be counted as fall-out.
>
>  path.c | 24 +++-
>  1 file changed, 15 insertions(+), 9 deletions(-)

Thanks.

> diff --git a/path.c b/path.c
> index 52d889c88e..02dc70fb92 100644
> --- a/path.c
> +++ b/path.c
> @@ -991,7 +991,7 @@ const char *remove_leading_path(const char *in, const 
> char *prefix)
>   *
>   * Performs the following normalizations on src, storing the result in dst:
>   * - Ensures that components are separated by '/' (Windows only)
> - * - Squashes sequences of '/'.
> + * - Squashes sequences of '/' except "//server/share" on Windows

"on windows" because offset_1st_component() does the magic only
there?  Makes sense.

>   * - Removes "." components.
>   * - Removes ".." components, and the components the precede them.
>   * Returns failure (non-zero) if a ".." component appears as first path
> @@ -1014,17 +1014,23 @@ const char *remove_leading_path(const char *in, const 
> char *prefix)
>  int normalize_path_copy_len(char *dst, const char *src, int *prefix_len)
>  {
>   char *dst0;
> - int i;
> -
> - for (i = has_dos_drive_prefix(src); i > 0; i--)
> - *dst++ = *src++;
> - dst0 = dst;
> + int offset;
>  
> - if (is_dir_sep(*src)) {
> + /*
> +  * Handle initial part of absolute path: "/", "C:/", "\\server\share/".
> +  */
> + offset = offset_1st_component(src);
> + if (offset) {
> + /* Convert the trailing separator to '/' on Windows. */
> + memcpy(dst, src, offset - 1);
> + dst += offset - 1;
>   *dst++ = '/';
> - while (is_dir_sep(*src))
> - src++;
> + src += offset;
>   }
> + dst0 = dst;

By resetting dst0 here, we ensure that up_one that is triggered by
seeing "../" will not escape the \\server\share\ part, which makes
sense to me.

> + while (is_dir_sep(*src))
> + src++;
>  
>   for (;;) {
>   char c = *src;


Re: [PATCH v2 05/34] sequencer (rebase -i): learn about the 'verbose' mode

2016-12-13 Thread Junio C Hamano
Johannes Schindelin  writes:

> @@ -1493,9 +1498,26 @@ static int pick_commits(struct todo_list *todo_list, 
> struct replay_opts *opts)
>   }
>  
>   if (is_rebase_i(opts)) {
> + struct strbuf buf = STRBUF_INIT;
> +
>   /* Stopped in the middle, as planned? */
>   if (todo_list->current < todo_list->nr)
>   return 0;
> +
> + if (opts->verbose) {
> + const char *argv[] = {
> + "diff-tree", "--stat", NULL, NULL
> + };
> +
> + if (!read_oneliner(&buf, rebase_path_orig_head(), 0))
> + return error(_("could not read '%s'"),
> + rebase_path_orig_head());
> + strbuf_addstr(&buf, "..HEAD");
> + argv[2] = buf.buf;
> + run_command_v_opt(argv, RUN_GIT_CMD);
> + strbuf_reset(&buf);
> + }
> + strbuf_release(&buf);
>   }

It's a bit curious that the previous step avoided running a separate
process and instead did "diff-tree -p" all in C, but this one does not.

I think it is because this one is outside the loop?  The original,
being a scripted Porcelain, formulates a lazy and loose command
line, but you may want to tighten it up a bit if you spawn a
process.  If your user happens to have a file whose name is
$orig_head..HEAD, the command line you are creating (which is
identical to the scripted version) will barf with "ambiguous
argument".

One good thing about a complete C rewrite is that it won't have an
issue like this one because you'd be working with in-core objects.

> diff --git a/sequencer.h b/sequencer.h
> index cb21cfddee..f885b68395 100644
> --- a/sequencer.h
> +++ b/sequencer.h
> @@ -24,6 +24,7 @@ struct replay_opts {
>   int allow_empty;
>   int allow_empty_message;
>   int keep_redundant_commits;
> + int verbose;
>  
>   int mainline;


Re: [PATCH v2 02/34] sequencer (rebase -i): implement the 'noop' command

2016-12-13 Thread Junio C Hamano
Linus Torvalds  writes:

> On Tue, Dec 13, 2016 at 12:38 PM, Junio C Hamano  wrote:
>> Johannes Schindelin  writes:
>>
>>> +/*
>>> + * Note that ordering matters in this enum. Not only must it match the 
>>> mapping
>>> + * below, it is also divided into several sections that matter.  When 
>>> adding
>>> + * new commands, make sure you add it in the right section.
>>> + */
>>
>> Good thinking.  Makes me wish C were a better language, though ;-)
>
> Do this:
>
>   static const char *todo_command_strings[] = {
>   [TODO_PICK] = "pick",
>   [TODO_REVERT] = "revert",
>   [TODO_NOOP] = "noop:,
>   };
>
> which makes the array be order-independent. You still need to make
> sure you fill in all the entries, of course, but it tends to avoid at
> least one gotcha, and it makes it more obvious how the two are tied
> together.
>
>   Linus

Yes, I know.  But I do not think the variant of C we stick to is not
new enough to have that.


Re: [PATCH v2 06/34] sequencer (rebase -i): write the 'done' file

2016-12-13 Thread Junio C Hamano
Johannes Schindelin  writes:

> In the interactive rebase, commands that were successfully processed are
> not simply discarded, but appended to the 'done' file instead. This is
> used e.g. to display the current state to the user in the output of
> `git status` or the progress.
>
> Signed-off-by: Johannes Schindelin 
> ---

Looks good.

I'd stop at this point for now, and start working on other things
for the rest of the day.  I might find time to come back to it later
tonight.

So far, looking mostly good.


Re: [PATCH 1/4] doc: add articles (grammar)

2016-12-13 Thread Kristoffer Haugsbakk

Junio C Hamano writes:

> I was planning to merge all four from you as-is to 'next' today,
> though.  Should I wait?

I'll definitely defer to whatever you think is best.  I guess it depends
on whether you are interested in Philip Oakley's suggestions.  I sent
those emails to inform about what I intended to do in the next round, if
it got to that point, since I haven't tried to contribute to such an
organised project before.  So I was informing about my assumptions about
how to deal with "looks good to me"-kinds of feedback.

So for my part, I'm happy with iterating on this (perhaps just adding
the two "acks", or also replying to the suggestions), or just merging it
as-is.

-- 
Kristoffer Haugsbakk


Re: [PATCH v2 04/34] sequencer (rebase -i): implement the 'exec' command

2016-12-13 Thread Junio C Hamano
Johannes Schindelin  writes:

> +static int do_exec(const char *command_line)
> +{
> + const char *child_argv[] = { NULL, NULL };
> + int dirty, status;
> +
> + fprintf(stderr, "Executing: %s\n", command_line);
> + child_argv[0] = command_line;
> + status = run_command_v_opt(child_argv, RUN_USING_SHELL);
> +
> + /* force re-reading of the cache */
> + if (discard_cache() < 0 || read_cache() < 0)
> + return error(_("could not read index"));
> +
> + dirty = require_clean_work_tree("rebase", NULL, 1, 1);
> +
> + if (status) {
> + warning(_("execution failed: %s\n%s"
> +   "You can fix the problem, and then run\n"
> +   "\n"
> +   "  git rebase --continue\n"
> +   "\n"),
> + command_line,
> + dirty ? N_("and made changes to the index and/or the "
> + "working tree\n") : "");
> + if (status == 127)
> + /* command not found */
> + status = 1;
> + }
> + else if (dirty) {
> + warning(_("execution succeeded: %s\nbut "
> +   "left changes to the index and/or the working tree\n"
> +   "Commit or stash your changes, and then run\n"
> +   "\n"
> +   "  git rebase --continue\n"
> +   "\n"), command_line);
> + status = 1;
> + }
> +
> + return status;
> +}

OK, this looks like a faithful reproduction of what the scripted
version does inside do_next() helper function.

Please have "else if" on the same line as "}" that closes the
"if (...) {" in the same if/else if/else cascade.


Re: What's cooking in git.git (Dec 2016, #02; Mon, 12)

2016-12-13 Thread Brandon Williams
On 12/13, Junio C Hamano wrote:
> Johannes Schindelin  writes:
> 
> > ok 13 - grep tree and more pathspecs
> >
> > expecting success: 
> > git init parent &&
> > test_when_finished "rm -rf parent" &&
> > echo "foobar" >"parent/fi:le" &&
> > git -C parent add "fi:le" &&
> > git -C parent commit -m "add fi:le" &&
> > ...
> > test_cmp expect actual
> >
> > ++ git init parent
> > Initialized empty Git repository in C:/git-sdk-64/usr/src/git/wip3/t/trash
> > directory.t7814-grep-recurse-submodules/parent/.git/
> > ++ test_when_finished 'rm -rf parent'
> > ++ test 0 = 0
> > ++ test_cleanup='{ rm -rf parent
> > } && (exit "$eval_ret"); eval_ret=$?; :'
> > ++ echo foobar
> > ++ git -C parent add fi:le
> > fatal: pathspec 'fi:le' did not match any files
> 
> I think !MINGW prereq is missing?

Yes the !MINGW prereq is missing on this one test since the test uses a
filename with a ":" which isn't supported on windows.  I have that
change made in my local grep branch but I haven't sent out a reroll of
the series yet due to the underlying race-condition that existed (due to
the way realpath was being calculated).  I'll send out a reroll of the
series once the discussion on bw/realpath-wo-chdir has concluded (as
the grep series is now dependent on it).

-- 
Brandon Williams


[PATCH] fix pushing to //server/share/dir paths on Windows

2016-12-13 Thread Johannes Sixt
normalize_path_copy() is not prepared to keep the double-slash of a
//server/share/dir kind of path, but treats it like a regular POSIX
style path and transforms it to /server/share/dir.

The bug manifests when 'git push //server/share/dir master' is run,
because tmp_objdir_add_as_alternate() uses the path in normalized
form when it registers the quarantine object database via
link_alt_odb_entries(). Needless to say that the directory cannot be
accessed using the wrongly normalized path.

Fix it by skipping all of the root part, not just a potential drive
prefix. offset_1st_component takes care of this, see the
implementation in compat/mingw.c::mingw_offset_1st_component().

There is a change in behavior: \\server\share is not transformed
into //server/share anymore, but all subsequent directory separators
are rewritten to '/'. This should not make a difference; Windows can
handle the mix. In the context of 'git push' this cannot be verified,
though, as there seems to be an independent bug that transforms the
double '\\' to a single '\' on the way.

Signed-off-by: Johannes Sixt 
---
 Another long-standing bug uncovered by the quarantine series.

 Dscho, it looks like this could fix the original report at
 https://github.com/git-for-windows/git/issues/979

 This patch should cook well because of the change in behavior.
 I would not be surprised if there is some fall-out.

 The other bug I'm alluding to, I still have to investigate. I do
 not think that it can be counted as fall-out.

 path.c | 24 +++-
 1 file changed, 15 insertions(+), 9 deletions(-)

diff --git a/path.c b/path.c
index 52d889c88e..02dc70fb92 100644
--- a/path.c
+++ b/path.c
@@ -991,7 +991,7 @@ const char *remove_leading_path(const char *in, const char 
*prefix)
  *
  * Performs the following normalizations on src, storing the result in dst:
  * - Ensures that components are separated by '/' (Windows only)
- * - Squashes sequences of '/'.
+ * - Squashes sequences of '/' except "//server/share" on Windows
  * - Removes "." components.
  * - Removes ".." components, and the components the precede them.
  * Returns failure (non-zero) if a ".." component appears as first path
@@ -1014,17 +1014,23 @@ const char *remove_leading_path(const char *in, const 
char *prefix)
 int normalize_path_copy_len(char *dst, const char *src, int *prefix_len)
 {
char *dst0;
-   int i;
-
-   for (i = has_dos_drive_prefix(src); i > 0; i--)
-   *dst++ = *src++;
-   dst0 = dst;
+   int offset;
 
-   if (is_dir_sep(*src)) {
+   /*
+* Handle initial part of absolute path: "/", "C:/", "\\server\share/".
+*/
+   offset = offset_1st_component(src);
+   if (offset) {
+   /* Convert the trailing separator to '/' on Windows. */
+   memcpy(dst, src, offset - 1);
+   dst += offset - 1;
*dst++ = '/';
-   while (is_dir_sep(*src))
-   src++;
+   src += offset;
}
+   dst0 = dst;
+
+   while (is_dir_sep(*src))
+   src++;
 
for (;;) {
char c = *src;
-- 
2.11.0.79.g263f27a



Re: [PATCH v2 03/34] sequencer (rebase -i): implement the 'edit' command

2016-12-13 Thread Junio C Hamano
Johannes Schindelin  writes:

> @@ -43,6 +44,20 @@ static GIT_PATH_FUNC(rebase_path_todo, 
> "rebase-merge/git-rebase-todo")
>   */
>  static GIT_PATH_FUNC(rebase_path_author_script, "rebase-merge/author-script")
>  /*

It is minor, but please have a blank line to separate the logical
blocks.  If you have "comment for thing A" before "thing A", then 
having a blank after that before "comment for thing B" and "thing B"
that follow would help.  Otherwise "thing A" immediately followed by
"comment for thing B" are (mis)read together, leading to nonsense.

> + * When an "edit" rebase command is being processed, the SHA1 of the
> + * commit to be edited is recorded in this file.  When "git rebase
> + * --continue" is executed, if there are any staged changes then they
> + * will be amended to the HEAD commit, but only provided the HEAD
> + * commit is still the commit to be edited.  When any other rebase
> + * command is processed, this file is deleted.
> + */
> +static GIT_PATH_FUNC(rebase_path_amend, "rebase-merge/amend")
> +/*
> + * When we stop at a given patch via the "edit" command, this file contains
> + * the long commit name of the corresponding patch.

If you abbreviate an object name to 38-hex that is still long but
that is not full; if you meant full 40-hex, better spell it out as
"full"---that conveys useful information to programmers (e.g. they
can just use get_sha1_hex()).

But I think you are writing short_commit_name() to it?  So perhaps
"an abbreviated commit object name"?

> @@ -1301,9 +1318,87 @@ static int save_opts(struct replay_opts *opts)
>   return res;
>  }
>  
> +static int make_patch(struct commit *commit, struct replay_opts *opts)
> +{
> + struct strbuf buf = STRBUF_INIT;
> + struct rev_info log_tree_opt;
> + const char *commit_buffer = get_commit_buffer(commit, NULL), *subject, 
> *p;
> + int res = 0;
> +
> + p = short_commit_name(commit);
> + if (write_message(p, strlen(p), rebase_path_stopped_sha(), 1) < 0)
> + return -1;
> +
> + strbuf_addf(&buf, "%s/patch", get_dir(opts));
> + memset(&log_tree_opt, 0, sizeof(log_tree_opt));
> + init_revisions(&log_tree_opt, NULL);
> + log_tree_opt.abbrev = 0;
> + log_tree_opt.diff = 1;
> + log_tree_opt.diffopt.output_format = DIFF_FORMAT_PATCH;
> + log_tree_opt.disable_stdin = 1;
> + log_tree_opt.no_commit_id = 1;
> + log_tree_opt.diffopt.file = fopen(buf.buf, "w");
> + log_tree_opt.diffopt.use_color = GIT_COLOR_NEVER;
> + if (!log_tree_opt.diffopt.file)
> + res |= error_errno(_("could not open '%s'"), buf.buf);
> + else {
> + res |= log_tree_commit(&log_tree_opt, commit);
> + fclose(log_tree_opt.diffopt.file);
> + }
> + strbuf_reset(&buf);
> + strbuf_addf(&buf, "%s/message", get_dir(opts));
> + if (!file_exists(buf.buf)) {
> + find_commit_subject(commit_buffer, &subject);
> + res |= write_message(subject, strlen(subject), buf.buf, 1);
> + unuse_commit_buffer(commit, commit_buffer);
> + }
> + strbuf_release(&buf);
> +
> + return res;
> +}

OK.  This seems to match what scripted make_patch does in a handful
of lines.  We probably should have given you a helper to reduce
boilerplate that sets up log_tree_opt so that this function does not
have to be this long, but that is a separate topic.

Does it matter output_format is set to FORMAT_PATCH here, though?
With --no-commit-id set, I suspect there is no log message or
authorship information given to the output.

As you are only interested in seeing the patch/diff in this file and
the log is stored in a separate "message" file, as long as "patch"
file gets the patch correctly, it is not a problem, but it just
looked strange to see FORMAT_PATCH there.



Re: [PATCH v2 02/34] sequencer (rebase -i): implement the 'noop' command

2016-12-13 Thread Linus Torvalds
On Tue, Dec 13, 2016 at 12:38 PM, Junio C Hamano  wrote:
> Johannes Schindelin  writes:
>
>> +/*
>> + * Note that ordering matters in this enum. Not only must it match the 
>> mapping
>> + * below, it is also divided into several sections that matter.  When adding
>> + * new commands, make sure you add it in the right section.
>> + */
>
> Good thinking.  Makes me wish C were a better language, though ;-)

Do this:

  static const char *todo_command_strings[] = {
  [TODO_PICK] = "pick",
  [TODO_REVERT] = "revert",
  [TODO_NOOP] = "noop:,
  };

which makes the array be order-independent. You still need to make
sure you fill in all the entries, of course, but it tends to avoid at
least one gotcha, and it makes it more obvious how the two are tied
together.

  Linus


[PATCHv2 3/5] submodule: add flags to ok_to_remove_submodule

2016-12-13 Thread Stefan Beller
In different contexts the question whether deleting a submodule is ok
to remove may be answered differently.

In 293ab15eea (submodule: teach rm to remove submodules unless they
contain a git directory, 2012-09-26) a case was made that we can safely
ignore ignored untracked files for removal as we explicitely ask for the
removal of the submodule.

In a later patch we want to remove submodules even when the user doesn't
explicitly ask for it (e.g. checking out a tree-ish in which the submodule
doesn't exist).  In that case we want to be more careful when it comes
to deletion of untracked files. As of this patch it is unclear how this
will be implemented exactly, so we'll offer flags in which the caller
can specify how the different untracked files ought to be handled.

Signed-off-by: Stefan Beller 
---
 builtin/rm.c |  3 ++-
 submodule.c  | 23 +++
 submodule.h  |  5 -
 3 files changed, 25 insertions(+), 6 deletions(-)

diff --git a/builtin/rm.c b/builtin/rm.c
index 3f3e24eb36..fdd7183f61 100644
--- a/builtin/rm.c
+++ b/builtin/rm.c
@@ -187,7 +187,8 @@ static int check_local_mod(struct object_id *head, int 
index_only)
 */
if (ce_match_stat(ce, &st, 0) ||
(S_ISGITLINK(ce->ce_mode) &&
-!ok_to_remove_submodule(ce->name)))
+!ok_to_remove_submodule(ce->name,
+   SUBMODULE_REMOVAL_IGNORE_IGNORED_UNTRACKED)))
local_changes = 1;
 
/*
diff --git a/submodule.c b/submodule.c
index 9f0b544ebe..2d13744b06 100644
--- a/submodule.c
+++ b/submodule.c
@@ -1019,7 +1019,7 @@ int submodule_uses_gitfile(const char *path)
return 1;
 }
 
-int ok_to_remove_submodule(const char *path)
+int ok_to_remove_submodule(const char *path, unsigned flags)
 {
ssize_t len;
struct child_process cp = CHILD_PROCESS_INIT;
@@ -1032,15 +1032,27 @@ int ok_to_remove_submodule(const char *path)
if (!submodule_uses_gitfile(path))
return 0;
 
-   argv_array_pushl(&cp.args, "status", "--porcelain", "-u",
+   argv_array_pushl(&cp.args, "status", "--porcelain",
   "--ignore-submodules=none", NULL);
+
+   if (flags & SUBMODULE_REMOVAL_IGNORE_UNTRACKED)
+   argv_array_push(&cp.args, "-uno");
+   else
+   argv_array_push(&cp.args, "-uall");
+
+   if (!(flags & SUBMODULE_REMOVAL_IGNORE_IGNORED_UNTRACKED))
+   argv_array_push(&cp.args, "--ignored");
+
prepare_submodule_repo_env(&cp.env_array);
cp.git_cmd = 1;
cp.no_stdin = 1;
cp.out = -1;
cp.dir = path;
if (start_command(&cp))
-   die(_("could not run 'git status --porcelain -u 
--ignore-submodules=none' in submodule %s"), path);
+   die(_("could not run 'git status --porcelain 
--ignore-submodules=none %s %s' in submodule '%s'"),
+   (flags & SUBMODULE_REMOVAL_IGNORE_UNTRACKED) ? "-uno" : 
"-uall",
+   (!(flags & SUBMODULE_REMOVAL_IGNORE_IGNORED_UNTRACKED)) 
? "--ignored" : "",
+   path);
 
len = strbuf_read(&buf, cp.out, 1024);
if (len > 2)
@@ -1048,7 +1060,10 @@ int ok_to_remove_submodule(const char *path)
close(cp.out);
 
if (finish_command(&cp))
-   die(_("'git status --porcelain -u --ignore-submodules=none' 
failed in submodule %s"), path);
+   die(_("'git status --porcelain --ignore-submodules=none %s %s' 
failed in submodule '%s'"),
+   (flags & SUBMODULE_REMOVAL_IGNORE_UNTRACKED) ? "-uno" : 
"-uall",
+   (!(flags & SUBMODULE_REMOVAL_IGNORE_IGNORED_UNTRACKED)) 
? "--ignored" : "",
+   path);
 
strbuf_release(&buf);
return ok_to_remove;
diff --git a/submodule.h b/submodule.h
index 61fb610749..3ed3aa479a 100644
--- a/submodule.h
+++ b/submodule.h
@@ -59,7 +59,10 @@ extern int fetch_populated_submodules(const struct 
argv_array *options,
   int quiet, int max_parallel_jobs);
 extern unsigned is_submodule_modified(const char *path, int ignore_untracked);
 extern int submodule_uses_gitfile(const char *path);
-extern int ok_to_remove_submodule(const char *path);
+
+#define SUBMODULE_REMOVAL_IGNORE_UNTRACKED (1<<0)
+#define SUBMODULE_REMOVAL_IGNORE_IGNORED_UNTRACKED (1<<1)
+extern int ok_to_remove_submodule(const char *path, unsigned flags);
 extern int merge_submodule(unsigned char result[20], const char *path,
   const unsigned char base[20],
   const unsigned char a[20],
-- 
2.11.0.rc2.35.g26e18c9



[PATCHv2 5/5] rm: add absorb a submodules git dir before deletion

2016-12-13 Thread Stefan Beller
When deleting a submodule, we need to keep the actual git directory around,
such that we do not lose local changes in there and at a later checkout
of the submodule we don't need to clone it again.

Implement `depopulate_submodule`, that migrates the git directory before
deletion of a submodule and afterwards the equivalent of "rm -rf", which
is already found in entry.c, so expose that and for clarity add a suffix
"_or_die" to it.

Signed-off-by: Stefan Beller 
---
 builtin/rm.c  | 30 --
 cache.h   |  2 ++
 entry.c   |  5 +
 submodule.c   | 31 +++
 submodule.h   |  6 ++
 t/t3600-rm.sh | 39 +++
 6 files changed, 67 insertions(+), 46 deletions(-)

diff --git a/builtin/rm.c b/builtin/rm.c
index fdd7183f61..8c9c535a88 100644
--- a/builtin/rm.c
+++ b/builtin/rm.c
@@ -392,28 +392,14 @@ int cmd_rm(int argc, const char **argv, const char 
*prefix)
for (i = 0; i < list.nr; i++) {
const char *path = list.entry[i].name;
if (list.entry[i].is_submodule) {
-   if (is_empty_dir(path)) {
-   if (!rmdir(path)) {
-   removed = 1;
-   if 
(!remove_path_from_gitmodules(path))
-   gitmodules_modified = 1;
-   continue;
-   }
-   } else {
-   strbuf_reset(&buf);
-   strbuf_addstr(&buf, path);
-   if (!remove_dir_recursively(&buf, 0)) {
-   removed = 1;
-   if 
(!remove_path_from_gitmodules(path))
-   gitmodules_modified = 1;
-   strbuf_release(&buf);
-   continue;
-   } else if (!file_exists(path))
-   /* Submodule was removed by 
user */
-   if 
(!remove_path_from_gitmodules(path))
-   gitmodules_modified = 1;
-   /* Fallthrough and let remove_path() 
fail. */
-   }
+   if (is_empty_dir(path) && rmdir(path))
+   die_errno("git rm: '%s'", path);
+   if (file_exists(path))
+   depopulate_submodule(path);
+   removed = 1;
+   if (!remove_path_from_gitmodules(path))
+   gitmodules_modified = 1;
+   continue;
}
if (!remove_path(path)) {
removed = 1;
diff --git a/cache.h b/cache.h
index a50a61a197..b645ca2f9a 100644
--- a/cache.h
+++ b/cache.h
@@ -2018,4 +2018,6 @@ void sleep_millisec(int millisec);
  */
 void safe_create_dir(const char *dir, int share);
 
+extern void remove_directory_or_die(struct strbuf *path);
+
 #endif /* CACHE_H */
diff --git a/entry.c b/entry.c
index c6eea240b6..02c4ac9f22 100644
--- a/entry.c
+++ b/entry.c
@@ -73,6 +73,11 @@ static void remove_subtree(struct strbuf *path)
die_errno("cannot rmdir '%s'", path->buf);
 }
 
+void remove_directory_or_die(struct strbuf *path)
+{
+   remove_subtree(path);
+}
+
 static int create_file(const char *path, unsigned int mode)
 {
mode = (mode & 0100) ? 0777 : 0666;
diff --git a/submodule.c b/submodule.c
index e42efa2337..3770ecb7b9 100644
--- a/submodule.c
+++ b/submodule.c
@@ -308,6 +308,37 @@ static void print_submodule_summary(struct rev_info *rev, 
FILE *f,
strbuf_release(&sb);
 }
 
+void depopulate_submodule(const char *path)
+{
+   struct strbuf pathbuf = STRBUF_INIT;
+   char *dot_git = xstrfmt("%s/.git", path);
+
+   /* Is it populated? */
+   if (!resolve_gitdir(dot_git))
+   goto out;
+
+   /* Does it have a .git directory? */
+   if (!submodule_uses_gitfile(path)) {
+   absorb_git_dir_into_superproject("", path,
+   ABSORB_GITDIR_RECURSE_SUBMODULES);
+
+   if (!submodule_uses_gitfile(path)) {
+   /*
+* We should be using a gitfile by now. Let's double
+* check as losing the git dir would be fatal.
+*/
+   die("BUG: could not absorb git directory for '%s'", 
path);
+

[PATCHv2 4/5] ok_to_remove_submodule: absorb the submodule git dir

2016-12-13 Thread Stefan Beller
It is a major reason to say no, when deciding if a submodule can be
deleted, if the git directory of the submodule being contained in the
submodule's working directory.

Migrate the git directory into the superproject instead of failing,
and proceed with the other checks.

Signed-off-by: Stefan Beller 
---
 submodule.c | 15 +--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/submodule.c b/submodule.c
index 2d13744b06..e42efa2337 100644
--- a/submodule.c
+++ b/submodule.c
@@ -1026,11 +1026,22 @@ int ok_to_remove_submodule(const char *path, unsigned 
flags)
struct strbuf buf = STRBUF_INIT;
int ok_to_remove = 1;
 
+   /* Is it there? */
if (!file_exists(path) || is_empty_dir(path))
return 1;
 
-   if (!submodule_uses_gitfile(path))
-   return 0;
+   /* Does it have a .git directory? */
+   if (!submodule_uses_gitfile(path)) {
+   absorb_git_dir_into_superproject("", path,
+   ABSORB_GITDIR_RECURSE_SUBMODULES);
+
+   /*
+* We should be using a gitfile by now. Let's double
+* check as losing the git dir would be fatal.
+*/
+   if (!submodule_uses_gitfile(path))
+   return 0;
+   }
 
argv_array_pushl(&cp.args, "status", "--porcelain",
   "--ignore-submodules=none", NULL);
-- 
2.11.0.rc2.35.g26e18c9



[PATCHv2 2/5] submodule: modernize ok_to_remove_submodule to use argv_array

2016-12-13 Thread Stefan Beller
Instead of constructing the NULL terminated array ourselves, we
should make use of the argv_array infrastructure.

While at it, adapt the error messages to reflect the actual invocation.

Signed-off-by: Stefan Beller 
---
 submodule.c | 14 --
 1 file changed, 4 insertions(+), 10 deletions(-)

diff --git a/submodule.c b/submodule.c
index 45ccfb7ab4..9f0b544ebe 100644
--- a/submodule.c
+++ b/submodule.c
@@ -1023,13 +1023,6 @@ int ok_to_remove_submodule(const char *path)
 {
ssize_t len;
struct child_process cp = CHILD_PROCESS_INIT;
-   const char *argv[] = {
-   "status",
-   "--porcelain",
-   "-u",
-   "--ignore-submodules=none",
-   NULL,
-   };
struct strbuf buf = STRBUF_INIT;
int ok_to_remove = 1;
 
@@ -1039,14 +1032,15 @@ int ok_to_remove_submodule(const char *path)
if (!submodule_uses_gitfile(path))
return 0;
 
-   cp.argv = argv;
+   argv_array_pushl(&cp.args, "status", "--porcelain", "-u",
+  "--ignore-submodules=none", NULL);
prepare_submodule_repo_env(&cp.env_array);
cp.git_cmd = 1;
cp.no_stdin = 1;
cp.out = -1;
cp.dir = path;
if (start_command(&cp))
-   die("Could not run 'git status --porcelain -uall 
--ignore-submodules=none' in submodule %s", path);
+   die(_("could not run 'git status --porcelain -u 
--ignore-submodules=none' in submodule %s"), path);
 
len = strbuf_read(&buf, cp.out, 1024);
if (len > 2)
@@ -1054,7 +1048,7 @@ int ok_to_remove_submodule(const char *path)
close(cp.out);
 
if (finish_command(&cp))
-   die("'git status --porcelain -uall --ignore-submodules=none' 
failed in submodule %s", path);
+   die(_("'git status --porcelain -u --ignore-submodules=none' 
failed in submodule %s"), path);
 
strbuf_release(&buf);
return ok_to_remove;
-- 
2.11.0.rc2.35.g26e18c9



[PATCHv2 0/5] git-rm absorbs submodule git directory before deletion

2016-12-13 Thread Stefan Beller
v2:
* new base where to apply the patch:
  sb/submodule-embed-gitdir merged with sb/t3600-cleanup.
  I got merge conflicts and resolved them this way:
#@@@ -709,9 -687,10 +687,9 @@@ test_expect_success 'checking out a com
#  git commit -m "submodule removal" submod &&
#  git checkout HEAD^ &&
#  git submodule update &&
#- git checkout -q HEAD^ 2>actual &&
#+ git checkout -q HEAD^ &&
#  git checkout -q master 2>actual &&
# -echo "warning: unable to rmdir submod: Directory not empty" 
>expected &&
# -test_i18ncmp expected actual &&
# +test_i18ngrep "^warning: unable to rmdir submod:" actual &&
#  git status -s submod >actual &&
#  echo "?? submod/" >expected &&
#  test_cmp expected actual &&
#

* improved commit message in "ok_to_remove_submodule: absorb the submodule git 
dir"
  (David Turner offered me some advice on how to write better English off list)
* simplified code in last patch:
  -> dropped wrong comment for fallthrough
  -> moved redundant code out of both bodies of an if-clause.
* Fixed last patchs commit message to have "or_die" instead of or_dir.

v1:
The "checkout --recurse-submodules" series got too large to comfortably send
it out for review, so I had to break it up into smaller series'; this is the
first subseries, but it makes sense on its own.

This series teaches git-rm to absorb the git directory of a submodule instead
of failing and complaining about the git directory preventing deletion.

It applies on origin/sb/submodule-embed-gitdir.

Any feedback welcome!

Thanks,
Stefan

Stefan Beller (5):
  submodule.h: add extern keyword to functions
  submodule: modernize ok_to_remove_submodule to use argv_array
  submodule: add flags to ok_to_remove_submodule
  ok_to_remove_submodule: absorb the submodule git dir
  rm: add absorb a submodules git dir before deletion

 builtin/rm.c  | 33 -
 cache.h   |  2 ++
 entry.c   |  5 
 submodule.c   | 77 +--
 submodule.h   | 64 ++---
 t/t3600-rm.sh | 39 --
 6 files changed, 135 insertions(+), 85 deletions(-)

-- 
2.11.0.rc2.35.g26e18c9



[PATCHv2 1/5] submodule.h: add extern keyword to functions

2016-12-13 Thread Stefan Beller
As the upcoming series will add a lot of functions to the submodule
header, let's first make the header consistent to the rest of the project
by adding the extern keyword to functions.

As per the CodingGuidelines we try to stay below 80 characters per line,
so adapt all those functions to stay below 80 characters that are already
using more than one line.  Those function using just one line are better
kept in one line than breaking them up into multiple lines just for the
goal of staying below the character limit as it makes grepping
for functions easier if they are one liners.

Signed-off-by: Stefan Beller 
---
 submodule.h | 55 ++-
 1 file changed, 30 insertions(+), 25 deletions(-)

diff --git a/submodule.h b/submodule.h
index 6229054b99..61fb610749 100644
--- a/submodule.h
+++ b/submodule.h
@@ -29,50 +29,55 @@ struct submodule_update_strategy {
 };
 #define SUBMODULE_UPDATE_STRATEGY_INIT {SM_UPDATE_UNSPECIFIED, NULL}
 
-int is_staging_gitmodules_ok(void);
-int update_path_in_gitmodules(const char *oldpath, const char *newpath);
-int remove_path_from_gitmodules(const char *path);
-void stage_updated_gitmodules(void);
-void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,
+extern int is_staging_gitmodules_ok(void);
+extern int update_path_in_gitmodules(const char *oldpath, const char *newpath);
+extern int remove_path_from_gitmodules(const char *path);
+extern void stage_updated_gitmodules(void);
+extern void set_diffopt_flags_from_submodule_config(struct diff_options *,
const char *path);
-int submodule_config(const char *var, const char *value, void *cb);
-void gitmodules_config(void);
-int parse_submodule_update_strategy(const char *value,
+extern int submodule_config(const char *var, const char *value, void *cb);
+extern void gitmodules_config(void);
+extern int parse_submodule_update_strategy(const char *value,
struct submodule_update_strategy *dst);
-const char *submodule_strategy_to_string(const struct 
submodule_update_strategy *s);
-void handle_ignore_submodules_arg(struct diff_options *diffopt, const char *);
-void show_submodule_summary(FILE *f, const char *path,
+extern const char *submodule_strategy_to_string(const struct 
submodule_update_strategy *s);
+extern void handle_ignore_submodules_arg(struct diff_options *, const char *);
+extern void show_submodule_summary(FILE *f, const char *path,
const char *line_prefix,
struct object_id *one, struct object_id *two,
unsigned dirty_submodule, const char *meta,
const char *del, const char *add, const char *reset);
-void show_submodule_inline_diff(FILE *f, const char *path,
+extern void show_submodule_inline_diff(FILE *f, const char *path,
const char *line_prefix,
struct object_id *one, struct object_id *two,
unsigned dirty_submodule, const char *meta,
const char *del, const char *add, const char *reset,
const struct diff_options *opt);
-void set_config_fetch_recurse_submodules(int value);
-void check_for_new_submodule_commits(unsigned char new_sha1[20]);
-int fetch_populated_submodules(const struct argv_array *options,
+extern void set_config_fetch_recurse_submodules(int value);
+extern void check_for_new_submodule_commits(unsigned char new_sha1[20]);
+extern int fetch_populated_submodules(const struct argv_array *options,
   const char *prefix, int command_line_option,
   int quiet, int max_parallel_jobs);
-unsigned is_submodule_modified(const char *path, int ignore_untracked);
-int submodule_uses_gitfile(const char *path);
-int ok_to_remove_submodule(const char *path);
-int merge_submodule(unsigned char result[20], const char *path, const unsigned 
char base[20],
-   const unsigned char a[20], const unsigned char b[20], int 
search);
-int find_unpushed_submodules(unsigned char new_sha1[20], const char 
*remotes_name,
-   struct string_list *needs_pushing);
-int push_unpushed_submodules(unsigned char new_sha1[20], const char 
*remotes_name);
-int parallel_submodules(void);
+extern unsigned is_submodule_modified(const char *path, int ignore_untracked);
+extern int submodule_uses_gitfile(const char *path);
+extern int ok_to_remove_submodule(const char *path);
+extern int merge_submodule(unsigned char result[20], const char *path,
+  const unsigned char base[20],
+  const unsigned char a[20],
+  const unsigned char b[20], int search);
+extern int find_unpushed_submodules(unsigned char new_sha1[20],
+   const char *remotes_name,
+   struct string_list *needs_pushing);
+extern int push_unpushed_submodules(unsigned char new_sha1[20],
+   const char *remotes_na

Re: [PATCH v2 01/34] sequencer: support a new action: 'interactive rebase'

2016-12-13 Thread Junio C Hamano
Johannes Schindelin  writes:

>  static inline int is_rebase_i(const struct replay_opts *opts)
>  {
> - return 0;
> + return opts->action == REPLAY_INTERACTIVE_REBASE;
>  }
>  
>  static const char *get_dir(const struct replay_opts *opts)
>  {
> + if (is_rebase_i(opts))
> + return rebase_path();
>   return git_path_seq_dir();
>  }
>  
>  static const char *get_todo_path(const struct replay_opts *opts)
>  {
> + if (is_rebase_i(opts))
> + return rebase_path_todo();
>   return git_path_todo_file();
>  }
>  
> @@ -168,7 +179,15 @@ int sequencer_remove_state(struct replay_opts *opts)
>  
>  static const char *action_name(const struct replay_opts *opts)
>  {
> - return opts->action == REPLAY_REVERT ? N_("revert") : N_("cherry-pick");
> + switch (opts->action) {
> + case REPLAY_REVERT:
> + return N_("revert");
> + case REPLAY_PICK:
> + return N_("cherry-pick");
> + case REPLAY_INTERACTIVE_REBASE:
> + return N_("rebase -i");
> + }
> + die(_("Unknown action: %d"), opts->action);
>  }

This case statement which looks perfectly sensible---it says that
there are three equal modes the subsystem operates in.  

This is just a mental note and not a suggestion to change anything
immediately, but it makes me wonder if git_dir/get_todo_path would
also want to do so, moving towards retiring is_rebase_i() which is
"everything else vs one oddball which is rebase-i" mindset.

> @@ -395,7 +414,10 @@ static int do_recursive_merge(struct commit *base, 
> struct commit *next,
>  
>   if (active_cache_changed &&
>   write_locked_index(&the_index, &index_lock, COMMIT_LOCK))
> - /* TRANSLATORS: %s will be "revert" or "cherry-pick" */
> + /*
> +  * TRANSLATORS: %s will be "revert", "cherry-pick" or
> +  * "rebase -i".
> +  */

IIRC, the "TRANSLATORS:" comment has to deviate from our coding
style due to tool limitation and has to be done like this:

> + /* TRANSLATORS: %s will be "revert", "cherry-pick" or
> +  * "rebase -i".
> +  */

> @@ -1204,6 +1226,9 @@ static int save_todo(struct todo_list *todo_list, 
> struct replay_opts *opts)
>   const char *todo_path = get_todo_path(opts);
>   int next = todo_list->current, offset, fd;
>  
> + if (is_rebase_i(opts))
> + next++;
> +

This is because...?  Everybody else counts 0-based while rebase-i
counts from 1 or something?

>   fd = hold_lock_file_for_update(&todo_lock, todo_path, 0);
>   if (fd < 0)
>   return error_errno(_("could not lock '%s'"), todo_path);

Everything else in the patch is understandable.  This bit isn't
without explanation, at least to me.


Re: [PATCH v2 02/34] sequencer (rebase -i): implement the 'noop' command

2016-12-13 Thread Junio C Hamano
Johannes Schindelin  writes:

> +/*
> + * Note that ordering matters in this enum. Not only must it match the 
> mapping
> + * below, it is also divided into several sections that matter.  When adding
> + * new commands, make sure you add it in the right section.
> + */

Good thinking.  Makes me wish C were a better language, though ;-)

>  enum todo_command {
> + /* commands that handle commits */
>   TODO_PICK = 0,
> - TODO_REVERT
> + TODO_REVERT,
> + /* commands that do nothing but are counted for reporting progress */
> + TODO_NOOP
>  };
>  
>  static const char *todo_command_strings[] = {
>   "pick",
> - "revert"
> + "revert",
> + "noop"
>  };

> @@ -1292,7 +1316,12 @@ static int pick_commits(struct todo_list *todo_list, 
> struct replay_opts *opts)
>   struct todo_item *item = todo_list->items + todo_list->current;
>   if (save_todo(todo_list, opts))
>   return -1;
> - res = do_pick_commit(item->command, item->commit, opts);
> + if (item->command <= TODO_REVERT)
> + res = do_pick_commit(item->command, item->commit,
> + opts);
> + else if (item->command != TODO_NOOP)
> + return error(_("unknown command %d"), item->command);

I wonder if making this a switch() statement is easier to read in
the longer run.  The only thing at this point we are gaining by "not
only mapping and enum must match, the orders matter" is so that this
codepath can do the same thing for PICK and REVERT, but these two
would become more and more minority as we learn more words.

>   todo_list->current++;
>   if (res)
>   return res;


Re: [PATCH 0/6] git-rm absorbs submodule git directory before deletion

2016-12-13 Thread Stefan Beller
On Tue, Dec 13, 2016 at 12:09 PM, Stefan Beller  wrote:
>
> So I will reroll it with "absorb" fixing some nits pointed out by David?

I got confused there, Davids nits are for this series, the absorb series itself
doesn't seem to have nits.

So I'll just reroll this series on top of the currently
sb/submodule-embed-gitdir (which you originally noted to be better renamed to
submodule-absorb-gitdir) merged with t3600-cleanup.

Thanks,
Stefan


Re: [PATCH 2/2] tmp-objdir: quote paths we add to alternates

2016-12-13 Thread Junio C Hamano
Jeff King  writes:

> On Tue, Dec 13, 2016 at 10:10:04AM -0800, Junio C Hamano wrote:
>
>> > -  git clone --bare . xxx:yyy.git &&
>> > +  git clone --bare . xxx${path_sep}yyy.git &&
>> 
>> Don't you want to dq the whole thing to prevent the shell from
>> splitting this into two commands at ';'?  The other one below is OK.
>
> After expansion, I don't think the shell will do any further processing
> except for whitespace splitting. E.g.:

Ah, my mistake.  Staring at too many `eval`s does it to me.

Thanks.


Re: [PATCH 0/6] git-rm absorbs submodule git directory before deletion

2016-12-13 Thread Stefan Beller
On Tue, Dec 13, 2016 at 11:47 AM, Junio C Hamano  wrote:
> Stefan Beller  writes:
>
>> The desired standard for submodules is to have the git dir inside the
>> superprojects git dir (since  501770e, Aug 2011, Move git-dir for
>> submodules), which is why I think an "embedded submodule git dir"
>> is inside the superproject already.
>
> Think how you start a new submodule.  What are the steps you take
> before you say "git submodule add"?  And where does .git for the
> submodule live at that point?

Well there is no way to directly start a submodule
(e.g. "git submodule create"), such that there has to be one repo
that actually has the git dir inside the working tree.

If the submodule exists already somewhere, there are 2 ways to do it
("git submodule add "  or "git clone && git submodule add")
which lead to different outcomes, where the .git resides.

> With the current system, you as the submodule originator need to do
> something different to make your working tree of the superproject
> match what the others who clone from your public repository.
>
> And comparing the two layout, the one originally held by the
> submodule originator has .git embedded in the working tree, no?

When starting a new submodule repo, yes, the git dir is inside
the working tree.

> All of the above is coming from "submodule" centric mindset.  It
> just is not centric to those who follow what others originated.

ok.

> Another reason why I personally see a .git in each submodule working
> tree is "embedded" has nothing to do with Git.  It is an analogy I
> feel (perhaps it is just me) with the word "embedded reporters in
> warzone".  These people are spread around, assigned to units to
> report from places closer to the front line and being closer to the
> leaf of the hierarchy, as opposed to be assigned to a more central
> place like HQ to do their reporting.

I talked to people in the office and got a heavy rejection on the
the work "embedded" here for another reason:

"Does it put the submodule on an embedded device?
What does embedded even mean?
The end user is super confused"

So I think we should not use embed or un-embed one way or the other.
Instead we need to have another name.

I think absorb is ok-ish, as "git submodule absorb" hints that the
superproject absorbs something from the submodule.

So I will reroll it with "absorb" fixing some nits pointed out by David?


Re: [RFC/PATCH v3 00/16] Add initial experimental external ODB support

2016-12-13 Thread Junio C Hamano
Christian Couder  writes:

> In general I think that having a lot of refs is really a big problem
> right now in Git as many big organizations using Git are facing this
> problem in one form or another.
> So I think that support for a big number of refs is a separate and
> important problem that should and hopefully will be solved.

But you do not have to make it worse.

Is "refs" a good match for the problem you are solving?  Or is it
merely an expedient thing to use?  I think it is the latter, judging
by your mentioning RefTree.  Whatever mechanism we choose, that will
be carved into stone in users' repositories and you'd end up having
to support it, and devise the migration path out of it if the initial
selection is too problematic.

That is why people (not just me) pointed out upfront that using refs
for this purose would not scale.


Re: git add -p with unmerged files

2016-12-13 Thread Junio C Hamano
Stephan Beyer  writes:

> While we're on the topic that "git add -p" should behave like the
> "normal" "git add" (not "git add -u"): what about unmerged changes?
>
>
> When I have merge conflicts, I almost always use my aliases
> "edit-unmerged" and "add-unmerged":
>
> $ git config --global --list | grep unmerged
> alias.list-unmerged=diff --name-only --diff-filter=U
> alias.edit-unmerged=!vim `git list-unmerged`
> alias.add-unmerged=!git add `git list-unmerged`
> alias.reset-unmerged=!uf=`git list-unmerged`; git reset HEAD $uf; git
> checkout -- $uf
>
> The "add-unmerged" alias is always a little scary because I'd rather
> like to check the changes with the "git add -p" workflow I am used to.
>
> Opinions?

For this, you would NEVER want to use "add -p" to pick and choose.
By definition, while you are in conflicted merge, the path that had
conflicts before you started the merge-y operation (be it "pull",
"am -3", or "cherry-pick") did not have any change since HEAD, and
"pick this hunk, drop that hunk" cannot be correct for the conflict
resolution.

"git diff" while conflicted will highlight what conflicted by
showing the three-way diff (similar to "diff --cc" on a merge
result) and after conflict is resolved you can view "diff HEAD"
on the path to see what the merge brought in.


Re: [PATCH 0/6] git-rm absorbs submodule git directory before deletion

2016-12-13 Thread Junio C Hamano
Stefan Beller  writes:

> I guess the latter is the case, so embedding is actually inside
> the working tree and un-embedding is the relocation to the
> superproject.

Another reason why I personally see a .git in each submodule working
tree is "embedded" has nothing to do with Git.  It is an analogy I
feel (perhaps it is just me) with the word "embedded reporters in
warzone".  These people are spread around, assigned to units to
report from places closer to the front line and being closer to the
leaf of the hierarchy, as opposed to be assigned to a more central
place like HQ to do their reporting.


Re: git add -p with unmerged files (was: git add -p with new file)

2016-12-13 Thread Jeff King
On Tue, Dec 13, 2016 at 08:21:59PM +0100, Stephan Beyer wrote:

> While we're on the topic that "git add -p" should behave like the
> "normal" "git add" (not "git add -u"): what about unmerged changes?

I agree that's a related part of the workflow, though the implementation
is a bit harder.

> When I have merge conflicts, I almost always use my aliases
> "edit-unmerged" and "add-unmerged":
> 
> $ git config --global --list | grep unmerged
> alias.list-unmerged=diff --name-only --diff-filter=U
> alias.edit-unmerged=!vim `git list-unmerged`

You might like contrib/git-jump for that, which makes it easier to go to
the specific spots within files.

When "git jump merge" produces no hits, I know I've dealt with all of
the conflicts (textual ones, anyway). I do often want to run "git add
-p" then to review the changes before staging.

I think what is most helpful there is probably "git diff HEAD" to see
what the merge is bringing in (or the cherry-pick, or "am", or
whatever). If I wanted "add -p" to do anything, I think it would be to
act as if stage 2 ("ours", which should be the same as what is in HEAD)
was already in the index. I.e., show the diff against that, apply any
hunks we select, and store the whole thing as stage 0, losing the
unmerged bit.

When you select all hunks, this is equivalent to "git add unmerge-file".
If you choose only a subset of hunks, it leaves the unselected ones for
you to examine later via "git diff". And if you choose none, it should
probably leave unmerged.

That's just a scheme I thought up, though. I've never actually tried it
in practice.

-Peff


Re: [PATCH 0/6] git-rm absorbs submodule git directory before deletion

2016-12-13 Thread Junio C Hamano
Stefan Beller  writes:

> The desired standard for submodules is to have the git dir inside the
> superprojects git dir (since  501770e, Aug 2011, Move git-dir for
> submodules), which is why I think an "embedded submodule git dir"
> is inside the superproject already.

Think how you start a new submodule.  What are the steps you take
before you say "git submodule add"?  And where does .git for the
submodule live at that point?

With the current system, you as the submodule originator need to do
something different to make your working tree of the superproject
match what the others who clone from your public repository.

And comparing the two layout, the one originally held by the
submodule originator has .git embedded in the working tree, no?

All of the above is coming from "submodule" centric mindset.  It
just is not centric to those who follow what others originated.


Re: [PATCH 0/6] git-rm absorbs submodule git directory before deletion

2016-12-13 Thread Stefan Beller
On Tue, Dec 13, 2016 at 11:11 AM, Junio C Hamano  wrote:
> Stefan Beller  writes:
>
>>> I do not think there is no dispute about what embedding means.
>>
>> double negative: You think we have a slight dispute here.
>
> Sorry, I do not think there is any dispute on that.
>
>>>  A
>>> submodule whose .git is inside its working tree has its repository
>>> embedded.
>>>
>>> What we had trouble settling on was what to call the operation to
>>> undo the embedding, unentangling its repository out of the working
>>> tree.  I'd still vote for unembed if you want a name to be nominated.
>>
>> So I can redo the series with two commands "git submodule [un]embed".
>>
>> For me "unembed" == "absorb", such that we could also go with
>> absorb into superproject <-> embed into worktree
>
> With us agreeing that "embed" is about something is _IN_ submodule
> working tree, unembed would naturally be something becomes OUTSIDE
> the same thing (i.e. "submodule working tree").  However, if you
> introduce "absorb", we suddenly need to talk about a different
> thing, i.e. "superproject's .git/modules", that is doing the
> absorption.  That is why I suggest "unembed" over "absorb".

ok, I will take unembed then.  We could also go with more command line options
such as "embed --reverse" or such, but that is not as nice I'd think.


Re: [PATCH v2 00/34] Teach the sequencer to act as rebase -i's backend

2016-12-13 Thread Junio C Hamano
Johannes Schindelin  writes:

> This marks the count down to '3': two more patch series after this
> (really tiny ones) and we have a faster rebase -i.

Nice.

> Apart from mostly cosmetic patches (and the occasional odd bug that I
> fixed promptly), I used these patches since mid May to perform all of my
> interactive rebases. In mid June, I had the idea to teach rebase -i to
> run *both* scripted rebase and rebase--helper and to cross-validate the
> results. This slowed down all my interactive rebases since, but helped
> me catch three rather obscure bugs (e.g. that git commit --fixup unfolds
> long onelines and rebase -i still finds the correct original commit).
> ...
> Please note that the interdiff vs v1 is only of limited use: too many
> things changed in the meantime, in particular the prepare-sequencer
> branch that went through a couple of iterations before it found its way
> into git.git's master branch. So please take the interdiff with a
> mountain range of salt.
> ...
> Changes since v1:
> ...
> - removed the beautiful ordinal logic (to print out "1st", "2nd", "3rd"
>   etc) and made things consistent with the current `rebase -i`.

It was removed because it was too Anglo-centric and unusable in i18n
context, no?

Judging from the list above, interdiff are pretty much all cosmetic
and that is why you say it is only of limited use, I guess.

... goes and reads the remainder and finds that these were
... all minor changes, mostly cosmetic, with a helper function
... refactored out or two and things of that nature.

It is actually a good thing.  We do not want to see it deviate too
drastically from what you have been testing for some months.

Thanks.


Re: [PATCH 0/6] git-rm absorbs submodule git directory before deletion

2016-12-13 Thread Stefan Beller
On Tue, Dec 13, 2016 at 11:13 AM, Stefan Beller  wrote:
> On Tue, Dec 13, 2016 at 11:11 AM, Junio C Hamano  wrote:
>> Stefan Beller  writes:
>>
 I do not think there is no dispute about what embedding means.
>>>
>>> double negative: You think we have a slight dispute here.
>>
>> Sorry, I do not think there is any dispute on that.
>>
  A
 submodule whose .git is inside its working tree has its repository
 embedded.

 What we had trouble settling on was what to call the operation to
 undo the embedding, unentangling its repository out of the working
 tree.  I'd still vote for unembed if you want a name to be nominated.
>>>
>>> So I can redo the series with two commands "git submodule [un]embed".
>>>
>>> For me "unembed" == "absorb", such that we could also go with
>>> absorb into superproject <-> embed into worktree
>>
>> With us agreeing that "embed" is about something is _IN_ submodule
>> working tree, unembed would naturally be something becomes OUTSIDE
>> the same thing (i.e. "submodule working tree").

I do not agree, yet.
So I thought about this for a while.

The standard in Git is to have the .git directory inside the working tree,
which is why you are convinced that embedded means the .git is in the
working tree, because you approach this discussion as the Git maintainer,
spending only little time on submodule related stuff.

The desired standard for submodules is to have the git dir inside the
superprojects git dir (since  501770e, Aug 2011, Move git-dir for
submodules), which is why I think an "embedded submodule git dir"
is inside the superproject already.

I think both views are legit, and we would want to choose the one that
users find most intuitive (and I think there will be users that find either
viewpoint intuitive).

So when you have typed "git submodule ", I wonder if a user would
assume a submodule-centric mindset of how submodules ought to
work or if they still look at a submodule as its own git repo
that just happens to be embedded into the superproject.

I guess the latter is the case, so embedding is actually inside the working
tree and un-embedding is the relocation to the superproject.


git add -p with unmerged files (was: git add -p with new file)

2016-12-13 Thread Stephan Beyer
Hi,

While we're on the topic that "git add -p" should behave like the
"normal" "git add" (not "git add -u"): what about unmerged changes?

When I have merge conflicts, I almost always use my aliases
"edit-unmerged" and "add-unmerged":

$ git config --global --list | grep unmerged
alias.list-unmerged=diff --name-only --diff-filter=U
alias.edit-unmerged=!vim `git list-unmerged`
alias.add-unmerged=!git add `git list-unmerged`
alias.reset-unmerged=!uf=`git list-unmerged`; git reset HEAD $uf; git
checkout -- $uf

The "add-unmerged" alias is always a little scary because I'd rather
like to check the changes with the "git add -p" workflow I am used to.

Opinions?

Best
  Stephan


Re: What's cooking in git.git (Dec 2016, #02; Mon, 12)

2016-12-13 Thread Junio C Hamano
Johannes Schindelin  writes:

> ok 13 - grep tree and more pathspecs
>
> expecting success: 
>   git init parent &&
>   test_when_finished "rm -rf parent" &&
>   echo "foobar" >"parent/fi:le" &&
>   git -C parent add "fi:le" &&
>   git -C parent commit -m "add fi:le" &&
> ...
>   test_cmp expect actual
>
> ++ git init parent
> Initialized empty Git repository in C:/git-sdk-64/usr/src/git/wip3/t/trash
> directory.t7814-grep-recurse-submodules/parent/.git/
> ++ test_when_finished 'rm -rf parent'
> ++ test 0 = 0
> ++ test_cleanup='{ rm -rf parent
>   } && (exit "$eval_ret"); eval_ret=$?; :'
> ++ echo foobar
> ++ git -C parent add fi:le
> fatal: pathspec 'fi:le' did not match any files

I think !MINGW prereq is missing?



Re: [PATCH 3/2] t5547-push-quarantine: run the path separator test on Windows, too

2016-12-13 Thread Junio C Hamano
Johannes Sixt  writes:

> To perform the test case on Windows in a way that corresponds to the
> POSIX version, inject the semicolon in a directory name.
>
> Typically, an absolute POSIX style path, such as the one in $PWD, is
> translated into a Windows style path by bash when it invokes git.exe.
> However, the presence of the semicolon suppresses this translation;
> but the untranslated POSIX style path is useless for git.exe.
> Therefore, instead of $PWD pass the Windows style path that $(pwd)
> produces.
>
> Signed-off-by: Johannes Sixt 
> ---
> Am 12.12.2016 um 20:53 schrieb Jeff King:
>> Johannes, please let me know if I am wrong about skipping the test on
>> !MINGW. The appropriate check there would be ";" anyway, but I am not
>> sure _that_ is allowed in paths, either.
>
> Here is a version for Windows. I'd prefer this patch on top instead
> of squashing it into yours to keep the $PWD vs. $(pwd) explanation.
>
> The result is the same as yours in all practical matters; but this
> version I have already tested.

Will queue (I would wait for peff@ to say "OK", but I suspect he
would be OK in this case).

Thanks.


>  t/t5547-push-quarantine.sh | 14 ++
>  1 file changed, 10 insertions(+), 4 deletions(-)
>
> diff --git a/t/t5547-push-quarantine.sh b/t/t5547-push-quarantine.sh
> index 6275ec807b..af9fcd833a 100755
> --- a/t/t5547-push-quarantine.sh
> +++ b/t/t5547-push-quarantine.sh
> @@ -33,8 +33,7 @@ test_expect_success 'rejected objects are removed' '
>   test_cmp expect actual
>  '
>  
> -# MINGW does not allow colons in pathnames in the first place
> -test_expect_success !MINGW 'push to repo path with colon' '
> +test_expect_success 'push to repo path with path separator (colon)' '
>   # The interesting failure case here is when the
>   # receiving end cannot access its original object directory,
>   # so make it likely for us to generate a delta by having
> @@ -43,13 +42,20 @@ test_expect_success !MINGW 'push to repo path with colon' 
> '
>   test-genrandom foo 4096 >file.bin &&
>   git add file.bin &&
>   git commit -m bin &&
> - git clone --bare . xxx:yyy.git &&
> +
> + if test_have_prereq MINGW
> + then
> + pathsep=";"
> + else
> + pathsep=":"
> + fi &&
> + git clone --bare . "xxx${pathsep}yyy.git" &&
>  
>   echo change >>file.bin &&
>   git commit -am change &&
>   # Note that we have to use the full path here, or it gets confused
>   # with the ssh host:path syntax.
> - git push "$PWD/xxx:yyy.git" HEAD
> + git push "$(pwd)/xxx${pathsep}yyy.git" HEAD
>  '
>  
>  test_done


Re: What's cooking in git.git (Dec 2016, #02; Mon, 12)

2016-12-13 Thread Johannes Schindelin
Hi Junio,

On Mon, 12 Dec 2016, Junio C Hamano wrote:

> * bw/grep-recurse-submodules (2016-11-22) 6 commits
>  - grep: search history of moved submodules
>  - grep: enable recurse-submodules to work on  objects
>  - grep: optionally recurse into submodules
>  - grep: add submodules as a grep source type
>  - submodules: load gitmodules file from commit sha1
>  - submodules: add helper functions to determine presence of submodules
> 
>  "git grep" learns to optionally recurse into submodules
> 
>  Has anybody else seen t7814 being flakey with this series?

It is not flakey for me, it fails consistently on Windows. This is the
output with -i -v -x (sorry, I won't have time this week to do anything
about it, but maybe it helps identify the root cause):

-- snipsnap --
Initialized empty Git repository in C:/git-sdk-64/usr/src/git/wip3/t/trash
directory.t7814-grep-recurse-submodules/.git/
expecting success: 
echo "foobar" >a &&
mkdir b &&
echo "bar" >b/b &&
git add a b &&
git commit -m "add a and b" &&
git init submodule &&
echo "foobar" >submodule/a &&
git -C submodule add a &&
git -C submodule commit -m "add a" &&
git submodule add ./submodule &&
git commit -m "added submodule"

++ echo foobar
++ mkdir b
++ echo bar
++ git add a b
++ git commit -m 'add a and b'
[master (root-commit) 6a17548] add a and b
 Author: A U Thor 
 2 files changed, 2 insertions(+)
 create mode 100644 a
 create mode 100644 b/b
++ git init submodule
Initialized empty Git repository in C:/git-sdk-64/usr/src/git/wip3/t/trash
directory.t7814-grep-recurse-submodules/submodule/.git/
++ echo foobar
++ git -C submodule add a
++ git -C submodule commit -m 'add a'
[master (root-commit) 081a998] add a
 Author: A U Thor 
 1 file changed, 1 insertion(+)
 create mode 100644 a
++ git submodule add ./submodule
Adding existing repo at 'submodule' to the index
++ git commit -m 'added submodule'
[master 0c0fdd0] added submodule
 Author: A U Thor 
 2 files changed, 4 insertions(+)
 create mode 100644 .gitmodules
 create mode 16 submodule
+ test_eval_ret_=0
+ want_trace
+ test t = t
+ test t = t
+ set +x
ok 1 - setup directory structure and submodule

expecting success: 
cat >expect <<-\EOF &&
a:foobar
b/b:bar
submodule/a:foobar
EOF

git grep -e "bar" --recurse-submodules >actual &&
test_cmp expect actual

++ cat
++ git grep -e bar --recurse-submodules
++ test_cmp expect actual
++ mingw_test_cmp expect actual
++ local test_cmp_a= test_cmp_b=
++ local stdin_for_diff=
++ test -s expect
++ test -s actual
++ mingw_read_file_strip_cr_ test_cmp_a
++ local line
++ :
++ IFS=$'\r'
++ read -r -d '
' line
++ line='a:foobar
'
++ eval 'test_cmp_a=$test_cmp_a$line'
+++ test_cmp_a='a:foobar
'
++ :
++ IFS=$'\r'
++ read -r -d '
' line
++ line='b/b:bar
'
++ eval 'test_cmp_a=$test_cmp_a$line'
+++ test_cmp_a='a:foobar
b/b:bar
'
++ :
++ IFS=$'\r'
++ read -r -d '
' line
++ line='submodule/a:foobar
'
++ eval 'test_cmp_a=$test_cmp_a$line'
+++ test_cmp_a='a:foobar
b/b:bar
submodule/a:foobar
'
++ :
++ IFS=$'\r'
++ read -r -d '
' line
++ test -z ''
++ break
++ mingw_read_file_strip_cr_ test_cmp_b
++ local line
++ :
++ IFS=$'\r'
++ read -r -d '
' line
++ line='a:foobar
'
++ eval 'test_cmp_b=$test_cmp_b$line'
+++ test_cmp_b='a:foobar
'
++ :
++ IFS=$'\r'
++ read -r -d '
' line
++ line='b/b:bar
'
++ eval 'test_cmp_b=$test_cmp_b$line'
+++ test_cmp_b='a:foobar
b/b:bar
'
++ :
++ IFS=$'\r'
++ read -r -d '
' line
++ line='submodule/a:foobar
'
++ eval 'test_cmp_b=$test_cmp_b$line'
+++ test_cmp_b='a:foobar
b/b:bar
submodule/a:foobar
'
++ :
++ IFS=$'\r'
++ read -r -d '
' line
++ test -z ''
++ break
++ test -n 'a:foobar
b/b:bar
submodule/a:foobar
'
++ test -n 'a:foobar
b/b:bar
submodule/a:foobar
'
++ test 'a:foobar
b/b:bar
submodule/a:foobar
' = 'a:foobar
b/b:bar
submodule/a:foobar
'
+ test_eval_ret_=0
+ want_trace
+ test t = t
+ test t = t
+ set +x
ok 2 - grep correctly finds patterns in a submodule

expecting success: 
cat >expect <<-\EOF &&
submodule/a:foobar
EOF

git grep -e. --recurse-submodules -- submodule >actual &&
test_cmp expect actual

++ cat
++ git grep -e. --recurse-submodules -- submodule
++ test_cmp expect actual
++ mingw_test_cmp expect actual
++ local test_cmp_a= test_cmp_b=
++ local stdin_for_diff=
++ test -s expect
++ test -s actual
++ mingw_read_file_strip_cr_ test_cmp_a
++ local line
++ :
++ IFS=$'\r'
++ read -r -d '
' line
++ line='submodule/a:foobar
'
++ eval 'test_cmp_a=$test_cmp_a$line'
+++ test_cmp_a='submodule/a:foobar
'
++ :
++ IFS=$'\r'
++ read -r -d '
' line
++ test -z ''
++ break
++ mingw_read_file_strip_cr_ test_cmp_b
++ local line
++ :
++ IFS=$'\r'
++ read -r -d '
' line
++ line='submodule/a:foobar
'
++ eval 'test_cmp_b=$test_cmp_b$line'
+++ test_cmp_b='submodule/a:foobar
'
++ :
++ IFS=$'\r'
++ read -r -d '
' line
++ test -z ''
++ break
++ test -n 'submodule/a:foobar
'
++ test

Re: [PATCH 3/2] t5547-push-quarantine: run the path separator test on Windows, too

2016-12-13 Thread Jeff King
On Tue, Dec 13, 2016 at 08:09:31PM +0100, Johannes Sixt wrote:

> Am 12.12.2016 um 20:53 schrieb Jeff King:
> > Johannes, please let me know if I am wrong about skipping the test on
> > !MINGW. The appropriate check there would be ";" anyway, but I am not
> > sure _that_ is allowed in paths, either.
> 
> Here is a version for Windows. I'd prefer this patch on top instead
> of squashing it into yours to keep the $PWD vs. $(pwd) explanation.
> 
> The result is the same as yours in all practical matters; but this
> version I have already tested.

Yeah, I'm happy to have this on top. The patch itself looks obviously
correct. Thanks!

-Peff


Re: git add -p with new file

2016-12-13 Thread Junio C Hamano
Jeff King  writes:

>> Perhaps the latter is not advertised well enough?  "add -p" does not
>> even page so it is not very useful way to check what is being added
>> if you are adding a new file (unless you are doing a toy example to
>> add a 7-line file).
>
> I use "add -p" routinely for my final add-and-sanity-check,...
> ... To me they are all tools in the toolbox, and I can pick the one that
> works best in any given situation, or that I just feel like using that
> day.

Oh, there is no question about that.  I was just pointing out that
"add -p" is not the "one that works best" when dealing with a path
that is not yet even in the index.


Re: [PATCH 0/6] git-rm absorbs submodule git directory before deletion

2016-12-13 Thread Junio C Hamano
Stefan Beller  writes:

>> I do not think there is no dispute about what embedding means.
>
> double negative: You think we have a slight dispute here.

Sorry, I do not think there is any dispute on that.

>>  A
>> submodule whose .git is inside its working tree has its repository
>> embedded.
>>
>> What we had trouble settling on was what to call the operation to
>> undo the embedding, unentangling its repository out of the working
>> tree.  I'd still vote for unembed if you want a name to be nominated.
>
> So I can redo the series with two commands "git submodule [un]embed".
>
> For me "unembed" == "absorb", such that we could also go with
> absorb into superproject <-> embed into worktree

With us agreeing that "embed" is about something is _IN_ submodule
working tree, unembed would naturally be something becomes OUTSIDE
the same thing (i.e. "submodule working tree").  However, if you
introduce "absorb", we suddenly need to talk about a different
thing, i.e. "superproject's .git/modules", that is doing the
absorption.  That is why I suggest "unembed" over "absorb".


Re: [PATCH] builtin/commit.c: convert trivial snprintf calls to xsnprintf

2016-12-13 Thread Jeff King
On Tue, Dec 13, 2016 at 11:03:53AM -0800, Junio C Hamano wrote:

> >> @@ -1525,12 +1526,10 @@ static int git_commit_config(const char *k, const 
> >> char *v, void *cb)
> >>  static int run_rewrite_hook(const unsigned char *oldsha1,
> >>const unsigned char *newsha1)
> >>  {
> >> -  /* oldsha1 SP newsha1 LF NUL */
> >> -  static char buf[2*40 + 3];
> >> +  char *buf;
> >>struct child_process proc = CHILD_PROCESS_INIT;
> >>const char *argv[3];
> >>int code;
> >> -  size_t n;
> >>  
> >>argv[0] = find_hook("post-rewrite");
> >>if (!argv[0])
> >> @@ -1546,34 +1545,33 @@ static int run_rewrite_hook(const unsigned char 
> >> *oldsha1,
> >>code = start_command(&proc);
> >>if (code)
> >>return code;
> >> -  n = snprintf(buf, sizeof(buf), "%s %s\n",
> >> -   sha1_to_hex(oldsha1), sha1_to_hex(newsha1));
> >> +  buf = xstrfmt("%s %s\n", sha1_to_hex(oldsha1), sha1_to_hex(newsha1));
> >>sigchain_push(SIGPIPE, SIG_IGN);
> >> -  write_in_full(proc.in, buf, n);
> >> +  write_in_full(proc.in, buf, strlen(buf));
> >>close(proc.in);
> >> +  free(buf);
> >
> > Any time you care about the length of the result, I'd generally use an
> > actual strbuf instead of xstrfmt. The extra strlen isn't a big deal
> > here, but it somehow seems simpler to me. It probably doesn't matter
> > much either way, though.
> 
> Your justification for this extra allocation was that it is a
> heavy-weight operation.  While I agree that the runtime cost of
> allocation and deallocation does not matter, I would be a bit
> worried about extra cognitive burden to programmers.  They did not
> have to worry about leaking because they are writing a fixed length
> string.  Now they do, whether they use xstrfmt() or struct strbuf.
> When they need to update what they write, they do have to remember
> to adjust the size of the "fixed string", and the original is not
> free from the "programmers' cognitive cost" point of view, of
> course.  Probably use of strbuf/xstrfmt is an overall win.

So I think you are agreeing, but I have a minor nit to pick. :)

The fact that the extra allocation will not hurt performance is
_necessary_, but not _sufficient_. So it's not a justification in
itself, only something we have to check before proceeding.

The only justification here is that magic numbers like "2*40 + 3" are
confusing and a potential maintenance burden. And that's why I suggested
splitting this one out from the other two (whose justification is
"PATH_MAX is sometimes too small").

I agree with you that it's a tradeoff between "magic numbers" versus
"having to free resources". In my opinion it's a net improvement, but I
think it would also be reasonable to switch to xsnprintf() here. Then
the programmer has an automatic check that the buffer size is
sufficient.

-Peff


[PATCH 3/2] t5547-push-quarantine: run the path separator test on Windows, too

2016-12-13 Thread Johannes Sixt
To perform the test case on Windows in a way that corresponds to the
POSIX version, inject the semicolon in a directory name.

Typically, an absolute POSIX style path, such as the one in $PWD, is
translated into a Windows style path by bash when it invokes git.exe.
However, the presence of the semicolon suppresses this translation;
but the untranslated POSIX style path is useless for git.exe.
Therefore, instead of $PWD pass the Windows style path that $(pwd)
produces.

Signed-off-by: Johannes Sixt 
---
Am 12.12.2016 um 20:53 schrieb Jeff King:
> Johannes, please let me know if I am wrong about skipping the test on
> !MINGW. The appropriate check there would be ";" anyway, but I am not
> sure _that_ is allowed in paths, either.

Here is a version for Windows. I'd prefer this patch on top instead
of squashing it into yours to keep the $PWD vs. $(pwd) explanation.

The result is the same as yours in all practical matters; but this
version I have already tested.

 t/t5547-push-quarantine.sh | 14 ++
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/t/t5547-push-quarantine.sh b/t/t5547-push-quarantine.sh
index 6275ec807b..af9fcd833a 100755
--- a/t/t5547-push-quarantine.sh
+++ b/t/t5547-push-quarantine.sh
@@ -33,8 +33,7 @@ test_expect_success 'rejected objects are removed' '
test_cmp expect actual
 '
 
-# MINGW does not allow colons in pathnames in the first place
-test_expect_success !MINGW 'push to repo path with colon' '
+test_expect_success 'push to repo path with path separator (colon)' '
# The interesting failure case here is when the
# receiving end cannot access its original object directory,
# so make it likely for us to generate a delta by having
@@ -43,13 +42,20 @@ test_expect_success !MINGW 'push to repo path with colon' '
test-genrandom foo 4096 >file.bin &&
git add file.bin &&
git commit -m bin &&
-   git clone --bare . xxx:yyy.git &&
+
+   if test_have_prereq MINGW
+   then
+   pathsep=";"
+   else
+   pathsep=":"
+   fi &&
+   git clone --bare . "xxx${pathsep}yyy.git" &&
 
echo change >>file.bin &&
git commit -am change &&
# Note that we have to use the full path here, or it gets confused
# with the ssh host:path syntax.
-   git push "$PWD/xxx:yyy.git" HEAD
+   git push "$(pwd)/xxx${pathsep}yyy.git" HEAD
 '
 
 test_done
-- 
2.11.0.55.g6a4dbb1



Re: [PATCH 0/6] git-rm absorbs submodule git directory before deletion

2016-12-13 Thread Stefan Beller
On Tue, Dec 13, 2016 at 10:53 AM, Junio C Hamano  wrote:
> Stefan Beller  writes:
>
>> On Mon, Dec 12, 2016 at 11:28 PM, Junio C Hamano  wrote:
>>> Stefan Beller  writes:
>>>
 The "checkout --recurse-submodules" series got too large to comfortably 
 send
 it out for review, so I had to break it up into smaller series'; this is 
 the
 first subseries, but it makes sense on its own.

 This series teaches git-rm to absorb the git directory of a submodule 
 instead
 of failing and complaining about the git directory preventing deletion.

 It applies on origin/sb/submodule-embed-gitdir.
>>>
>>> Thanks.  I probably should rename the topic again with s/embed/absorb/;
>>
>> I mostly renamed it in the hope to settle our dispute what embedding means. 
>> ;)
>
> I do not think there is no dispute about what embedding means.

double negative: You think we have a slight dispute here.

>  A
> submodule whose .git is inside its working tree has its repository
> embedded.
>
> What we had trouble settling on was what to call the operation to
> undo the embedding, unentangling its repository out of the working
> tree.  I'd still vote for unembed if you want a name to be nominated.

So I can redo the series with two commands "git submodule [un]embed".

For me "unembed" == "absorb", such that we could also go with
absorb into superproject <-> embed into worktree


>
>> Note that sb/t3600-cleanup is part of this series now,
>> (The first commit of that series is in patch 6/6 of this series, and patch 5 
>> is
>> the modernization effort.)
>
> Well, "t3600: remove useless redirect" has been in 'next' already;
> do you mean that you want me to queue this series on top of that
> topic?
>

I need to reroll this series any way; the reroll will be on top of that.

Thanks,
Stefan


Re: [PATCH] builtin/commit.c: convert trivial snprintf calls to xsnprintf

2016-12-13 Thread Junio C Hamano
Jeff King  writes:

>> +argv_array_pushf(&env, "GIT_INDEX_FILE=%s", index_file);
>> +if (launch_editor(git_path_commit_editmsg(), NULL, env.argv)) {
>>  fprintf(stderr,
>>  _("Please supply the message using either -m or -F 
>> option.\n"));
>> +argv_array_clear(&env);
>>  exit(1);
>>  }
>> +argv_array_clear(&env);
>
> I'd generally skip the clear() right before exiting, though I saw
> somebody disagree with me recently on that.  I wonder if we should
> decide as a project on whether it is worth doing or not.

I'd say it is a responsibility of the person who turns exit(1) to
return -1 to ensure the code does not leak.

>> @@ -1525,12 +1526,10 @@ static int git_commit_config(const char *k, const 
>> char *v, void *cb)
>>  static int run_rewrite_hook(const unsigned char *oldsha1,
>>  const unsigned char *newsha1)
>>  {
>> -/* oldsha1 SP newsha1 LF NUL */
>> -static char buf[2*40 + 3];
>> +char *buf;
>>  struct child_process proc = CHILD_PROCESS_INIT;
>>  const char *argv[3];
>>  int code;
>> -size_t n;
>>  
>>  argv[0] = find_hook("post-rewrite");
>>  if (!argv[0])
>> @@ -1546,34 +1545,33 @@ static int run_rewrite_hook(const unsigned char 
>> *oldsha1,
>>  code = start_command(&proc);
>>  if (code)
>>  return code;
>> -n = snprintf(buf, sizeof(buf), "%s %s\n",
>> - sha1_to_hex(oldsha1), sha1_to_hex(newsha1));
>> +buf = xstrfmt("%s %s\n", sha1_to_hex(oldsha1), sha1_to_hex(newsha1));
>>  sigchain_push(SIGPIPE, SIG_IGN);
>> -write_in_full(proc.in, buf, n);
>> +write_in_full(proc.in, buf, strlen(buf));
>>  close(proc.in);
>> +free(buf);
>
> Any time you care about the length of the result, I'd generally use an
> actual strbuf instead of xstrfmt. The extra strlen isn't a big deal
> here, but it somehow seems simpler to me. It probably doesn't matter
> much either way, though.

Your justification for this extra allocation was that it is a
heavy-weight operation.  While I agree that the runtime cost of
allocation and deallocation does not matter, I would be a bit
worried about extra cognitive burden to programmers.  They did not
have to worry about leaking because they are writing a fixed length
string.  Now they do, whether they use xstrfmt() or struct strbuf.
When they need to update what they write, they do have to remember
to adjust the size of the "fixed string", and the original is not
free from the "programmers' cognitive cost" point of view, of
course.  Probably use of strbuf/xstrfmt is an overall win.

And of course, I think strbuf is more appropriate if you have to do
strlen().


Re: git add -p with new file

2016-12-13 Thread Jeff King
On Tue, Dec 13, 2016 at 10:48:07AM -0800, Junio C Hamano wrote:

> > I think the problem is just that "add -p" does not give the whole story
> > of what you might want to do before making a commit.
> 
> The same is shared by "git diff [HEAD]", by the way.  It is beyond
> me why people use "add -p", not "git diff [HEAD]", for the final
> sanity check before committing.  
> 
> Perhaps the latter is not advertised well enough?  "add -p" does not
> even page so it is not very useful way to check what is being added
> if you are adding a new file (unless you are doing a toy example to
> add a 7-line file).

I use "add -p" routinely for my final add-and-sanity-check, and it is
certainly not because I don't know about "git diff". I think it's just
nice to break it into bite-size chunks and sort them into "yes, OK" or
"no, not yet" bins. The lack of paging isn't usually a problem, because
this "add -p" is useful precisely when you have a lot of little changes
spread across the code base.

I'd probably also run "git diff" if I wanted to look at something
bigger. And I routinely use "git status", too, to see the full state of
my tree.

To me they are all tools in the toolbox, and I can pick the one that
works best in any given situation, or that I just feel like using that
day.

> >> Hm, "interactive.showUntracked" is a confusing name because "git add -i"
> >> (interactive) already handles untracked files.
> >
> > Sure, that was just meant for illustration. I agree there's probably a
> > better name.
> 
> "interactive.*" is not a sensible hierarchy to use, because things
> other than "add" can go interactive.
> 
> addPatch.showUntracked?

Hmm, I wonder if interactive.diffFilter was mis-named then. The
description is written in such a way as to cover other possible
interactive commands showing a diff.

It might be possible to do the same here: come up with a general option
that _could_ cover new situations, but right now just applies here. Or
maybe it would be too confusing.

TBH, I wasn't all that concerned with the name yet. Whoever writes the
patch can figure it out, and _then_ we can all bikeshed it. :)

-Peff


Re: [PATCH 0/6] git-rm absorbs submodule git directory before deletion

2016-12-13 Thread Junio C Hamano
Stefan Beller  writes:

> On Mon, Dec 12, 2016 at 11:28 PM, Junio C Hamano  wrote:
>> Stefan Beller  writes:
>>
>>> The "checkout --recurse-submodules" series got too large to comfortably send
>>> it out for review, so I had to break it up into smaller series'; this is the
>>> first subseries, but it makes sense on its own.
>>>
>>> This series teaches git-rm to absorb the git directory of a submodule 
>>> instead
>>> of failing and complaining about the git directory preventing deletion.
>>>
>>> It applies on origin/sb/submodule-embed-gitdir.
>>
>> Thanks.  I probably should rename the topic again with s/embed/absorb/;
>
> I mostly renamed it in the hope to settle our dispute what embedding means. ;)

I do not think there is no dispute about what embedding means.  A
submodule whose .git is inside its working tree has its repository
embedded.

What we had trouble settling on was what to call the operation to
undo the embedding, unentangling its repository out of the working
tree.  I'd still vote for unembed if you want a name to be nominated.

> Note that sb/t3600-cleanup is part of this series now,
> (The first commit of that series is in patch 6/6 of this series, and patch 5 
> is
> the modernization effort.)

Well, "t3600: remove useless redirect" has been in 'next' already;
do you mean that you want me to queue this series on top of that
topic?




Re: git add -p with new file

2016-12-13 Thread Junio C Hamano
Jeff King  writes:

>> I am also not really sure what problem this feature is trying to solve.
>> If the "problem"(?) is that it should act more like "git add" instead of
>> "git add -u", for whatever reason, this may be fine (but the
>> configuration option is a must-have then).
>
> I think the problem is just that "add -p" does not give the whole story
> of what you might want to do before making a commit.

The same is shared by "git diff [HEAD]", by the way.  It is beyond
me why people use "add -p", not "git diff [HEAD]", for the final
sanity check before committing.  

Perhaps the latter is not advertised well enough?  "add -p" does not
even page so it is not very useful way to check what is being added
if you are adding a new file (unless you are doing a toy example to
add a 7-line file).

>> > I'd also probably add interactive.showUntracked to make the whole thing
>> > optional (but I think it would be OK to default it to on).
>> Hm, "interactive.showUntracked" is a confusing name because "git add -i"
>> (interactive) already handles untracked files.
>
> Sure, that was just meant for illustration. I agree there's probably a
> better name.

"interactive.*" is not a sensible hierarchy to use, because things
other than "add" can go interactive.

addPatch.showUntracked?


Re: [PATCH 0/2] handling alternates paths with colons

2016-12-13 Thread Jeff King
On Tue, Dec 13, 2016 at 10:42:39AM -0800, Junio C Hamano wrote:

> Jeff King  writes:
> 
> > Right, but we also support relative paths via environment variables. I
> > don't think that changes the conclusion though. I'm not convinced
> > relative paths via the environment aren't slightly insane in the first
> > place,
> 
> Sorry, a triple negation is above my head.  "relative paths in env
> aren't insane" == "using relative paths is OK" and you are not
> convinced that it is the case, so you are saying that you think
> relative paths in env is not something that is sensible?

I think relative paths in env have very flaky semantics which makes them
inadvisable to use in general. That being said, when we broke even those
flaky semantics somebody complained. So I consider a feature we _do_
support, but not one I would recommend to people.

-Peff


Re: [PATCH 0/2] handling alternates paths with colons

2016-12-13 Thread Junio C Hamano
Jeff King  writes:

> Right, but we also support relative paths via environment variables. I
> don't think that changes the conclusion though. I'm not convinced
> relative paths via the environment aren't slightly insane in the first
> place,

Sorry, a triple negation is above my head.  "relative paths in env
aren't insane" == "using relative paths is OK" and you are not
convinced that it is the case, so you are saying that you think
relative paths in env is not something that is sensible?

> given the discussion in 37a95862c (alternates: re-allow relative
> paths from environment, 2016-11-07). And they'd probably start with
> "../" as well.

Yeah.  In any case, there is a potential regression but the chance
is miniscule---the user has to have been using a relative path that
begins with a double-quote in the environment or in alternates file.


Re: [PATCH 0/2] handling alternates paths with colons

2016-12-13 Thread Jeff King
On Tue, Dec 13, 2016 at 10:10:54AM -0800, Junio C Hamano wrote:

> > We do support non-absolute paths, both in alternates files and
> > environment variables. It's a nice feature if you want to have a
> > relocatable family of shared repositories. I'd imagine that most cases
> > start with "../", though.
> 
> Yes.  I was only talking about the environment variable, as you can
> tell from my mention of "colon" there.

Right, but we also support relative paths via environment variables. I
don't think that changes the conclusion though. I'm not convinced
relative paths via the environment aren't slightly insane in the first
place, given the discussion in 37a95862c (alternates: re-allow relative
paths from environment, 2016-11-07). And they'd probably start with
"../" as well.

-Peff


Re: [PATCH 2/2] tmp-objdir: quote paths we add to alternates

2016-12-13 Thread Jeff King
On Tue, Dec 13, 2016 at 10:10:04AM -0800, Junio C Hamano wrote:

> > -   git clone --bare . xxx:yyy.git &&
> > +   git clone --bare . xxx${path_sep}yyy.git &&
> 
> Don't you want to dq the whole thing to prevent the shell from
> splitting this into two commands at ';'?  The other one below is OK.

After expansion, I don't think the shell will do any further processing
except for whitespace splitting. E.g.:

  $ debug() { for i in "$@"; do echo "got $i"; done; }
  $ sep=';'
  $ space=' '
  $ debug foo${sep}bar
  got foo;bar
  $ debug foo${space}bar
  got foo
  got bar

I don't mind quoting it to make it more obvious, though.

-Peff


Re: [PATCH v6 01/16] Git.pm: add subroutines for commenting lines

2016-12-13 Thread Junio C Hamano
Vasco Almeida  writes:

>> We only update comment_line_char from the default "#" when the
>> configured value is a single-byte character and we ignore incorrect
>> values in the configuration file. So I think the patch you sent is
>> correct after all.
>
> I am still not sure what version do we prefer.
>
> Check whether core.commentchar is a single character. If not, use '#'
> as the $comment_line_char.

This, plus special casing "auto".

Picking the first byte is inconsistent with the current practice
(the paragraph you quoted above), I think.


Re: [PATCH 1/4] doc: add articles (grammar)

2016-12-13 Thread Junio C Hamano
Kristoffer Haugsbakk  writes:

> Thank you for reviewing this series, Philip.
>
> Philip Oakley writes:
>
>> This looks good to me.
>
> I'll add this header:
>
> Acked-by: Philip Oakley 
>
> To the commit message of this patch in the next review round (version 2
> of the patch series).
>
> Let me know if I should add another header, or do something different
> than this.

I was planning to merge all four from you as-is to 'next' today,
though.  Should I wait?



Re: [PATCH 0/2] handling alternates paths with colons

2016-12-13 Thread Junio C Hamano
Jeff King  writes:

> On Mon, Dec 12, 2016 at 02:37:08PM -0800, Junio C Hamano wrote:
>
>> Jeff King  writes:
>> 
>> > So here are patches that do that. It kicks in only when the first
>> > character of a path is a double-quote, and then expects the usual
>> > C-style quoting.
>> 
>> The quote being per delimited component is what makes this fifth
>> approach a huge win.  
>> 
>> All sane components on a list-valued environment are still honored
>> and an insane component that has either a colon in the middle or
>> begins with a double-quote gets quoted.  As long as nobody used a
>> path that begins with a double-quote as an element in such a
>> list-valued environment (and they cannot be, as using a non-absolute
>> path as an element does not make much sense), this will be safe, and
>> a path with a colon didn't work with Git unaware of the new quoting
>> rule anyway.  Nice.
>
> We do support non-absolute paths, both in alternates files and
> environment variables. It's a nice feature if you want to have a
> relocatable family of shared repositories. I'd imagine that most cases
> start with "../", though.

Yes.  I was only talking about the environment variable, as you can
tell from my mention of "colon" there.


Re: [PATCH 2/2] tmp-objdir: quote paths we add to alternates

2016-12-13 Thread Junio C Hamano
Jeff King  writes:

> The naive conversion is just:
> ...
> -# MINGW does not allow colons in pathnames in the first place
> -test_expect_success !MINGW 'push to repo path with colon' '
> +if test_have_prereq MINGW
> +then
> + path_sep=';'
> +else
> + path_sep=':'
> +fi
> ...
> - git clone --bare . xxx:yyy.git &&
> + git clone --bare . xxx${path_sep}yyy.git &&

Don't you want to dq the whole thing to prevent the shell from
splitting this into two commands at ';'?  The other one below is OK.

>  
>   echo change >>file.bin &&
>   git commit -am change &&
>   # Note that we have to use the full path here, or it gets confused
>   # with the ssh host:path syntax.
> - git push "$PWD/xxx:yyy.git" HEAD
> + git push "$PWD/xxx${path_sep}yyy.git" HEAD
>  '
>  
>  test_done
>
> Does that work?
>
> -Peff


Re: [PATCH 1/2] alternates: accept double-quoted paths

2016-12-13 Thread Junio C Hamano
Duy Nguyen  writes:

> At least attr has the same problem and is going the same direction
> [1]. Cool. (I actually thought the patch was in and evidence that this
> kind of backward compatibility breaking was ok, turns out the patch
> has stayed around for years)
>
> [1] 
> http://public-inbox.org/git/%3c20161110203428.30512-18-sbel...@google.com%3E/

Seeing that again, I see this in the proposed log message:

Full pattern must be quoted. So 'pat"t"ern attr' will give exactly
'pat"t"ern', not 'pattern'.

I cannot tell what it is trying to say.  The code suggests something
quite different, i.e. a line like this

"pat\"t\"ern" attr

would tell us that a path that matches the pattern

pat"t"ern

is given 'attr'.  

The log message may need to be cleaned up.  The update by that
commit to the documentation looks alright, thoguh.



RE: [PATCH 6/6] rm: add absorb a submodules git dir before deletion

2016-12-13 Thread David Turner
> -Original Message-
> From: Stefan Beller [mailto:sbel...@google.com]
> Sent: Monday, December 12, 2016 8:41 PM
> To: gits...@pobox.com
> Cc: git@vger.kernel.org; David Turner; bmw...@google.com; Stefan Beller
> Subject: [PATCH 6/6] rm: add absorb a submodules git dir before deletion
> 
> When deleting a submodule we need to keep the actual git directory around,

Nit: comma after submodule.

> - strbuf_reset(&buf);
> - strbuf_addstr(&buf, path);
> - if (!remove_dir_recursively(&buf, 0)) {
> - removed = 1;
> - if
> (!remove_path_from_gitmodules(path))
> - gitmodules_modified = 1;
> - strbuf_release(&buf);
> - continue;
> - } else if (!file_exists(path))
> - /* Submodule was removed by 
> user */
> - if
> (!remove_path_from_gitmodules(path))
> - gitmodules_modified = 1;
> + if (file_exists(path))
> + depopulate_submodule(path);
> + removed = 1;
> + if (!remove_path_from_gitmodules(path))
> + gitmodules_modified = 1;
> + continue;
>   /* Fallthrough and let remove_path() 
> fail.
> */

It seems odd to have a continue right before a comment that says "Fallthrough". 
 



Re: [PATCHv2 1/2] merge: Add '--continue' option as a synonym for 'git commit'

2016-12-13 Thread Junio C Hamano
Chris Packham  writes:

> +'git merge' --continue
>  
>  DESCRIPTION
>  ---
> @@ -61,6 +62,9 @@ reconstruct the original (pre-merge) changes. Therefore:
>  discouraged: while possible, it may leave you in a state that is hard to
>  back out of in the case of a conflict.
>  
> +The fourth syntax ("`git merge --continue`") can only be run after the
> +merge has resulted in conflicts.

OK.  I can see that the code refuses if there is no MERGE_HEAD, so
"can only be run" is ensured correctly.

> 'git merge --continue' will take the
> +currently staged changes and complete the merge.

For Git-savvy folks, this may be sufficient to tell that they are
expected to resolve conflicts in the working tree and register the
resolusion by doing "git add" before running "git merge --continue",
but I wonder if that is clear enough for new readers.

The same comment applies to the option description below.  I suspect
that it is better to remove the last sentence above, leaving "4th
one can be run only with MERGE_HEAD" here, and enhance the
explanation in the option description (see below).

>  OPTIONS
>  ---
> @@ -99,6 +103,12 @@ commit or stash your changes before running 'git merge'.
>  'git merge --abort' is equivalent to 'git reset --merge' when
>  `MERGE_HEAD` is present.
>  
> +--continue::
> + Take the currently staged changes and complete the merge.
> ++
> +'git merge --continue' is equivalent to 'git commit' when
> +`MERGE_HEAD` is present.
> +

These two sentences are even more technical and unfriendly to new
readers, I am afraid.  How about giving a hint by referring to an
existing section, like this?

--continue::
After a "git merge" stops due to conflicts you can conclude
the merge by running "git merge --continue" (see "How to
resolve conflicts" section below).

> @@ -277,7 +287,8 @@ After seeing a conflict, you can do two things:
>  
>   * Resolve the conflicts.  Git will mark the conflicts in
> the working tree.  Edit the files into shape and
> -   'git add' them to the index.  Use 'git commit' to seal the deal.
> +   'git add' them to the index.  Use 'git merge --continue' to seal the
> +   deal.

Why do we want to make it harder to discover "git commit" here?
I would understand:

... Use 'git commit' to conclude (you can also say 'git
merge --continue').

though.  After all, we are merely introducing a synonym for those
who want to type more.  There is no plan to deprecate the use of
'git commit', which is a perfectly reasonable way to conclude an
interrupted merge, that has worked well for us for the past 10 years
and still works.

> @@ -65,6 +66,7 @@ static int option_renormalize;
>  static int verbosity;
>  static int allow_rerere_auto;
>  static int abort_current_merge;
> +static int continue_current_merge;
>  static int allow_unrelated_histories;
>  static int show_progress = -1;
>  static int default_to_upstream = 1;
> @@ -223,6 +225,8 @@ static struct option builtin_merge_options[] = {
>   OPT__VERBOSITY(&verbosity),
>   OPT_BOOL(0, "abort", &abort_current_merge,
>   N_("abort the current in-progress merge")),
> + OPT_BOOL(0, "continue", &continue_current_merge,
> + N_("continue the current in-progress merge")),
>   OPT_BOOL(0, "allow-unrelated-histories", &allow_unrelated_histories,
>N_("allow merging unrelated histories")),
>   OPT_SET_INT(0, "progress", &show_progress, N_("force progress 
> reporting"), 1),
> @@ -739,7 +743,7 @@ static void abort_commit(struct commit_list *remoteheads, 
> const char *err_msg)
>   if (err_msg)
>   error("%s", err_msg);
>   fprintf(stderr,
> - _("Not committing merge; use 'git commit' to complete the 
> merge.\n"));
> + _("Not committing merge; use 'git merge --continue' to complete 
> the merge.\n"));

Likewise.  I do not see a need to change this one at all.

> @@ -1166,6 +1170,22 @@ int cmd_merge(int argc, const char **argv, const char 
> *prefix)
>   goto done;
>   }
>  
> + if (continue_current_merge) {
> + int nargc = 1;
> + const char *nargv[] = {"commit", NULL};
> +
> + if (argc)
> + usage_msg_opt("--continue expects no arguments",
> +   builtin_merge_usage, builtin_merge_options);

Peff already commented on "what about other options?", and I think
his "check the number of args before parse-options ran to ensure
that the '--abort' or '--continue' was the only thing" is probably
a workable hack.

The "right" way to fix it would be way too involved to be worth for
just this single change (and also fixing "--abort").  Just thinking
aloud:

 * Update parse-options API to:

   - extend "struct option" with one field that holds what "command
 modes" the option the "struct option" describes is incompatible
 with.

   - make parse_options() to keep track of the set of command modes
 that are

Re: [PATCH 0/6] git-rm absorbs submodule git directory before deletion

2016-12-13 Thread Stefan Beller
On Mon, Dec 12, 2016 at 11:28 PM, Junio C Hamano  wrote:
> Stefan Beller  writes:
>
>> The "checkout --recurse-submodules" series got too large to comfortably send
>> it out for review, so I had to break it up into smaller series'; this is the
>> first subseries, but it makes sense on its own.
>>
>> This series teaches git-rm to absorb the git directory of a submodule instead
>> of failing and complaining about the git directory preventing deletion.
>>
>> It applies on origin/sb/submodule-embed-gitdir.
>
> Thanks.  I probably should rename the topic again with s/embed/absorb/;

I mostly renamed it in the hope to settle our dispute what embedding means. ;)
So in case we want to further discuss on the name of the function, we should
do that before doing actual work such as renaming.

Note that sb/t3600-cleanup is part of this series now,
(The first commit of that series is in patch 6/6 of this series, and patch 5 is
the modernization effort.)

Thanks,
Stefan


Re: [PATCH 6/6] rm: add absorb a submodules git dir before deletion

2016-12-13 Thread Stefan Beller
On Mon, Dec 12, 2016 at 7:28 PM, brian m. carlson
 wrote:
> On Mon, Dec 12, 2016 at 05:40:55PM -0800, Stefan Beller wrote:
>> When deleting a submodule we need to keep the actual git directory around,
>> such that we do not lose local changes in there and at a later checkout
>> of the submodule we don't need to clone it again.
>>
>> Implement `depopulate_submodule`, that migrates the git directory before
>> deletion of a submodule and afterwards the equivalent of "rm -rf", which
>> is already found in entry.c, so expose that and for clarity add a suffix
>> "_or_dir" to it.
>
> I think you might have meant "_or_die" here.

indeed, will fix in a reroll. Thanks for the review!


Re: git add -p with new file

2016-12-13 Thread Jeff King
On Mon, Dec 12, 2016 at 09:31:03PM +0100, Stephan Beyer wrote:

> I am also a "git add -p"-only user (except for new files and merges).
> However, I usually keep a lot of untracked files in my repositories.
> Files that I do not (git)ignore because I want to see them when I type
> "git status".
> 
> Hence, the imagination only that "git add -p" starts to ask me for each
> untracked file feels like a lot of annoying "n" presses. I could imagine
> that it is okay-ish when it asks about the untracked files *after* all
> tracked paths have been processed (I guess this has been proposed
> before), so that I can safely quit.

Yeah, this is the "some people might be annoyed" that I mentioned
originally. If your workflow leaves a lot of untracked files that you
don't care about it, then I think you'd want this feature disabled
entirely via a config option (or vice versa, that it would only be
enabled by config option).

> I am also not really sure what problem this feature is trying to solve.
> If the "problem"(?) is that it should act more like "git add" instead of
> "git add -u", for whatever reason, this may be fine (but the
> configuration option is a must-have then).

I think the problem is just that "add -p" does not give the whole story
of what you might want to do before making a commit.

> > I'd also probably add interactive.showUntracked to make the whole thing
> > optional (but I think it would be OK to default it to on).
> Hm, "interactive.showUntracked" is a confusing name because "git add -i"
> (interactive) already handles untracked files.

Sure, that was just meant for illustration. I agree there's probably a
better name.

-Peff


  1   2   >