Git development
 help / color / mirror / Atom feed
* Re: Left with empty files after "git stash pop" when system hung
From: Jeff King @ 2016-09-14 22:58 UTC (permalink / raw)
  To: Daniel Hahler; +Cc: git
In-Reply-To: <5b203a8e-faa8-9f6e-8cdd-1024194e74a3@thequod.de>

On Tue, Sep 13, 2016 at 11:39:56PM +0200, Daniel Hahler wrote:

> I have used "git stash --include-untracked", checked out another branch,
> went back, and "git stash pop"ed the changes.
> Then my system crashed/hung (music that was playing was repeated in a
> loop).  I have waited for some minutes, and then turned it off.
> 
> Afterwards, the repository in question was in a state where all files
> contained in the stash were empty.
> "git status" looked good on first sight: all the untracked and modified
> files were listed there; but they were empty.
> 
>   % git fsck --lost-found
>   error: object file .git/objects/04/1e659b5dbfd3f0be351a782b54743692875aec is empty
>   error: object file .git/objects/04/1e659b5dbfd3f0be351a782b54743692875aec is empty
>   fatal: loose object 041e659b5dbfd3f0be351a782b54743692875aec (stored in .git/objects/04/1e659b5dbfd3f0be351a782b54743692875aec) is corrupt
>   % find .git/objects -size 0|wc -l
>   12
>
> [...]
> The filesystem in question is ext4, and I am using Arch Linux.

Is your filesystem mounted with data=writeback? Git should never write
an empty object file; it writes the content to a temporary file, and
then hardlinks it into place. If your filesystem does not order data and
metadata writes (i.e., the hardlink may get journaled and picked
up, even though the data did not hit the disk), then you can end up with
empty files. If you set core.fsyncobjectfiles in your config file, then
Git will fsync each object write (at the cost of some performance).

> I would have assumed that the "stash pop" operation would be "atomic",
> i.e. it should not remove the stash object before other objects have
> been written successfully.

Stash does not remove any objects at all; it should only be updating the
stash reflog to delete the entry (which also happens via write to a
tempfile and rename, though I don't think we ever fsync it, even with
core.fsyncobjectfiles).

The empty object you found is probably the result of a write too close
to the crash. In general I wouldn't expect "stash pop" to write, but I
suspect it may in order to populate the index.

> I have removed all empty files in .git/objects and tried to find the
> previous stash with `gitk --all $( git fsck | awk '{print $3}' )` then,
> but it appears to have disappeared.

fsck won't mention the object as dangling if it's reachable from a
reflog. Did you try "git stash list" (or just "git log -g refs/stash")?

-Peff

^ permalink raw reply

* Re: [PATCH] Move format-patch base commit and prerequisites before email signature
From: Junio C Hamano @ 2016-09-14 22:57 UTC (permalink / raw)
  To: Josh Triplett; +Cc: Jeff King, git
In-Reply-To: <xmqq7fakai5k.fsf@gitster.mtv.corp.google.com>

Junio C Hamano <gitster@pobox.com> writes:

> I do not mind doing it myself, but I am already in today's
> integration cycle (which will merge a handful of topics to
> 'master'), so I won't get around to it for some time.  If you are
> inclined to, please be my guest ;-)

I queued this on top for now; I think it can be just squashed into
your patch.  Please say "I agree" and I'll make it happen, or say
"that's wrong" followed by a replacement patch ;-).

Thanks.

 builtin/log.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/log.c b/builtin/log.c
index d69d5e6..cd9c4a4 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -1360,7 +1360,7 @@ static void print_bases(struct base_tree_info *bases, FILE *file)
 		return;
 
 	/* Show the base commit */
-	fprintf(file, "base-commit: %s\n", oid_to_hex(&bases->base_commit));
+	fprintf(file, "\nbase-commit: %s\n", oid_to_hex(&bases->base_commit));
 
 	/* Show the prerequisite patches */
 	for (i = bases->nr_patch_id - 1; i >= 0; i--)
-- 
2.10.0-458-g8cce42d


^ permalink raw reply related

* Re: [PATCH v4 3/4] read-cache: introduce chmod_index_entry
From: Junio C Hamano @ 2016-09-14 22:54 UTC (permalink / raw)
  To: Thomas Gummerer
  Cc: git, Johannes Schindelin, Jeff King, Jan Keromnes,
	Ingo Brückl, Edward Thomson
In-Reply-To: <xmqqbmzqqhm7.fsf@gitster.mtv.corp.google.com>

I've queued this trivial SQUASH??? on top, which I think should be
squashed into 3/4.

Thanks.


 read-cache.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/read-cache.c b/read-cache.c
index 2445e30..c2b2e97 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -779,7 +779,7 @@ int chmod_index_entry(struct index_state *istate, struct cache_entry *ce,
 	default:
 		return -2;
 	}
-	cache_tree_invalidate_path(&the_index, ce->name);
+	cache_tree_invalidate_path(istate, ce->name);
 	ce->ce_flags |= CE_UPDATE_IN_BASE;
 	istate->cache_changed |= CE_ENTRY_CHANGED;
 
-- 
2.10.0-458-g8cce42d


^ permalink raw reply related

* Re: [PATCH 1/2] serialize collection of changed submodules
From: Junio C Hamano @ 2016-09-14 22:30 UTC (permalink / raw)
  To: Heiko Voigt
  Cc: Jeff King, Stefan Beller, git@vger.kernel.org, Jens Lehmann,
	Fredrik Gustafsson, Leandro Lucarella
In-Reply-To: <20160914173124.GA7613@sandbox>

Heiko Voigt <hvoigt@hvoigt.net> writes:

> Sorry about the late reply. I was not able to process emails until now.
> Here are two patches that should help to improve the situation and batch
> up some processing. This one is for repositories with submodules, so
> that they do not iterate over the same submodule twice with the same
> hash.
>
> The second one will be the one people without submodules are interested
> in.

Thanks.  Will take a look at later as I'm already deep in today's
integration cycle.  Very much appreciated.

^ permalink raw reply

* Re: Bug
From: Dennis Kaarsemaker @ 2016-09-14 22:14 UTC (permalink / raw)
  To: Mike Hawes, git; +Cc: mh351681
In-Reply-To: <B1BB8E37-C36E-4F4A-BC5F-FDA32CE162AF@gmail.com>

On Tue, 2016-09-13 at 13:18 -0400, Mike Hawes wrote:
> To whom this may concern,
>
> I found a bug in git while trying to push my website.
> I redid the process and it happened again.
> I also tried it on another computer and it happened again.
> I was wondering how to claim a bug?

Hi Mike,

When you think git does not behave as you expect, please do not stop
your bug report with just "git does not work".  "I used git in this
way, but it did not work" is not much better, neither is "I used git
in this way, and X happend, which is broken".  It often is that git is
correct to cause X happen in such a case, and it is your expectation
that is broken. People would not know what other result Y you expected
to see instead of X, if you left it unsaid.

Please remember to always state

 - what you wanted to achieve;

 - what you did (the version of git and the command sequence to reproduce
   the behavior);

 - what you saw happen (X above);

 - what you expected to see (Y above); and

 - how the last two are different.

See http://www.chiark.greenend.org.uk/~sgtatham/bugs.html for further
hints.

(The above was shamelessly copied from the "A note from the maintainer" mails)

D.

^ permalink raw reply

* Re: [PATCH v4 4/4] add: modify already added files when --chmod is given
From: Junio C Hamano @ 2016-09-14 21:54 UTC (permalink / raw)
  To: Thomas Gummerer
  Cc: git, Johannes Schindelin, Jeff King, Jan Keromnes,
	Ingo Brückl, Edward Thomson
In-Reply-To: <20160914210747.15485-5-t.gummerer@gmail.com>

Thomas Gummerer <t.gummerer@gmail.com> writes:

> When the chmod option was added to git add, it was hooked up to the diff
> machinery, meaning that it only works when the version in the index
> differs from the version on disk.
>
> As the option was supposed to mirror the chmod option in update-index,
> which always changes the mode in the index, regardless of the status of
> the file, make sure the option behaves the same way in git add.
>
> Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
> ---

This change essentially reverts most of what 4e55ed32 ("add: add
--chmod=+x / --chmod=-x options", 2016-05-31) did, except that it
keeps the command line option and adjusts its validation, and adds a
separate phase to "fix-up" the executable bits for all paths that
match the given pathspec, whether they were new or modified or
unchanged.

The patch makes sense to me.  Thanks.

^ permalink raw reply

* Re: [PATCH v4 3/4] read-cache: introduce chmod_index_entry
From: Junio C Hamano @ 2016-09-14 21:46 UTC (permalink / raw)
  To: Thomas Gummerer
  Cc: git, Johannes Schindelin, Jeff King, Jan Keromnes,
	Ingo Brückl, Edward Thomson
In-Reply-To: <20160914210747.15485-4-t.gummerer@gmail.com>

Thomas Gummerer <t.gummerer@gmail.com> writes:

> As there are chmod options for both add and update-index, introduce a
> new chmod_index_entry function to do the work.  Use it in update-index,
> while it will be used in add in the next patch.
>
> Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
> ---
>  builtin/update-index.c | 16 ++--------------
>  cache.h                |  2 ++
>  read-cache.c           | 29 +++++++++++++++++++++++++++++
>  3 files changed, 33 insertions(+), 14 deletions(-)
>
> diff --git a/builtin/update-index.c b/builtin/update-index.c
> index bbdf0d9..9e9e040 100644
> --- a/builtin/update-index.c
> +++ b/builtin/update-index.c
> @@ -423,26 +423,14 @@ static void chmod_path(char flip, const char *path)
>  {
> ...
> -	mode = ce->ce_mode;
> -	if (!S_ISREG(mode))
> -		goto fail;
> -	switch (flip) {
> -	case '+':
> -		ce->ce_mode |= 0111; break;
> -	case '-':
> -		ce->ce_mode &= ~0111; break;
> -	default:
> +	if (chmod_cache_entry(ce, flip) < 0)
>  		goto fail;
> -	}
> -	cache_tree_invalidate_path(&the_index, path);

This used to always work on the default index, hence the_index
reference is here, but ...

> +int chmod_index_entry(struct index_state *istate, struct cache_entry *ce,
> +		      char flip)
> +{
> +	if (!S_ISREG(ce->ce_mode))
> +		return -1;
> +	switch (flip) {
> +	case '+':
> +		ce->ce_mode |= 0111;
> +		break;
> +	case '-':
> +		ce->ce_mode &= ~0111;
> +		break;
> +	default:
> +		return -2;
> +	}
> +	cache_tree_invalidate_path(&the_index, ce->name);

... this one takes istate, so you need to use it, instead of the
hard-coded the_index reference.

> +	ce->ce_flags |= CE_UPDATE_IN_BASE;
> +	istate->cache_changed |= CE_ENTRY_CHANGED;
> +
> +	return 0;
> +}
> +
>  int ce_same_name(const struct cache_entry *a, const struct cache_entry *b)
>  {
>  	int len = ce_namelen(a);

Other than that, this looks good to me.

^ permalink raw reply

* [PATCH v4 4/4] add: modify already added files when --chmod is given
From: Thomas Gummerer @ 2016-09-14 21:07 UTC (permalink / raw)
  To: git
  Cc: Johannes Schindelin, Jeff King, Jan Keromnes, Ingo Brückl,
	Edward Thomson, Junio C Hamano, Thomas Gummerer
In-Reply-To: <20160914210747.15485-1-t.gummerer@gmail.com>

When the chmod option was added to git add, it was hooked up to the diff
machinery, meaning that it only works when the version in the index
differs from the version on disk.

As the option was supposed to mirror the chmod option in update-index,
which always changes the mode in the index, regardless of the status of
the file, make sure the option behaves the same way in git add.

Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
---
 builtin/add.c      | 47 ++++++++++++++++++++++++++++-------------------
 builtin/checkout.c |  2 +-
 builtin/commit.c   |  2 +-
 cache.h            | 10 +++++-----
 read-cache.c       | 14 ++++++--------
 t/t3700-add.sh     | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 91 insertions(+), 34 deletions(-)

diff --git a/builtin/add.c b/builtin/add.c
index b1dddb4..595a0b2 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -26,10 +26,25 @@ static int patch_interactive, add_interactive, edit_interactive;
 static int take_worktree_changes;
 
 struct update_callback_data {
-	int flags, force_mode;
+	int flags;
 	int add_errors;
 };
 
+static void chmod_pathspec(struct pathspec *pathspec, int force_mode)
+{
+	int i;
+	
+	for (i = 0; i < active_nr; i++) {
+		struct cache_entry *ce = active_cache[i];
+
+		if (pathspec && !ce_path_match(ce, pathspec, NULL))
+			continue;
+
+		if (chmod_cache_entry(ce, force_mode) < 0)
+			fprintf(stderr, "cannot chmod '%s'", ce->name);
+	}
+}
+
 static int fix_unmerged_status(struct diff_filepair *p,
 			       struct update_callback_data *data)
 {
@@ -65,8 +80,7 @@ static void update_callback(struct diff_queue_struct *q,
 			die(_("unexpected diff status %c"), p->status);
 		case DIFF_STATUS_MODIFIED:
 		case DIFF_STATUS_TYPE_CHANGED:
-			if (add_file_to_index(&the_index, path,
-					data->flags, data->force_mode)) {
+			if (add_file_to_index(&the_index, path,	data->flags)) {
 				if (!(data->flags & ADD_CACHE_IGNORE_ERRORS))
 					die(_("updating files failed"));
 				data->add_errors++;
@@ -84,15 +98,14 @@ static void update_callback(struct diff_queue_struct *q,
 	}
 }
 
-int add_files_to_cache(const char *prefix, const struct pathspec *pathspec,
-	int flags, int force_mode)
+int add_files_to_cache(const char *prefix,
+		       const struct pathspec *pathspec, int flags)
 {
 	struct update_callback_data data;
 	struct rev_info rev;
 
 	memset(&data, 0, sizeof(data));
 	data.flags = flags;
-	data.force_mode = force_mode;
 
 	init_revisions(&rev, prefix);
 	setup_revisions(0, NULL, &rev, NULL);
@@ -281,7 +294,7 @@ static int add_config(const char *var, const char *value, void *cb)
 	return git_default_config(var, value, cb);
 }
 
-static int add_files(struct dir_struct *dir, int flags, int force_mode)
+static int add_files(struct dir_struct *dir, int flags)
 {
 	int i, exit_status = 0;
 
@@ -294,8 +307,7 @@ static int add_files(struct dir_struct *dir, int flags, int force_mode)
 	}
 
 	for (i = 0; i < dir->nr; i++)
-		if (add_file_to_index(&the_index, dir->entries[i]->name,
-				flags, force_mode)) {
+		if (add_file_to_index(&the_index, dir->entries[i]->name, flags)) {
 			if (!ignore_add_errors)
 				die(_("adding files failed"));
 			exit_status = 1;
@@ -308,7 +320,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
 	int exit_status = 0;
 	struct pathspec pathspec;
 	struct dir_struct dir;
-	int flags, force_mode;
+	int flags;
 	int add_new_files;
 	int require_pathspec;
 	char *seen = NULL;
@@ -342,13 +354,8 @@ int cmd_add(int argc, const char **argv, const char *prefix)
 	if (!show_only && ignore_missing)
 		die(_("Option --ignore-missing can only be used together with --dry-run"));
 
-	if (!chmod_arg)
-		force_mode = 0;
-	else if (!strcmp(chmod_arg, "-x"))
-		force_mode = 0666;
-	else if (!strcmp(chmod_arg, "+x"))
-		force_mode = 0777;
-	else
+	if (chmod_arg && ((chmod_arg[0] != '-' && chmod_arg[0] != '+') ||
+			  chmod_arg[1] != 'x' || chmod_arg[2]))
 		die(_("--chmod param '%s' must be either -x or +x"), chmod_arg);
 
 	add_new_files = !take_worktree_changes && !refresh_only;
@@ -441,11 +448,13 @@ int cmd_add(int argc, const char **argv, const char *prefix)
 
 	plug_bulk_checkin();
 
-	exit_status |= add_files_to_cache(prefix, &pathspec, flags, force_mode);
+	exit_status |= add_files_to_cache(prefix, &pathspec, flags);
 
 	if (add_new_files)
-		exit_status |= add_files(&dir, flags, force_mode);
+		exit_status |= add_files(&dir, flags);
 
+	if (chmod_arg && pathspec.nr)
+		chmod_pathspec(&pathspec, chmod_arg[0]);
 	unplug_bulk_checkin();
 
 finish:
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 8672d07..a83c78f 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -548,7 +548,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
 			 * entries in the index.
 			 */
 
-			add_files_to_cache(NULL, NULL, 0, 0);
+			add_files_to_cache(NULL, NULL, 0);
 			/*
 			 * NEEDSWORK: carrying over local changes
 			 * when branches have different end-of-line
diff --git a/builtin/commit.c b/builtin/commit.c
index bb9f79b..1cba3b7 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -397,7 +397,7 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
 	 */
 	if (all || (also && pathspec.nr)) {
 		hold_locked_index(&index_lock, 1);
-		add_files_to_cache(also ? prefix : NULL, &pathspec, 0, 0);
+		add_files_to_cache(also ? prefix : NULL, &pathspec, 0);
 		refresh_cache_or_die(refresh_flags);
 		update_main_cache_tree(WRITE_TREE_SILENT);
 		if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))
diff --git a/cache.h b/cache.h
index 35c8d1c..cd8e9fe 100644
--- a/cache.h
+++ b/cache.h
@@ -367,8 +367,8 @@ extern void free_name_hash(struct index_state *istate);
 #define rename_cache_entry_at(pos, new_name) rename_index_entry_at(&the_index, (pos), (new_name))
 #define remove_cache_entry_at(pos) remove_index_entry_at(&the_index, (pos))
 #define remove_file_from_cache(path) remove_file_from_index(&the_index, (path))
-#define add_to_cache(path, st, flags) add_to_index(&the_index, (path), (st), (flags), 0)
-#define add_file_to_cache(path, flags) add_file_to_index(&the_index, (path), (flags), 0)
+#define add_to_cache(path, st, flags) add_to_index(&the_index, (path), (st), (flags))
+#define add_file_to_cache(path, flags) add_file_to_index(&the_index, (path), (flags))
 #define chmod_cache_entry(ce, flip) chmod_index_entry(&the_index, (ce), (flip))
 #define refresh_cache(flags) refresh_index(&the_index, (flags), NULL, NULL, NULL)
 #define ce_match_stat(ce, st, options) ie_match_stat(&the_index, (ce), (st), (options))
@@ -582,8 +582,8 @@ extern int remove_file_from_index(struct index_state *, const char *path);
 #define ADD_CACHE_IGNORE_ERRORS	4
 #define ADD_CACHE_IGNORE_REMOVAL 8
 #define ADD_CACHE_INTENT 16
-extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags, int force_mode);
-extern int add_file_to_index(struct index_state *, const char *path, int flags, int force_mode);
+extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags);
+extern int add_file_to_index(struct index_state *, const char *path, int flags);
 extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, unsigned int refresh_options);
 extern int chmod_index_entry(struct index_state *, struct cache_entry *ce, char flip);
 extern int ce_same_name(const struct cache_entry *a, const struct cache_entry *b);
@@ -1821,7 +1821,7 @@ void packet_trace_identity(const char *prog);
  * return 0 if success, 1 - if addition of a file failed and
  * ADD_FILES_IGNORE_ERRORS was specified in flags
  */
-int add_files_to_cache(const char *prefix, const struct pathspec *pathspec, int flags, int force_mode);
+int add_files_to_cache(const char *prefix, const struct pathspec *pathspec, int flags);
 
 /* diff.c */
 extern int diff_auto_refresh_index;
diff --git a/read-cache.c b/read-cache.c
index 8924f2e..016bbcb 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -627,7 +627,7 @@ void set_object_name_for_intent_to_add_entry(struct cache_entry *ce)
 	hashcpy(ce->sha1, sha1);
 }
 
-int add_to_index(struct index_state *istate, const char *path, struct stat *st, int flags, int force_mode)
+int add_to_index(struct index_state *istate, const char *path, struct stat *st, int flags)
 {
 	int size, namelen, was_same;
 	mode_t st_mode = st->st_mode;
@@ -656,11 +656,10 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
 	else
 		ce->ce_flags |= CE_INTENT_TO_ADD;
 
-	if (S_ISREG(st_mode) && force_mode)
-		ce->ce_mode = create_ce_mode(force_mode);
-	else if (trust_executable_bit && has_symlinks)
+
+	if (trust_executable_bit && has_symlinks) {
 		ce->ce_mode = create_ce_mode(st_mode);
-	else {
+	} else {
 		/* If there is an existing entry, pick the mode bits and type
 		 * from it, otherwise assume unexecutable regular file.
 		 */
@@ -719,13 +718,12 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
 	return 0;
 }
 
-int add_file_to_index(struct index_state *istate, const char *path,
-	int flags, int force_mode)
+int add_file_to_index(struct index_state *istate, const char *path, int flags)
 {
 	struct stat st;
 	if (lstat(path, &st))
 		die_errno("unable to stat '%s'", path);
-	return add_to_index(istate, path, &st, flags, force_mode);
+	return add_to_index(istate, path, &st, flags);
 }
 
 struct cache_entry *make_cache_entry(unsigned int mode,
diff --git a/t/t3700-add.sh b/t/t3700-add.sh
index 2978cb9..0a962a6 100755
--- a/t/t3700-add.sh
+++ b/t/t3700-add.sh
@@ -349,4 +349,54 @@ test_expect_success POSIXPERM,SYMLINKS 'git add --chmod=+x with symlinks' '
 	test_mode_in_index 100755 foo2
 '
 
+test_expect_success 'git add --chmod=[+-]x changes index with already added file' '
+	echo foo >foo3 &&
+	git add foo3 &&
+	git add --chmod=+x foo3 &&
+	test_mode_in_index 100755 foo3 &&
+	echo foo >xfoo3 &&
+	chmod 755 xfoo3 &&
+	git add xfoo3 &&
+	git add --chmod=-x xfoo3 &&
+	test_mode_in_index 100644 xfoo3
+'
+
+test_expect_success 'file status is changed after git add --chmod=+x' '
+	echo "AM foo4" >expected &&
+	echo foo >foo4 &&
+	git add foo4 &&
+	git add --chmod=+x foo4 &&
+	git status -s foo4 >actual &&
+	test_cmp expected actual
+'
+
+test_expect_success 'no file status change if no pathspec is given' '
+	>foo5 &&
+	>foo6 &&
+	git add foo5 foo6 &&
+	git add --chmod=+x &&
+	test_mode_in_index 100644 foo5 &&
+	test_mode_in_index 100644 foo6
+'
+
+test_expect_success 'no file status change if no pathspec is given in subdir' '
+	mkdir sub &&
+	(
+		cd sub &&
+		>sub-foo1 &&
+		>sub-foo2 &&
+		git add . &&
+		git add --chmod=+x &&
+		test_mode_in_index 100644 sub-foo1 &&
+		test_mode_in_index 100644 sub-foo2
+	)
+'
+
+test_expect_success 'all statuses changed in folder if . is given' '
+	git add --chmod=+x . &&
+	test $(git ls-files --stage | grep ^100644 | wc -l) -eq 0 &&
+	git add --chmod=-x . &&
+	test $(git ls-files --stage | grep ^100755 | wc -l) -eq 0
+'
+
 test_done
-- 
2.10.0.304.gf2ff484


^ permalink raw reply related

* [PATCH v4 3/4] read-cache: introduce chmod_index_entry
From: Thomas Gummerer @ 2016-09-14 21:07 UTC (permalink / raw)
  To: git
  Cc: Johannes Schindelin, Jeff King, Jan Keromnes, Ingo Brückl,
	Edward Thomson, Junio C Hamano, Thomas Gummerer
In-Reply-To: <20160914210747.15485-1-t.gummerer@gmail.com>

As there are chmod options for both add and update-index, introduce a
new chmod_index_entry function to do the work.  Use it in update-index,
while it will be used in add in the next patch.

Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
---
 builtin/update-index.c | 16 ++--------------
 cache.h                |  2 ++
 read-cache.c           | 29 +++++++++++++++++++++++++++++
 3 files changed, 33 insertions(+), 14 deletions(-)

diff --git a/builtin/update-index.c b/builtin/update-index.c
index bbdf0d9..9e9e040 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -423,26 +423,14 @@ static void chmod_path(char flip, const char *path)
 {
 	int pos;
 	struct cache_entry *ce;
-	unsigned int mode;
 
 	pos = cache_name_pos(path, strlen(path));
 	if (pos < 0)
 		goto fail;
 	ce = active_cache[pos];
-	mode = ce->ce_mode;
-	if (!S_ISREG(mode))
-		goto fail;
-	switch (flip) {
-	case '+':
-		ce->ce_mode |= 0111; break;
-	case '-':
-		ce->ce_mode &= ~0111; break;
-	default:
+	if (chmod_cache_entry(ce, flip) < 0)
 		goto fail;
-	}
-	cache_tree_invalidate_path(&the_index, path);
-	ce->ce_flags |= CE_UPDATE_IN_BASE;
-	active_cache_changed |= CE_ENTRY_CHANGED;
+
 	report("chmod %cx '%s'", flip, path);
 	return;
  fail:
diff --git a/cache.h b/cache.h
index 6738050..35c8d1c 100644
--- a/cache.h
+++ b/cache.h
@@ -369,6 +369,7 @@ extern void free_name_hash(struct index_state *istate);
 #define remove_file_from_cache(path) remove_file_from_index(&the_index, (path))
 #define add_to_cache(path, st, flags) add_to_index(&the_index, (path), (st), (flags), 0)
 #define add_file_to_cache(path, flags) add_file_to_index(&the_index, (path), (flags), 0)
+#define chmod_cache_entry(ce, flip) chmod_index_entry(&the_index, (ce), (flip))
 #define refresh_cache(flags) refresh_index(&the_index, (flags), NULL, NULL, NULL)
 #define ce_match_stat(ce, st, options) ie_match_stat(&the_index, (ce), (st), (options))
 #define ce_modified(ce, st, options) ie_modified(&the_index, (ce), (st), (options))
@@ -584,6 +585,7 @@ extern int remove_file_from_index(struct index_state *, const char *path);
 extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags, int force_mode);
 extern int add_file_to_index(struct index_state *, const char *path, int flags, int force_mode);
 extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, unsigned int refresh_options);
+extern int chmod_index_entry(struct index_state *, struct cache_entry *ce, char flip);
 extern int ce_same_name(const struct cache_entry *a, const struct cache_entry *b);
 extern void set_object_name_for_intent_to_add_entry(struct cache_entry *ce);
 extern int index_name_is_other(const struct index_state *, const char *, int);
diff --git a/read-cache.c b/read-cache.c
index 491e52d..8924f2e 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -756,6 +756,35 @@ struct cache_entry *make_cache_entry(unsigned int mode,
 	return ret;
 }
 
+/*
+ * Chmod an index entry with either +x or -x.
+ *
+ * Returns -1 if the chmod for the particular cache entry failed (if it's
+ * not a regular file), -2 if an invalid flip argument is passed in, 0
+ * otherwise.
+ */
+int chmod_index_entry(struct index_state *istate, struct cache_entry *ce,
+		      char flip)
+{
+	if (!S_ISREG(ce->ce_mode))
+		return -1;
+	switch (flip) {
+	case '+':
+		ce->ce_mode |= 0111;
+		break;
+	case '-':
+		ce->ce_mode &= ~0111;
+		break;
+	default:
+		return -2;
+	}
+	cache_tree_invalidate_path(&the_index, ce->name);
+	ce->ce_flags |= CE_UPDATE_IN_BASE;
+	istate->cache_changed |= CE_ENTRY_CHANGED;
+
+	return 0;
+}
+
 int ce_same_name(const struct cache_entry *a, const struct cache_entry *b)
 {
 	int len = ce_namelen(a);
-- 
2.10.0.304.gf2ff484


^ permalink raw reply related

* [PATCH v4 2/4] update-index: add test for chmod flags
From: Thomas Gummerer @ 2016-09-14 21:07 UTC (permalink / raw)
  To: git
  Cc: Johannes Schindelin, Jeff King, Jan Keromnes, Ingo Brückl,
	Edward Thomson, Junio C Hamano, Thomas Gummerer
In-Reply-To: <20160914210747.15485-1-t.gummerer@gmail.com>

Currently there is no test checking the expected behaviour when multiple
chmod flags with different arguments are passed.  As argument handling
is not in line with other git commands it's easy to miss and
accidentally change the current behaviour.

While there, fix the argument type of chmod_path, which takes an int,
but had a char passed in.

Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
---
 builtin/update-index.c        |  2 +-
 t/t2107-update-index-basic.sh | 13 +++++++++++++
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/builtin/update-index.c b/builtin/update-index.c
index ba04b19..bbdf0d9 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -419,7 +419,7 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,
 	return 0;
 }
 
-static void chmod_path(int flip, const char *path)
+static void chmod_path(char flip, const char *path)
 {
 	int pos;
 	struct cache_entry *ce;
diff --git a/t/t2107-update-index-basic.sh b/t/t2107-update-index-basic.sh
index dfe02f4..32ac6e0 100755
--- a/t/t2107-update-index-basic.sh
+++ b/t/t2107-update-index-basic.sh
@@ -80,4 +80,17 @@ test_expect_success '.lock files cleaned up' '
 	)
 '
 
+test_expect_success '--chmod=+x and chmod=-x in the same argument list' '
+	>A &&
+	>B &&
+	git add A B &&
+	git update-index --chmod=+x A --chmod=-x B &&
+	cat >expect <<-\EOF &&
+	100755 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0	A
+	100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0	B
+	EOF
+	git ls-files --stage A B >actual &&
+	test_cmp expect actual
+'
+
 test_done
-- 
2.10.0.304.gf2ff484


^ permalink raw reply related

* [PATCH v4 1/4] add: document the chmod option
From: Thomas Gummerer @ 2016-09-14 21:07 UTC (permalink / raw)
  To: git
  Cc: Johannes Schindelin, Jeff King, Jan Keromnes, Ingo Brückl,
	Edward Thomson, Junio C Hamano, Thomas Gummerer
In-Reply-To: <20160914210747.15485-1-t.gummerer@gmail.com>

The git add --chmod option was introduced in 4e55ed3 ("add: add
--chmod=+x / --chmod=-x options", 2016-05-31), but was never
documented.  Document the feature.

Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
---
 Documentation/git-add.txt | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt
index 6a96a66..7ed63dc 100644
--- a/Documentation/git-add.txt
+++ b/Documentation/git-add.txt
@@ -11,7 +11,7 @@ SYNOPSIS
 'git add' [--verbose | -v] [--dry-run | -n] [--force | -f] [--interactive | -i] [--patch | -p]
 	  [--edit | -e] [--[no-]all | --[no-]ignore-removal | [--update | -u]]
 	  [--intent-to-add | -N] [--refresh] [--ignore-errors] [--ignore-missing]
-	  [--] [<pathspec>...]
+	  [--chmod=(+|-)x] [--] [<pathspec>...]
 
 DESCRIPTION
 -----------
@@ -165,6 +165,11 @@ for "git add --no-all <pathspec>...", i.e. ignored removed files.
 	be ignored, no matter if they are already present in the work
 	tree or not.
 
+--chmod=(+|-)x::
+	Override the executable bit of the added files.  The executable
+	bit is only changed in the index, the files on disk are left
+	unchanged.
+
 \--::
 	This option can be used to separate command-line options from
 	the list of files, (useful when filenames might be mistaken
-- 
2.10.0.304.gf2ff484


^ permalink raw reply related

* [PATCH v4 0/4] git add --chmod: always change the file
From: Thomas Gummerer @ 2016-09-14 21:07 UTC (permalink / raw)
  To: git
  Cc: Johannes Schindelin, Jeff King, Jan Keromnes, Ingo Brückl,
	Edward Thomson, Junio C Hamano, Thomas Gummerer
In-Reply-To: <20160912210818.26282-1-t.gummerer@gmail.com>

Thanks Junio for the review of my last round.

Changes since then:
[1/4]: patch unchanged
[2/4]: Only adds a test now, and corrects the type of the argument of
       chmod_path, but leaves the rest of the patch unchanged.
[3/4]: chmod_index_entry now takes a char as argument which can either
       be + or -, and changes the mode based on that, instead of using
       the 0777 or 0666 mode that was passed in from the outside.
[4/4]: Adapted to the different behaviour of chmod_index_entry and
       added tests as suggested by Junio.

Thomas Gummerer (4):
  add: document the chmod option
  update-index: add test for chmod flags
  read-cache: introduce chmod_index_entry
  add: modify already added files when --chmod is given

 Documentation/git-add.txt     |  7 +++++-
 builtin/add.c                 | 47 ++++++++++++++++++++++++----------------
 builtin/checkout.c            |  2 +-
 builtin/commit.c              |  2 +-
 builtin/update-index.c        | 18 +++-------------
 cache.h                       | 12 ++++++-----
 read-cache.c                  | 43 ++++++++++++++++++++++++++++++-------
 t/t2107-update-index-basic.sh | 13 +++++++++++
 t/t3700-add.sh                | 50 +++++++++++++++++++++++++++++++++++++++++++
 9 files changed, 144 insertions(+), 50 deletions(-)

-- 
2.10.0.304.gf2ff484


^ permalink raw reply

* Re: Bug Report: "git submodule deinit" fails right after a clone
From: Heiko Voigt @ 2016-09-14 20:29 UTC (permalink / raw)
  To: Thomas Bétous; +Cc: git
In-Reply-To: <CAPOqYV+C-P9M2zcUBBkD2LALPm4K3sxSut+BjAkZ9T1AKLEr+A@mail.gmail.com>

On Tue, Aug 30, 2016 at 01:45:56PM +0200, Thomas Bétous wrote:
> Are you able to reproduce this problem?

No. I just did a clone and an immediate deinit afterwards and no error.
Maybe you can provide a script to reproduce? Which System was this on?

Cheers Heiko

^ permalink raw reply

* Re: git submodule add spits unrelated to actual problem error msg about .gitignore
From: Yaroslav Halchenko @ 2016-09-14 20:23 UTC (permalink / raw)
  To: Stefan Beller; +Cc: git@vger.kernel.org
In-Reply-To: <CAGZ79kbdfWHDGzoe21LVqt6naMJPWGf45S1oknrAp6=Z-Qm8dQ@mail.gmail.com>

On September 14, 2016 3:32:11 PM EDT, Stefan Beller <sbeller@google.com> wrote:
!
>I think we could chop off "2>&1" as that would have exposed the
>underlying error.
>
>Another way to go would be to use verbose git-add and grep for
>the string "add '$sm_path'".
>
>     if test -z "$force" && ! git add --verbose --dry-run
>--ignore-missing "$sm_path" |grep "add $sm_path"
>
>git-add already gives the correct (the same error message) for  the
>ignored files, so maybe we'd just do:
>
>    # no need for a if, but this single line will do:
>    test -z "$force" && git add --dry-run git.o >/dev/null || exit 1

FWIW Imho exposing error is good but not sufficient alone, since custom gitignore message would still be confusing.
-- 
Sent from a phone which beats iPhone.

^ permalink raw reply

* Re: [PATCH 2/2] serialize collection of refs that contain submodule changes
From: Stefan Beller @ 2016-09-14 20:04 UTC (permalink / raw)
  To: Heiko Voigt
  Cc: Jeff King, Junio C Hamano, git@vger.kernel.org, Jens Lehmann,
	Fredrik Gustafsson, Leandro Lucarella
In-Reply-To: <20160914194643.GC7613@sandbox>

On Wed, Sep 14, 2016 at 12:46 PM, Heiko Voigt <hvoigt@hvoigt.net> wrote:
> On Wed, Sep 14, 2016 at 07:51:30PM +0200, Heiko Voigt wrote:
>> Here are some numbers (using the my development clone of git
>> itself) from my local machine:
>>
>> rm -rf <test-git> && mkdir <test-git> &&
>> (cd <test-git> && git init) &&
>> time git push --mirror <test-git>
>>
>>    real       0m16.056s
>>    user       0m24.424s
>>    sys        0m1.380s
>>
>>    real       0m15.885s
>>    user       0m24.204s
>>    sys        0m1.296s
>>
>>    real       0m16.731s
>>    user       0m24.176s
>>    sys        0m1.244s
>>
>> rm -rf <test-git> && mkdir <test-git> &&
>> (cd <test-git> && git init) &&
>> time git push --mirror --recurse-submodules=check <test-git>
>>
>>    real       0m21.441s
>>    user       0m29.560s
>>    sys        0m1.480s
>>
>>    real       0m21.319s
>>    user       0m29.484s
>>    sys        0m1.464s
>>
>>    real       0m21.261s
>>    user       0m29.252s
>>    sys        0m1.592s
>>
>> Without my patches and --recurse-submodules=check the numbers are
>> basically the same. I stopped the test with --recurse-submodules=check
>> after ~ 9 minutes.
>
> Fun fact, I let the push without my patch and with
> --recurse-submodules=check finish:

Thanks for the numbers, one of the major push backs for
origin/sb/push-make-submodule-check-the-default
was that it introduced slowness; this patch might help a bit there.

^ permalink raw reply

* Re: [PATCH 2/2] serialize collection of refs that contain submodule changes
From: Heiko Voigt @ 2016-09-14 19:46 UTC (permalink / raw)
  To: Jeff King
  Cc: Stefan Beller, Junio C Hamano, git@vger.kernel.org, Jens Lehmann,
	Fredrik Gustafsson, Leandro Lucarella
In-Reply-To: <20160914175130.GB7613@sandbox>

On Wed, Sep 14, 2016 at 07:51:30PM +0200, Heiko Voigt wrote:
> Here are some numbers (using the my development clone of git
> itself) from my local machine:
> 
> rm -rf <test-git> && mkdir <test-git> &&
> (cd <test-git> && git init) &&
> time git push --mirror <test-git>
> 
>    real	0m16.056s
>    user	0m24.424s
>    sys	0m1.380s
> 
>    real	0m15.885s
>    user	0m24.204s
>    sys	0m1.296s
> 
>    real	0m16.731s
>    user	0m24.176s
>    sys	0m1.244s
> 
> rm -rf <test-git> && mkdir <test-git> &&
> (cd <test-git> && git init) &&
> time git push --mirror --recurse-submodules=check <test-git>
> 
>    real	0m21.441s
>    user	0m29.560s
>    sys	0m1.480s
> 
>    real	0m21.319s
>    user	0m29.484s
>    sys	0m1.464s
> 
>    real	0m21.261s
>    user	0m29.252s
>    sys	0m1.592s
> 
> Without my patches and --recurse-submodules=check the numbers are
> basically the same. I stopped the test with --recurse-submodules=check
> after ~ 9 minutes.

Fun fact, I let the push without my patch and with
--recurse-submodules=check finish:

real	27m7.962s
user	27m15.568s
sys	0m2.016s

Thats quite some time...

Cheers Heiko

^ permalink raw reply

* Re: [RFC 0/1] mailinfo: de-quote quoted-pair in header fields
From: Jeff King @ 2016-09-14 19:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Kevin Daudt, git
In-Reply-To: <xmqqfup2qny9.fsf@gitster.mtv.corp.google.com>

On Wed, Sep 14, 2016 at 12:30:06PM -0700, Junio C Hamano wrote:

> Another small thing I am not sure about is if the \ quoting can hide
> an embedded newline in the author name.  Would we end up turning
> 
> 	From: "Jeff \
>             King" <peff@peff.net>
> 
> or somesuch into
> 
> 	Author: Jeff
>         King
>         Email: peff@peff.net
> 
> ;-)

Heh, yeah. That is another reason to clean up and sanitize as much as
possible before stuffing it into another text format that will be
parsed.

> So let's roll the \" -> " into mailinfo.
> 
> I am not sure if we also should remove the surrounding "", i.e. we
> currently do not turn this
> 
> 	From: "Jeff King" <peff@peff.net>
> 
> into this:
> 
> 	Author: Jeff King
>         Email: peff@peff.net
> 
> I think we probably should, and remove the one that does so from the
> reader.

I think you have to, or else you cannot tell the difference between
surrounding quotes that need to be stripped, and ones that were
backslash-escaped. Like:

  From: "Jeff King" <peff@peff.net>
  From: \"Jeff King\" <peff@peff.net>

which would both become:

  Author: "Jeff King"
  Email: peff@peff.net

though I am not sure the latter one is actually valid; you might need to
be inside syntactic quotes in order to include backslashed quotes. I
haven't read rfc2822 carefully recently enough to know.

Anyway, I think that:

  From: One "Two \"Three\" Four" Five

may also be valid. So the quote-stripping in the reader is not just "at
the outside", but may need to handle interior syntactic quotes, too. So
it really makes sense for me to clean and sanitize as much as possible
in one step, and then make the parser of mailinfo as dumb as possible.

-Peff

^ permalink raw reply

* Re: git submodule add spits unrelated to actual problem error msg about .gitignore
From: Stefan Beller @ 2016-09-14 19:32 UTC (permalink / raw)
  To: Yaroslav Halchenko; +Cc: git@vger.kernel.org
In-Reply-To: <20160914140318.GB9833@onerussian.com>

On Wed, Sep 14, 2016 at 7:03 AM, Yaroslav Halchenko <yoh@onerussian.com> wrote:
> I have spent some time chasing the wild goose (well - the .gitignore
> file) after getting:
>
>     $> git-submodule add --name fcx-1 ./fcx-1/ ./fcx-1/
>     The following path is ignored by one of your .gitignore files:
>     fcx-1
>     Use -f if you really want to add it.
>
> long story short -- the culprit is this piece of code in git-submodule:
>
>     if test -z "$force" && ! git add --dry-run --ignore-missing "$sm_path" > /dev/null 2>&1
>     then
>         eval_gettextln "The following path is ignored by one of your .gitignore files:
> \$sm_path
> Use -f if you really want to add it." >&2
>         exit 1
>     fi
>
>
> so if anything goes wrong in git add, it just reports  this error
> message.

Thanks for the bug report!
I think we could chop off "2>&1" as that would have exposed the
underlying error.

Another way to go would be to use verbose git-add and grep for
the string "add '$sm_path'".

     if test -z "$force" && ! git add --verbose --dry-run
--ignore-missing "$sm_path" |grep "add $sm_path"

git-add already gives the correct (the same error message) for  the
ignored files, so maybe we'd just do:

    # no need for a if, but this single line will do:
    test -z "$force" && git add --dry-run git.o >/dev/null || exit 1

^ permalink raw reply

* Re: [PATCH] pathspec: removed unnecessary function prototypes
From: Brandon Williams @ 2016-09-14 19:30 UTC (permalink / raw)
  To: Jeff King; +Cc: git
In-Reply-To: <20160914192341.mgpcc35kgmjqunbh@sigill.intra.peff.net>

On Wed, Sep 14, 2016 at 12:23 PM, Jeff King <peff@peff.net> wrote:

> On Tue, Sep 13, 2016 at 11:15:52AM -0700, Jeff King wrote:
> I should have done a better job of not just providing the answer, but
> showing how. The easiest tool here is "git log -S":
>
>   git log -1 -p -Scheck_path_for_gitlink
>
> (and then you can see that the whole function went away there).
>
> -Peff

Perfect thanks! There's still a lot of little features like this that
I'm unaware
of so I really appreciate the pointer.

-Brandon

^ permalink raw reply

* Re: [RFC 0/1] mailinfo: de-quote quoted-pair in header fields
From: Junio C Hamano @ 2016-09-14 19:30 UTC (permalink / raw)
  To: Jeff King; +Cc: Kevin Daudt, git
In-Reply-To: <20160914191759.5unwaq2eequ4pifr@sigill.intra.peff.net>

Jeff King <peff@peff.net> writes:

> On Wed, Sep 14, 2016 at 10:43:18AM -0700, Junio C Hamano wrote:
>
>> I think we can go either way and it does not matter all that much if
>> "mailinfo" changes its output or the reader of "mailinfo" output
>> changes its input--we will either be munging data read from "From:"
>> when producing the "Author:" line, or taking the "Author:" output by
>> mailinfo and removing the quotes.
>
> Yeah, that was the part I was wondering about in my original response.
> What is the output of mailinfo _supposed_ to be, and do we consider that
> at all public (i.e., are there are other tools besides "git am" that
> build on mailinfo)?
>
> At least "am" already does some quote-stripping, so any de-quoting added
> in mailinfo is potentially a regression (if we indeed care about keeping
> the output stable).

Another small thing I am not sure about is if the \ quoting can hide
an embedded newline in the author name.  Would we end up turning

	From: "Jeff \
            King" <peff@peff.net>

or somesuch into

	Author: Jeff
        King
        Email: peff@peff.net

;-)

> But if we are OK with that, it seems to me that mailinfo is the best
> place to do the de-quoting, because then its output is well-defined:
> everything after "Author:" up to the newline is the name.

There are other things mailinfo does, like turning this

	From: peff@peff.net (Jeff King)

into

	Author: Jeff King
        Email: peff@peff.net

and

	From: Uh "foo" Bar peff@peff.net (Jeff King)

into

	Author: Uh "foo" Bar (Jeff King)
        Email: peff@peff.net

So let's roll the \" -> " into mailinfo.

I am not sure if we also should remove the surrounding "", i.e. we
currently do not turn this

	From: "Jeff King" <peff@peff.net>

into this:

	Author: Jeff King
        Email: peff@peff.net

I think we probably should, and remove the one that does so from the
reader.


^ permalink raw reply

* Re: [PATCH] pathspec: removed unnecessary function prototypes
From: Jeff King @ 2016-09-14 19:23 UTC (permalink / raw)
  To: Brandon Williams; +Cc: git
In-Reply-To: <20160913181552.74bhacoa2q76yv6k@sigill.intra.peff.net>

On Tue, Sep 13, 2016 at 11:15:52AM -0700, Jeff King wrote:

> On Tue, Sep 13, 2016 at 09:52:51AM -0700, Brandon Williams wrote:
> 
> > removed function prototypes from pathspec.h which don't have a
> > corresponding implementation.
> 
> I'm always curious of the "why" in cases like this. Did we forget to add
> them? Did they get renamed? Did they go away?
> 
> Looks like the latter; 5a76aff (add: convert to use parse_pathspec,
> 2013-07-14) just forgot to remove them.

I should have done a better job of not just providing the answer, but
showing how. The easiest tool here is "git log -S":

  git log -1 -p -Scheck_path_for_gitlink

(and then you can see that the whole function went away there).

-Peff

^ permalink raw reply

* Re: [RFC 0/1] mailinfo: de-quote quoted-pair in header fields
From: Jeff King @ 2016-09-14 19:17 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Kevin Daudt, git
In-Reply-To: <xmqqoa3qqsw9.fsf@gitster.mtv.corp.google.com>

On Wed, Sep 14, 2016 at 10:43:18AM -0700, Junio C Hamano wrote:

> I think we can go either way and it does not matter all that much if
> "mailinfo" changes its output or the reader of "mailinfo" output
> changes its input--we will either be munging data read from "From:"
> when producing the "Author:" line, or taking the "Author:" output by
> mailinfo and removing the quotes.

Yeah, that was the part I was wondering about in my original response.
What is the output of mailinfo _supposed_ to be, and do we consider that
at all public (i.e., are there are other tools besides "git am" that
build on mailinfo)?

At least "am" already does some quote-stripping, so any de-quoting added
in mailinfo is potentially a regression (if we indeed care about keeping
the output stable).

But if we are OK with that, it seems to me that mailinfo is the best
place to do the de-quoting, because then its output is well-defined:
everything after "Author:" up to the newline is the name. Whereas if the
cleanup of the value is split across mailinfo and its reader, then it is
hard to know which side is responsible for which part. mailinfo handles
whitespace unfolding, certainly. What other rfc2822 things does it
handle? What are the rules for dequoting its output?

I'll admit I don't care _too_ much. This is a remote corner of the code
that I hope never to have to look at. I'm mostly just describing how the
problem space makes sense to _me_, and how I would write it if starting
from scratch.

-Peff

^ permalink raw reply

* Re: [PATCH] vcs-svn/fast_export: fix timestamp fmt specifiers
From: Jeff King @ 2016-09-14 19:11 UTC (permalink / raw)
  To: Mike Ralphson; +Cc: git
In-Reply-To: <01020157276d4d1f-9c995462-4aea-4949-8d29-3dbdbec77dd7-000000@eu-west-1.amazonses.com>

On Wed, Sep 14, 2016 at 06:40:57AM +0000, Mike Ralphson wrote:

> Two instances of %ld being used for unsigned longs

Obviously this is an improvement, but I'm kind of surprised that
compiler warnings didn't flag this. I couldn't find a "-W" combination
that noticed, though (at least not with gcc 6).

-Peff

^ permalink raw reply

* [PATCH 2/2] serialize collection of refs that contain submodule changes
From: Heiko Voigt @ 2016-09-14 17:51 UTC (permalink / raw)
  To: Jeff King
  Cc: Stefan Beller, Junio C Hamano, git@vger.kernel.org, Jens Lehmann,
	Fredrik Gustafsson, Leandro Lucarella
In-Reply-To: <20160824230115.jhmcr4r7wobj5ejb@sigill.intra.peff.net>

We are iterating over each pushed ref and want to check whether it
contains changes to submodules. Instead of immediately checking each ref
lets first collect them and then do the check for all of them in one
revision walk.

Signed-off-by: Heiko Voigt <hvoigt@hvoigt.net>
---

Sorry this was not catched earlier. This was implemented as part of
summer of code and it seems we never tested with --mirror.

This is the one which does only one revision walk instead of one for
each ref. Here are some numbers (using the my development clone of git
itself) from my local machine:

rm -rf <test-git> && mkdir <test-git> &&
(cd <test-git> && git init) &&
time git push --mirror <test-git>

   real	0m16.056s
   user	0m24.424s
   sys	0m1.380s

   real	0m15.885s
   user	0m24.204s
   sys	0m1.296s

   real	0m16.731s
   user	0m24.176s
   sys	0m1.244s

rm -rf <test-git> && mkdir <test-git> &&
(cd <test-git> && git init) &&
time git push --mirror --recurse-submodules=check <test-git>

   real	0m21.441s
   user	0m29.560s
   sys	0m1.480s

   real	0m21.319s
   user	0m29.484s
   sys	0m1.464s

   real	0m21.261s
   user	0m29.252s
   sys	0m1.592s

Without my patches and --recurse-submodules=check the numbers are
basically the same. I stopped the test with --recurse-submodules=check
after ~ 9 minutes.

Cheers Heiko

 submodule.c | 36 +++++++++++++++++++++---------------
 submodule.h |  5 +++--
 transport.c | 22 ++++++++++++++--------
 3 files changed, 38 insertions(+), 25 deletions(-)

diff --git a/submodule.c b/submodule.c
index b04c066..a15e346 100644
--- a/submodule.c
+++ b/submodule.c
@@ -627,24 +627,31 @@ static void free_submodules_sha1s(struct string_list *submodules)
 	string_list_clear(submodules, 1);
 }
 
-int find_unpushed_submodules(unsigned char new_sha1[20],
+static void append_hash_to_argv(const unsigned char sha1[20],
+		void *data)
+{
+	struct argv_array *argv = (struct argv_array *) data;
+	argv_array_push(argv, sha1_to_hex(sha1));
+}
+
+int find_unpushed_submodules(struct sha1_array *hashes,
 		const char *remotes_name, struct string_list *needs_pushing)
 {
 	struct rev_info rev;
 	struct commit *commit;
-	const char *argv[] = {NULL, NULL, "--not", "NULL", NULL};
-	int argc = ARRAY_SIZE(argv) - 1, i;
-	char *sha1_copy;
+	int i;
 	struct string_list submodules = STRING_LIST_INIT_DUP;
+	struct argv_array argv = ARGV_ARRAY_INIT;
 
-	struct strbuf remotes_arg = STRBUF_INIT;
-
-	strbuf_addf(&remotes_arg, "--remotes=%s", remotes_name);
 	init_revisions(&rev, NULL);
-	sha1_copy = xstrdup(sha1_to_hex(new_sha1));
-	argv[1] = sha1_copy;
-	argv[3] = remotes_arg.buf;
-	setup_revisions(argc, argv, &rev, NULL);
+
+	/* argv.argv[0] will be ignored by setup_revisions */
+	argv_array_push(&argv, "find_unpushed_submodules");
+	sha1_array_for_each_unique(hashes, append_hash_to_argv, &argv);
+	argv_array_push(&argv, "--not");
+	argv_array_pushf(&argv, "--remotes=%s", remotes_name);
+
+	setup_revisions(argv.argc, argv.argv, &rev, NULL);
 	if (prepare_revision_walk(&rev))
 		die("revision walk setup failed");
 
@@ -652,8 +659,7 @@ int find_unpushed_submodules(unsigned char new_sha1[20],
 		find_unpushed_submodule_commits(commit, &submodules);
 
 	reset_revision_walk();
-	free(sha1_copy);
-	strbuf_release(&remotes_arg);
+	argv_array_clear(&argv);
 
 	for (i = 0; i < submodules.nr; i++) {
 		struct string_list_item *item = &submodules.items[i];
@@ -691,12 +697,12 @@ static int push_submodule(const char *path)
 	return 1;
 }
 
-int push_unpushed_submodules(unsigned char new_sha1[20], const char *remotes_name)
+int push_unpushed_submodules(struct sha1_array *hashes, const char *remotes_name)
 {
 	int i, ret = 1;
 	struct string_list needs_pushing = STRING_LIST_INIT_DUP;
 
-	if (!find_unpushed_submodules(new_sha1, remotes_name, &needs_pushing))
+	if (!find_unpushed_submodules(hashes, remotes_name, &needs_pushing))
 		return 1;
 
 	for (i = 0; i < needs_pushing.nr; i++) {
diff --git a/submodule.h b/submodule.h
index d9e197a..065b2f0 100644
--- a/submodule.h
+++ b/submodule.h
@@ -3,6 +3,7 @@
 
 struct diff_options;
 struct argv_array;
+struct sha1_array;
 
 enum {
 	RECURSE_SUBMODULES_CHECK = -4,
@@ -62,9 +63,9 @@ 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,
+int find_unpushed_submodules(struct sha1_array *hashes, const char *remotes_name,
 		struct string_list *needs_pushing);
-int push_unpushed_submodules(unsigned char new_sha1[20], const char *remotes_name);
+int push_unpushed_submodules(struct sha1_array *hashes, const char *remotes_name);
 void connect_work_tree_and_git_dir(const char *work_tree, const char *git_dir);
 int parallel_submodules(void);
 
diff --git a/transport.c b/transport.c
index 94d6dc3..76e1daf 100644
--- a/transport.c
+++ b/transport.c
@@ -903,23 +903,29 @@ int transport_push(struct transport *transport,
 
 		if ((flags & TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND) && !is_bare_repository()) {
 			struct ref *ref = remote_refs;
+			struct sha1_array hashes = SHA1_ARRAY_INIT;
+
 			for (; ref; ref = ref->next)
-				if (!is_null_oid(&ref->new_oid) &&
-				    !push_unpushed_submodules(ref->new_oid.hash,
-					    transport->remote->name))
-				    die ("Failed to push all needed submodules!");
+				if (!is_null_oid(&ref->new_oid))
+					sha1_array_append(&hashes, ref->new_oid.hash);
+
+			if (!push_unpushed_submodules(&hashes, transport->remote->name))
+				die ("Failed to push all needed submodules!");
 		}
 
 		if ((flags & (TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND |
 			      TRANSPORT_RECURSE_SUBMODULES_CHECK)) && !is_bare_repository()) {
 			struct ref *ref = remote_refs;
 			struct string_list needs_pushing = STRING_LIST_INIT_DUP;
+			struct sha1_array hashes = SHA1_ARRAY_INIT;
 
 			for (; ref; ref = ref->next)
-				if (!is_null_oid(&ref->new_oid) &&
-				    find_unpushed_submodules(ref->new_oid.hash,
-					    transport->remote->name, &needs_pushing))
-					die_with_unpushed_submodules(&needs_pushing);
+				if (!is_null_oid(&ref->new_oid))
+					sha1_array_append(&hashes, ref->new_oid.hash);
+
+			if (find_unpushed_submodules(&hashes, transport->remote->name,
+						&needs_pushing))
+				die_with_unpushed_submodules(&needs_pushing);
 		}
 
 		push_ret = transport->push_refs(transport, remote_refs, flags);
-- 
2.0.2.832.g083c931


^ permalink raw reply related

* Re: [RFC 0/1] mailinfo: de-quote quoted-pair in header fields
From: Junio C Hamano @ 2016-09-14 17:43 UTC (permalink / raw)
  To: Kevin Daudt; +Cc: Jeff King, git
In-Reply-To: <20160914160308.GB26893@ikke.info>

Kevin Daudt <me@ikke.info> writes:

> When applied the the author of this patch shows up as:
>
>     Author: A U Thor" (test) <au@thor.com>
>
> So I agree with Jeff[1] where he states that the surrounding quotes
> should be removed, if that's not a problem for git.
>
> [1]:https://public-inbox.org/git/20160914051305.vphknpsikyxi3hg3@sigill.intra.peff.net/

I think we can go either way and it does not matter all that much if
"mailinfo" changes its output or the reader of "mailinfo" output
changes its input--we will either be munging data read from "From:"
when producing the "Author:" line, or taking the "Author:" output by
mailinfo and removing the quotes.

As an output from mailinfo that looks like this:

	Author: "A U Thor"
        Email: au@thor.com

is made into a commit object that has this:

	author A U Thor <au@thor.com>

we know that the reader of mailinfo output _already_ has some logic
to strip the surrounding double quotes.  That is the only reason why
I think it is a better approach to not dequote in the "mailinfo" but
in the reader to turn

	Author: "A \"U\" Thor"
        Email: au@thor.com

into a commit object that has this:

	author A "U" Thor <au@thor.com>

than updating mailinfo to produce

	Author: A "U" Thor
        Email: au@thor.com

and then create the same result.

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox